4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 Roo.dd.DropTarget.superclass.constructor.call( this,
3902 this.ddGroup || this.group,
3907 * @scope Roo.dd.DropTarget
3912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3916 * IMPORTANT : it should set this.overClass and this.dropAllowed
3918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919 * @param {Event} e The event
3920 * @param {Object} data An object containing arbitrary data supplied by the drag source
3926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927 * This method will be called on every mouse movement while the drag source is over the drop target.
3928 * This default implementation simply returns the dropAllowed config value.
3930 * IMPORTANT : it should set this.dropAllowed
3932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933 * @param {Event} e The event
3934 * @param {Object} data An object containing arbitrary data supplied by the drag source
3940 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3942 * overClass (if any) from the drop element.
3943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944 * @param {Event} e The event
3945 * @param {Object} data An object containing arbitrary data supplied by the drag source
3951 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3953 * implementation that does something to process the drop event and returns true so that the drag source's
3954 * repair action does not run.
3956 * IMPORTANT : it should set this.success
3958 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959 * @param {Event} e The event
3960 * @param {Object} data An object containing arbitrary data supplied by the drag source
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973 * @cfg {String} overClass
3974 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3977 * @cfg {String} dropAllowed
3978 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3980 dropAllowed : "x-dd-drop-ok",
3982 * @cfg {String} dropNotAllowed
3983 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3985 dropNotAllowed : "x-dd-drop-nodrop",
3987 * @cfg {boolean} success
3988 * set this after drop listener..
3992 * @cfg {boolean} valid
3993 * if the drop point is valid for over/enter..
4000 isNotifyTarget : true,
4004 notifyEnter : function(dd, e, data){
4006 this.fireEvent('enter', this, dd, e, data);
4008 this.el.addClass(this.overClass);
4010 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4015 notifyOver : function(dd, e, data){
4017 this.fireEvent('over', this, dd, e, data);
4018 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOut : function(dd, e, data){
4023 this.fireEvent('out', this, dd, e, data);
4025 this.el.removeClass(this.overClass);
4030 notifyDrop : function(dd, e, data){
4031 this.success = false;
4032 this.fireEvent('drop', this, dd, e, data);
4033 return this.success;
4037 * Ext JS Library 1.1.1
4038 * Copyright(c) 2006-2007, Ext JS, LLC.
4040 * Originally Released Under LGPL - original licence link has changed is not relivant.
4043 * <script type="text/javascript">
4048 * @class Roo.dd.DragZone
4049 * @extends Roo.dd.DragSource
4050 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4051 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4053 * @param {String/HTMLElement/Element} el The container element
4054 * @param {Object} config
4056 Roo.dd.DragZone = function(el, config){
4057 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4058 if(this.containerScroll){
4059 Roo.dd.ScrollManager.register(this.el);
4063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4065 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4066 * for auto scrolling during drag operations.
4069 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4070 * method after a failed drop (defaults to "c3daf9" - light blue)
4074 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4075 * for a valid target to drag based on the mouse down. Override this method
4076 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4077 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4078 * @param {EventObject} e The mouse down event
4079 * @return {Object} The dragData
4081 getDragData : function(e){
4082 return Roo.dd.Registry.getHandleFromEvent(e);
4086 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4087 * this.dragData.ddel
4088 * @param {Number} x The x position of the click on the dragged object
4089 * @param {Number} y The y position of the click on the dragged object
4090 * @return {Boolean} true to continue the drag, false to cancel
4092 onInitDrag : function(x, y){
4093 this.proxy.update(this.dragData.ddel.cloneNode(true));
4094 this.onStartDrag(x, y);
4099 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4101 afterRepair : function(){
4103 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4105 this.dragging = false;
4109 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4110 * the XY of this.dragData.ddel
4111 * @param {EventObject} e The mouse up event
4112 * @return {Array} The xy location (e.g. [100, 200])
4114 getRepairXY : function(e){
4115 return Roo.Element.fly(this.dragData.ddel).getXY();
4119 * Ext JS Library 1.1.1
4120 * Copyright(c) 2006-2007, Ext JS, LLC.
4122 * Originally Released Under LGPL - original licence link has changed is not relivant.
4125 * <script type="text/javascript">
4128 * @class Roo.dd.DropZone
4129 * @extends Roo.dd.DropTarget
4130 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4131 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4133 * @param {String/HTMLElement/Element} el The container element
4134 * @param {Object} config
4136 Roo.dd.DropZone = function(el, config){
4137 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4142 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4143 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4144 * provide your own custom lookup.
4145 * @param {Event} e The event
4146 * @return {Object} data The custom data
4148 getTargetFromEvent : function(e){
4149 return Roo.dd.Registry.getTargetFromEvent(e);
4153 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4154 * that it has registered. This method has no default implementation and should be overridden to provide
4155 * node-specific processing if necessary.
4156 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4157 * {@link #getTargetFromEvent} for this node)
4158 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4159 * @param {Event} e The event
4160 * @param {Object} data An object containing arbitrary data supplied by the drag source
4162 onNodeEnter : function(n, dd, e, data){
4167 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4168 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4169 * overridden to provide the proper feedback.
4170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4171 * {@link #getTargetFromEvent} for this node)
4172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4173 * @param {Event} e The event
4174 * @param {Object} data An object containing arbitrary data supplied by the drag source
4175 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4176 * underlying {@link Roo.dd.StatusProxy} can be updated
4178 onNodeOver : function(n, dd, e, data){
4179 return this.dropAllowed;
4183 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4184 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4185 * node-specific processing if necessary.
4186 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4187 * {@link #getTargetFromEvent} for this node)
4188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4189 * @param {Event} e The event
4190 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 onNodeOut : function(n, dd, e, data){
4197 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4198 * the drop node. The default implementation returns false, so it should be overridden to provide the
4199 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4200 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4201 * {@link #getTargetFromEvent} for this node)
4202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4203 * @param {Event} e The event
4204 * @param {Object} data An object containing arbitrary data supplied by the drag source
4205 * @return {Boolean} True if the drop was valid, else false
4207 onNodeDrop : function(n, dd, e, data){
4212 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4213 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4214 * it should be overridden to provide the proper feedback if necessary.
4215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216 * @param {Event} e The event
4217 * @param {Object} data An object containing arbitrary data supplied by the drag source
4218 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4219 * underlying {@link Roo.dd.StatusProxy} can be updated
4221 onContainerOver : function(dd, e, data){
4222 return this.dropNotAllowed;
4226 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4227 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4228 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4229 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4231 * @param {Event} e The event
4232 * @param {Object} data An object containing arbitrary data supplied by the drag source
4233 * @return {Boolean} True if the drop was valid, else false
4235 onContainerDrop : function(dd, e, data){
4240 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4241 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4242 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4243 * you should override this method and provide a custom implementation.
4244 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4245 * @param {Event} e The event
4246 * @param {Object} data An object containing arbitrary data supplied by the drag source
4247 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4248 * underlying {@link Roo.dd.StatusProxy} can be updated
4250 notifyEnter : function(dd, e, data){
4251 return this.dropNotAllowed;
4255 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4256 * This method will be called on every mouse movement while the drag source is over the drop zone.
4257 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4258 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4259 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4260 * registered node, it will call {@link #onContainerOver}.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyOver : function(dd, e, data){
4268 var n = this.getTargetFromEvent(e);
4269 if(!n){ // not over valid drop target
4270 if(this.lastOverNode){
4271 this.onNodeOut(this.lastOverNode, dd, e, data);
4272 this.lastOverNode = null;
4274 return this.onContainerOver(dd, e, data);
4276 if(this.lastOverNode != n){
4277 if(this.lastOverNode){
4278 this.onNodeOut(this.lastOverNode, dd, e, data);
4280 this.onNodeEnter(n, dd, e, data);
4281 this.lastOverNode = n;
4283 return this.onNodeOver(n, dd, e, data);
4287 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4288 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4289 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4291 * @param {Event} e The event
4292 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4294 notifyOut : function(dd, e, data){
4295 if(this.lastOverNode){
4296 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.lastOverNode = null;
4302 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4303 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4304 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4305 * otherwise it will call {@link #onContainerDrop}.
4306 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4307 * @param {Event} e The event
4308 * @param {Object} data An object containing arbitrary data supplied by the drag source
4309 * @return {Boolean} True if the drop was valid, else false
4311 notifyDrop : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4316 var n = this.getTargetFromEvent(e);
4318 this.onNodeDrop(n, dd, e, data) :
4319 this.onContainerDrop(dd, e, data);
4323 triggerCacheRefresh : function(){
4324 Roo.dd.DDM.refreshCache(this.groups);
4328 * Ext JS Library 1.1.1
4329 * Copyright(c) 2006-2007, Ext JS, LLC.
4331 * Originally Released Under LGPL - original licence link has changed is not relivant.
4334 * <script type="text/javascript">
4339 * @class Roo.data.SortTypes
4341 * Defines the default sorting (casting?) comparison functions used when sorting data.
4343 Roo.data.SortTypes = {
4345 * Default sort that does nothing
4346 * @param {Mixed} s The value being converted
4347 * @return {Mixed} The comparison value
4354 * The regular expression used to strip tags
4358 stripTagsRE : /<\/?[^>]+>/gi,
4361 * Strips all HTML tags to sort on text only
4362 * @param {Mixed} s The value being converted
4363 * @return {String} The comparison value
4365 asText : function(s){
4366 return String(s).replace(this.stripTagsRE, "");
4370 * Strips all HTML tags to sort on text only - Case insensitive
4371 * @param {Mixed} s The value being converted
4372 * @return {String} The comparison value
4374 asUCText : function(s){
4375 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4379 * Case insensitive string
4380 * @param {Mixed} s The value being converted
4381 * @return {String} The comparison value
4383 asUCString : function(s) {
4384 return String(s).toUpperCase();
4389 * @param {Mixed} s The value being converted
4390 * @return {Number} The comparison value
4392 asDate : function(s) {
4396 if(s instanceof Date){
4399 return Date.parse(String(s));
4404 * @param {Mixed} s The value being converted
4405 * @return {Float} The comparison value
4407 asFloat : function(s) {
4408 var val = parseFloat(String(s).replace(/,/g, ""));
4409 if(isNaN(val)) val = 0;
4415 * @param {Mixed} s The value being converted
4416 * @return {Number} The comparison value
4418 asInt : function(s) {
4419 var val = parseInt(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4425 * Ext JS Library 1.1.1
4426 * Copyright(c) 2006-2007, Ext JS, LLC.
4428 * Originally Released Under LGPL - original licence link has changed is not relivant.
4431 * <script type="text/javascript">
4435 * @class Roo.data.Record
4436 * Instances of this class encapsulate both record <em>definition</em> information, and record
4437 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4438 * to access Records cached in an {@link Roo.data.Store} object.<br>
4440 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4441 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4444 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4446 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4447 * {@link #create}. The parameters are the same.
4448 * @param {Array} data An associative Array of data values keyed by the field name.
4449 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4450 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4451 * not specified an integer id is generated.
4453 Roo.data.Record = function(data, id){
4454 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4459 * Generate a constructor for a specific record layout.
4460 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4461 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4462 * Each field definition object may contain the following properties: <ul>
4463 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4464 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4465 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4466 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4467 * is being used, then this is a string containing the javascript expression to reference the data relative to
4468 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4469 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4470 * this may be omitted.</p></li>
4471 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4472 * <ul><li>auto (Default, implies no conversion)</li>
4477 * <li>date</li></ul></p></li>
4478 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4479 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4480 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4481 * by the Reader into an object that will be stored in the Record. It is passed the
4482 * following parameters:<ul>
4483 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4485 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4487 * <br>usage:<br><pre><code>
4488 var TopicRecord = Roo.data.Record.create(
4489 {name: 'title', mapping: 'topic_title'},
4490 {name: 'author', mapping: 'username'},
4491 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4492 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4493 {name: 'lastPoster', mapping: 'user2'},
4494 {name: 'excerpt', mapping: 'post_text'}
4497 var myNewRecord = new TopicRecord({
4498 title: 'Do my job please',
4501 lastPost: new Date(),
4502 lastPoster: 'Animal',
4503 excerpt: 'No way dude!'
4505 myStore.add(myNewRecord);
4510 Roo.data.Record.create = function(o){
4512 f.superclass.constructor.apply(this, arguments);
4514 Roo.extend(f, Roo.data.Record);
4515 var p = f.prototype;
4516 p.fields = new Roo.util.MixedCollection(false, function(field){
4519 for(var i = 0, len = o.length; i < len; i++){
4520 p.fields.add(new Roo.data.Field(o[i]));
4522 f.getField = function(name){
4523 return p.fields.get(name);
4528 Roo.data.Record.AUTO_ID = 1000;
4529 Roo.data.Record.EDIT = 'edit';
4530 Roo.data.Record.REJECT = 'reject';
4531 Roo.data.Record.COMMIT = 'commit';
4533 Roo.data.Record.prototype = {
4535 * Readonly flag - true if this record has been modified.
4544 join : function(store){
4549 * Set the named field to the specified value.
4550 * @param {String} name The name of the field to set.
4551 * @param {Object} value The value to set the field to.
4553 set : function(name, value){
4554 if(this.data[name] == value){
4561 if(typeof this.modified[name] == 'undefined'){
4562 this.modified[name] = this.data[name];
4564 this.data[name] = value;
4566 this.store.afterEdit(this);
4571 * Get the value of the named field.
4572 * @param {String} name The name of the field to get the value of.
4573 * @return {Object} The value of the field.
4575 get : function(name){
4576 return this.data[name];
4580 beginEdit : function(){
4581 this.editing = true;
4586 cancelEdit : function(){
4587 this.editing = false;
4588 delete this.modified;
4592 endEdit : function(){
4593 this.editing = false;
4594 if(this.dirty && this.store){
4595 this.store.afterEdit(this);
4600 * Usually called by the {@link Roo.data.Store} which owns the Record.
4601 * Rejects all changes made to the Record since either creation, or the last commit operation.
4602 * Modified fields are reverted to their original values.
4604 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4605 * of reject operations.
4607 reject : function(){
4608 var m = this.modified;
4610 if(typeof m[n] != "function"){
4611 this.data[n] = m[n];
4615 delete this.modified;
4616 this.editing = false;
4618 this.store.afterReject(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Commits all changes made to the Record since either creation, or the last commit operation.
4626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627 * of commit operations.
4629 commit : function(){
4631 delete this.modified;
4632 this.editing = false;
4634 this.store.afterCommit(this);
4639 hasError : function(){
4640 return this.error != null;
4644 clearError : function(){
4649 * Creates a copy of this record.
4650 * @param {String} id (optional) A new record id if you don't want to use this record's id
4653 copy : function(newId) {
4654 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4658 * Ext JS Library 1.1.1
4659 * Copyright(c) 2006-2007, Ext JS, LLC.
4661 * Originally Released Under LGPL - original licence link has changed is not relivant.
4664 * <script type="text/javascript">
4670 * @class Roo.data.Store
4671 * @extends Roo.util.Observable
4672 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4673 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4675 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4676 * has no knowledge of the format of the data returned by the Proxy.<br>
4678 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4679 * instances from the data object. These records are cached and made available through accessor functions.
4681 * Creates a new Store.
4682 * @param {Object} config A config object containing the objects needed for the Store to access data,
4683 * and read the data into Records.
4685 Roo.data.Store = function(config){
4686 this.data = new Roo.util.MixedCollection(false);
4687 this.data.getKey = function(o){
4690 this.baseParams = {};
4699 if(config && config.data){
4700 this.inlineData = config.data;
4704 Roo.apply(this, config);
4706 if(this.reader){ // reader passed
4707 this.reader = Roo.factory(this.reader, Roo.data);
4708 this.reader.xmodule = this.xmodule || false;
4709 if(!this.recordType){
4710 this.recordType = this.reader.recordType;
4712 if(this.reader.onMetaChange){
4713 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4717 if(this.recordType){
4718 this.fields = this.recordType.prototype.fields;
4724 * @event datachanged
4725 * Fires when the data cache has changed, and a widget which is using this Store
4726 * as a Record cache should refresh its view.
4727 * @param {Store} this
4732 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4733 * @param {Store} this
4734 * @param {Object} meta The JSON metadata
4739 * Fires when Records have been added to the Store
4740 * @param {Store} this
4741 * @param {Roo.data.Record[]} records The array of Records added
4742 * @param {Number} index The index at which the record(s) were added
4747 * Fires when a Record has been removed from the Store
4748 * @param {Store} this
4749 * @param {Roo.data.Record} record The Record that was removed
4750 * @param {Number} index The index at which the record was removed
4755 * Fires when a Record has been updated
4756 * @param {Store} this
4757 * @param {Roo.data.Record} record The Record that was updated
4758 * @param {String} operation The update operation being performed. Value may be one of:
4760 Roo.data.Record.EDIT
4761 Roo.data.Record.REJECT
4762 Roo.data.Record.COMMIT
4768 * Fires when the data cache has been cleared.
4769 * @param {Store} this
4774 * Fires before a request is made for a new data object. If the beforeload handler returns false
4775 * the load action will be canceled.
4776 * @param {Store} this
4777 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4782 * Fires after a new set of Records has been loaded.
4783 * @param {Store} this
4784 * @param {Roo.data.Record[]} records The Records that were loaded
4785 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4789 * @event loadexception
4790 * Fires if an exception occurs in the Proxy during loading.
4791 * Called with the signature of the Proxy's "loadexception" event.
4792 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4795 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4796 * @param {Object} load options
4797 * @param {Object} jsonData from your request (normally this contains the Exception)
4799 loadexception : true
4803 this.proxy = Roo.factory(this.proxy, Roo.data);
4804 this.proxy.xmodule = this.xmodule || false;
4805 this.relayEvents(this.proxy, ["loadexception"]);
4807 this.sortToggle = {};
4809 Roo.data.Store.superclass.constructor.call(this);
4811 if(this.inlineData){
4812 this.loadData(this.inlineData);
4813 delete this.inlineData;
4816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4818 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4819 * without a remote query - used by combo/forms at present.
4823 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4826 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4829 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4830 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4833 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4834 * on any HTTP request
4837 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4840 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4841 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4846 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4847 * loaded or when a record is removed. (defaults to false).
4849 pruneModifiedRecords : false,
4855 * Add Records to the Store and fires the add event.
4856 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4858 add : function(records){
4859 records = [].concat(records);
4860 for(var i = 0, len = records.length; i < len; i++){
4861 records[i].join(this);
4863 var index = this.data.length;
4864 this.data.addAll(records);
4865 this.fireEvent("add", this, records, index);
4869 * Remove a Record from the Store and fires the remove event.
4870 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4872 remove : function(record){
4873 var index = this.data.indexOf(record);
4874 this.data.removeAt(index);
4875 if(this.pruneModifiedRecords){
4876 this.modified.remove(record);
4878 this.fireEvent("remove", this, record, index);
4882 * Remove all Records from the Store and fires the clear event.
4884 removeAll : function(){
4886 if(this.pruneModifiedRecords){
4889 this.fireEvent("clear", this);
4893 * Inserts Records to the Store at the given index and fires the add event.
4894 * @param {Number} index The start index at which to insert the passed Records.
4895 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4897 insert : function(index, records){
4898 records = [].concat(records);
4899 for(var i = 0, len = records.length; i < len; i++){
4900 this.data.insert(index, records[i]);
4901 records[i].join(this);
4903 this.fireEvent("add", this, records, index);
4907 * Get the index within the cache of the passed Record.
4908 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4909 * @return {Number} The index of the passed Record. Returns -1 if not found.
4911 indexOf : function(record){
4912 return this.data.indexOf(record);
4916 * Get the index within the cache of the Record with the passed id.
4917 * @param {String} id The id of the Record to find.
4918 * @return {Number} The index of the Record. Returns -1 if not found.
4920 indexOfId : function(id){
4921 return this.data.indexOfKey(id);
4925 * Get the Record with the specified id.
4926 * @param {String} id The id of the Record to find.
4927 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4929 getById : function(id){
4930 return this.data.key(id);
4934 * Get the Record at the specified index.
4935 * @param {Number} index The index of the Record to find.
4936 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4938 getAt : function(index){
4939 return this.data.itemAt(index);
4943 * Returns a range of Records between specified indices.
4944 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4945 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4946 * @return {Roo.data.Record[]} An array of Records
4948 getRange : function(start, end){
4949 return this.data.getRange(start, end);
4953 storeOptions : function(o){
4954 o = Roo.apply({}, o);
4957 this.lastOptions = o;
4961 * Loads the Record cache from the configured Proxy using the configured Reader.
4963 * If using remote paging, then the first load call must specify the <em>start</em>
4964 * and <em>limit</em> properties in the options.params property to establish the initial
4965 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4967 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4968 * and this call will return before the new data has been loaded. Perform any post-processing
4969 * in a callback function, or in a "load" event handler.</strong>
4971 * @param {Object} options An object containing properties which control loading options:<ul>
4972 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4973 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4974 * passed the following arguments:<ul>
4975 * <li>r : Roo.data.Record[]</li>
4976 * <li>options: Options object from the load call</li>
4977 * <li>success: Boolean success indicator</li></ul></li>
4978 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4979 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4982 load : function(options){
4983 options = options || {};
4984 if(this.fireEvent("beforeload", this, options) !== false){
4985 this.storeOptions(options);
4986 var p = Roo.apply(options.params || {}, this.baseParams);
4987 // if meta was not loaded from remote source.. try requesting it.
4988 if (!this.reader.metaFromRemote) {
4991 if(this.sortInfo && this.remoteSort){
4992 var pn = this.paramNames;
4993 p[pn["sort"]] = this.sortInfo.field;
4994 p[pn["dir"]] = this.sortInfo.direction;
4996 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5001 * Reloads the Record cache from the configured Proxy using the configured Reader and
5002 * the options from the last load operation performed.
5003 * @param {Object} options (optional) An object containing properties which may override the options
5004 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5005 * the most recently used options are reused).
5007 reload : function(options){
5008 this.load(Roo.applyIf(options||{}, this.lastOptions));
5012 // Called as a callback by the Reader during a load operation.
5013 loadRecords : function(o, options, success){
5014 if(!o || success === false){
5015 if(success !== false){
5016 this.fireEvent("load", this, [], options);
5018 if(options.callback){
5019 options.callback.call(options.scope || this, [], options, false);
5023 // if data returned failure - throw an exception.
5024 if (o.success === false) {
5025 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5028 var r = o.records, t = o.totalRecords || r.length;
5029 if(!options || options.add !== true){
5030 if(this.pruneModifiedRecords){
5033 for(var i = 0, len = r.length; i < len; i++){
5037 this.data = this.snapshot;
5038 delete this.snapshot;
5041 this.data.addAll(r);
5042 this.totalLength = t;
5044 this.fireEvent("datachanged", this);
5046 this.totalLength = Math.max(t, this.data.length+r.length);
5049 this.fireEvent("load", this, r, options);
5050 if(options.callback){
5051 options.callback.call(options.scope || this, r, options, true);
5056 * Loads data from a passed data block. A Reader which understands the format of the data
5057 * must have been configured in the constructor.
5058 * @param {Object} data The data block from which to read the Records. The format of the data expected
5059 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5060 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5062 loadData : function(o, append){
5063 var r = this.reader.readRecords(o);
5064 this.loadRecords(r, {add: append}, true);
5068 * Gets the number of cached records.
5070 * <em>If using paging, this may not be the total size of the dataset. If the data object
5071 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5072 * the data set size</em>
5074 getCount : function(){
5075 return this.data.length || 0;
5079 * Gets the total number of records in the dataset as returned by the server.
5081 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5082 * the dataset size</em>
5084 getTotalCount : function(){
5085 return this.totalLength || 0;
5089 * Returns the sort state of the Store as an object with two properties:
5091 field {String} The name of the field by which the Records are sorted
5092 direction {String} The sort order, "ASC" or "DESC"
5095 getSortState : function(){
5096 return this.sortInfo;
5100 applySort : function(){
5101 if(this.sortInfo && !this.remoteSort){
5102 var s = this.sortInfo, f = s.field;
5103 var st = this.fields.get(f).sortType;
5104 var fn = function(r1, r2){
5105 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5106 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5108 this.data.sort(s.direction, fn);
5109 if(this.snapshot && this.snapshot != this.data){
5110 this.snapshot.sort(s.direction, fn);
5116 * Sets the default sort column and order to be used by the next load operation.
5117 * @param {String} fieldName The name of the field to sort by.
5118 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5120 setDefaultSort : function(field, dir){
5121 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5126 * If remote sorting is used, the sort is performed on the server, and the cache is
5127 * reloaded. If local sorting is used, the cache is sorted internally.
5128 * @param {String} fieldName The name of the field to sort by.
5129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131 sort : function(fieldName, dir){
5132 var f = this.fields.get(fieldName);
5134 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5135 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5140 this.sortToggle[f.name] = dir;
5141 this.sortInfo = {field: f.name, direction: dir};
5142 if(!this.remoteSort){
5144 this.fireEvent("datachanged", this);
5146 this.load(this.lastOptions);
5151 * Calls the specified function for each of the Records in the cache.
5152 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5153 * Returning <em>false</em> aborts and exits the iteration.
5154 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5156 each : function(fn, scope){
5157 this.data.each(fn, scope);
5161 * Gets all records modified since the last commit. Modified records are persisted across load operations
5162 * (e.g., during paging).
5163 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5165 getModifiedRecords : function(){
5166 return this.modified;
5170 createFilterFn : function(property, value, anyMatch){
5171 if(!value.exec){ // not a regex
5172 value = String(value);
5173 if(value.length == 0){
5176 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5179 return value.test(r.data[property]);
5184 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5185 * @param {String} property A field on your records
5186 * @param {Number} start The record index to start at (defaults to 0)
5187 * @param {Number} end The last record index to include (defaults to length - 1)
5188 * @return {Number} The sum
5190 sum : function(property, start, end){
5191 var rs = this.data.items, v = 0;
5193 end = (end || end === 0) ? end : rs.length-1;
5195 for(var i = start; i <= end; i++){
5196 v += (rs[i].data[property] || 0);
5202 * Filter the records by a specified property.
5203 * @param {String} field A field on your records
5204 * @param {String/RegExp} value Either a string that the field
5205 * should start with or a RegExp to test against the field
5206 * @param {Boolean} anyMatch True to match any part not just the beginning
5208 filter : function(property, value, anyMatch){
5209 var fn = this.createFilterFn(property, value, anyMatch);
5210 return fn ? this.filterBy(fn) : this.clearFilter();
5214 * Filter by a function. The specified function will be called with each
5215 * record in this data source. If the function returns true the record is included,
5216 * otherwise it is filtered.
5217 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5218 * @param {Object} scope (optional) The scope of the function (defaults to this)
5220 filterBy : function(fn, scope){
5221 this.snapshot = this.snapshot || this.data;
5222 this.data = this.queryBy(fn, scope||this);
5223 this.fireEvent("datachanged", this);
5227 * Query the records by a specified property.
5228 * @param {String} field A field on your records
5229 * @param {String/RegExp} value Either a string that the field
5230 * should start with or a RegExp to test against the field
5231 * @param {Boolean} anyMatch True to match any part not just the beginning
5232 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5234 query : function(property, value, anyMatch){
5235 var fn = this.createFilterFn(property, value, anyMatch);
5236 return fn ? this.queryBy(fn) : this.data.clone();
5240 * Query by a function. The specified function will be called with each
5241 * record in this data source. If the function returns true the record is included
5243 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5244 * @param {Object} scope (optional) The scope of the function (defaults to this)
5245 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5247 queryBy : function(fn, scope){
5248 var data = this.snapshot || this.data;
5249 return data.filterBy(fn, scope||this);
5253 * Collects unique values for a particular dataIndex from this store.
5254 * @param {String} dataIndex The property to collect
5255 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5256 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5257 * @return {Array} An array of the unique values
5259 collect : function(dataIndex, allowNull, bypassFilter){
5260 var d = (bypassFilter === true && this.snapshot) ?
5261 this.snapshot.items : this.data.items;
5262 var v, sv, r = [], l = {};
5263 for(var i = 0, len = d.length; i < len; i++){
5264 v = d[i].data[dataIndex];
5266 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5275 * Revert to a view of the Record cache with no filtering applied.
5276 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5278 clearFilter : function(suppressEvent){
5279 if(this.snapshot && this.snapshot != this.data){
5280 this.data = this.snapshot;
5281 delete this.snapshot;
5282 if(suppressEvent !== true){
5283 this.fireEvent("datachanged", this);
5289 afterEdit : function(record){
5290 if(this.modified.indexOf(record) == -1){
5291 this.modified.push(record);
5293 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5297 afterReject : function(record){
5298 this.modified.remove(record);
5299 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5303 afterCommit : function(record){
5304 this.modified.remove(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5309 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5310 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5312 commitChanges : function(){
5313 var m = this.modified.slice(0);
5315 for(var i = 0, len = m.length; i < len; i++){
5321 * Cancel outstanding changes on all changed records.
5323 rejectChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5331 onMetaChange : function(meta, rtype, o){
5332 this.recordType = rtype;
5333 this.fields = rtype.prototype.fields;
5334 delete this.snapshot;
5335 this.sortInfo = meta.sortInfo || this.sortInfo;
5337 this.fireEvent('metachange', this, this.reader.meta);
5341 * Ext JS Library 1.1.1
5342 * Copyright(c) 2006-2007, Ext JS, LLC.
5344 * Originally Released Under LGPL - original licence link has changed is not relivant.
5347 * <script type="text/javascript">
5351 * @class Roo.data.SimpleStore
5352 * @extends Roo.data.Store
5353 * Small helper class to make creating Stores from Array data easier.
5354 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5355 * @cfg {Array} fields An array of field definition objects, or field name strings.
5356 * @cfg {Array} data The multi-dimensional array of data
5358 * @param {Object} config
5360 Roo.data.SimpleStore = function(config){
5361 Roo.data.SimpleStore.superclass.constructor.call(this, {
5363 reader: new Roo.data.ArrayReader({
5366 Roo.data.Record.create(config.fields)
5368 proxy : new Roo.data.MemoryProxy(config.data)
5372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5374 * Ext JS Library 1.1.1
5375 * Copyright(c) 2006-2007, Ext JS, LLC.
5377 * Originally Released Under LGPL - original licence link has changed is not relivant.
5380 * <script type="text/javascript">
5385 * @extends Roo.data.Store
5386 * @class Roo.data.JsonStore
5387 * Small helper class to make creating Stores for JSON data easier. <br/>
5389 var store = new Roo.data.JsonStore({
5390 url: 'get-images.php',
5392 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5395 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5396 * JsonReader and HttpProxy (unless inline data is provided).</b>
5397 * @cfg {Array} fields An array of field definition objects, or field name strings.
5399 * @param {Object} config
5401 Roo.data.JsonStore = function(c){
5402 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5403 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5404 reader: new Roo.data.JsonReader(c, c.fields)
5407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5409 * Ext JS Library 1.1.1
5410 * Copyright(c) 2006-2007, Ext JS, LLC.
5412 * Originally Released Under LGPL - original licence link has changed is not relivant.
5415 * <script type="text/javascript">
5419 Roo.data.Field = function(config){
5420 if(typeof config == "string"){
5421 config = {name: config};
5423 Roo.apply(this, config);
5429 var st = Roo.data.SortTypes;
5430 // named sortTypes are supported, here we look them up
5431 if(typeof this.sortType == "string"){
5432 this.sortType = st[this.sortType];
5435 // set default sortType for strings and dates
5439 this.sortType = st.asUCString;
5442 this.sortType = st.asDate;
5445 this.sortType = st.none;
5450 var stripRe = /[\$,%]/g;
5452 // prebuilt conversion function for this field, instead of
5453 // switching every time we're reading a value
5455 var cv, dateFormat = this.dateFormat;
5460 cv = function(v){ return v; };
5463 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5467 return v !== undefined && v !== null && v !== '' ?
5468 parseInt(String(v).replace(stripRe, ""), 10) : '';
5473 return v !== undefined && v !== null && v !== '' ?
5474 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5479 cv = function(v){ return v === true || v === "true" || v == 1; };
5486 if(v instanceof Date){
5490 if(dateFormat == "timestamp"){
5491 return new Date(v*1000);
5493 return Date.parseDate(v, dateFormat);
5495 var parsed = Date.parse(v);
5496 return parsed ? new Date(parsed) : null;
5505 Roo.data.Field.prototype = {
5513 * Ext JS Library 1.1.1
5514 * Copyright(c) 2006-2007, Ext JS, LLC.
5516 * Originally Released Under LGPL - original licence link has changed is not relivant.
5519 * <script type="text/javascript">
5522 // Base class for reading structured data from a data source. This class is intended to be
5523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5526 * @class Roo.data.DataReader
5527 * Base class for reading structured data from a data source. This class is intended to be
5528 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5531 Roo.data.DataReader = function(meta, recordType){
5535 this.recordType = recordType instanceof Array ?
5536 Roo.data.Record.create(recordType) : recordType;
5539 Roo.data.DataReader.prototype = {
5541 * Create an empty record
5542 * @param {Object} data (optional) - overlay some values
5543 * @return {Roo.data.Record} record created.
5545 newRow : function(d) {
5547 this.recordType.prototype.fields.each(function(c) {
5549 case 'int' : da[c.name] = 0; break;
5550 case 'date' : da[c.name] = new Date(); break;
5551 case 'float' : da[c.name] = 0.0; break;
5552 case 'boolean' : da[c.name] = false; break;
5553 default : da[c.name] = ""; break;
5557 return new this.recordType(Roo.apply(da, d));
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.data.DataProxy
5573 * @extends Roo.data.Observable
5574 * This class is an abstract base class for implementations which provide retrieval of
5575 * unformatted data objects.<br>
5577 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5578 * (of the appropriate type which knows how to parse the data object) to provide a block of
5579 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5581 * Custom implementations must implement the load method as described in
5582 * {@link Roo.data.HttpProxy#load}.
5584 Roo.data.DataProxy = function(){
5588 * Fires before a network request is made to retrieve a data object.
5589 * @param {Object} This DataProxy object.
5590 * @param {Object} params The params parameter to the load function.
5595 * Fires before the load method's callback is called.
5596 * @param {Object} This DataProxy object.
5597 * @param {Object} o The data object.
5598 * @param {Object} arg The callback argument object passed to the load function.
5602 * @event loadexception
5603 * Fires if an Exception occurs during data retrieval.
5604 * @param {Object} This DataProxy object.
5605 * @param {Object} o The data object.
5606 * @param {Object} arg The callback argument object passed to the load function.
5607 * @param {Object} e The Exception.
5609 loadexception : true
5611 Roo.data.DataProxy.superclass.constructor.call(this);
5614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5617 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5621 * Ext JS Library 1.1.1
5622 * Copyright(c) 2006-2007, Ext JS, LLC.
5624 * Originally Released Under LGPL - original licence link has changed is not relivant.
5627 * <script type="text/javascript">
5630 * @class Roo.data.MemoryProxy
5631 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5632 * to the Reader when its load method is called.
5634 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5636 Roo.data.MemoryProxy = function(data){
5640 Roo.data.MemoryProxy.superclass.constructor.call(this);
5644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5646 * Load data from the requested source (in this case an in-memory
5647 * data object passed to the constructor), read the data object into
5648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5649 * process that block using the passed callback.
5650 * @param {Object} params This parameter is not used by the MemoryProxy class.
5651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652 * object into a block of Roo.data.Records.
5653 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5654 * The function must be passed <ul>
5655 * <li>The Record block object</li>
5656 * <li>The "arg" argument from the load function</li>
5657 * <li>A boolean success indicator</li>
5659 * @param {Object} scope The scope in which to call the callback
5660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5662 load : function(params, reader, callback, scope, arg){
5663 params = params || {};
5666 result = reader.readRecords(this.data);
5668 this.fireEvent("loadexception", this, arg, null, e);
5669 callback.call(scope, null, arg, false);
5672 callback.call(scope, result, arg, true);
5676 update : function(params, records){
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5690 * @class Roo.data.HttpProxy
5691 * @extends Roo.data.DataProxy
5692 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5693 * configured to reference a certain URL.<br><br>
5695 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5696 * from which the running page was served.<br><br>
5698 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5700 * Be aware that to enable the browser to parse an XML document, the server must set
5701 * the Content-Type header in the HTTP response to "text/xml".
5703 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5704 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5705 * will be used to make the request.
5707 Roo.data.HttpProxy = function(conn){
5708 Roo.data.HttpProxy.superclass.constructor.call(this);
5709 // is conn a conn config or a real conn?
5711 this.useAjax = !conn || !conn.events;
5715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5716 // thse are take from connection...
5719 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5722 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5723 * extra parameters to each request made by this object. (defaults to undefined)
5726 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5727 * to each request made by this object. (defaults to undefined)
5730 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5733 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5736 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5742 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5746 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5747 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5748 * a finer-grained basis than the DataProxy events.
5750 getConnection : function(){
5751 return this.useAjax ? Roo.Ajax : this.conn;
5755 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5756 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5757 * process that block using the passed callback.
5758 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5759 * for the request to the remote server.
5760 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5761 * object into a block of Roo.data.Records.
5762 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5763 * The function must be passed <ul>
5764 * <li>The Record block object</li>
5765 * <li>The "arg" argument from the load function</li>
5766 * <li>A boolean success indicator</li>
5768 * @param {Object} scope The scope in which to call the callback
5769 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5771 load : function(params, reader, callback, scope, arg){
5772 if(this.fireEvent("beforeload", this, params) !== false){
5774 params : params || {},
5776 callback : callback,
5781 callback : this.loadResponse,
5785 Roo.applyIf(o, this.conn);
5786 if(this.activeRequest){
5787 Roo.Ajax.abort(this.activeRequest);
5789 this.activeRequest = Roo.Ajax.request(o);
5791 this.conn.request(o);
5794 callback.call(scope||this, null, arg, false);
5799 loadResponse : function(o, success, response){
5800 delete this.activeRequest;
5802 this.fireEvent("loadexception", this, o, response);
5803 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5808 result = o.reader.read(response);
5810 this.fireEvent("loadexception", this, o, response, e);
5811 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5815 this.fireEvent("load", this, o, o.request.arg);
5816 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5820 update : function(dataSet){
5825 updateResponse : function(dataSet){
5830 * Ext JS Library 1.1.1
5831 * Copyright(c) 2006-2007, Ext JS, LLC.
5833 * Originally Released Under LGPL - original licence link has changed is not relivant.
5836 * <script type="text/javascript">
5840 * @class Roo.data.ScriptTagProxy
5841 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5842 * other than the originating domain of the running page.<br><br>
5844 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5845 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5847 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5848 * source code that is used as the source inside a <script> tag.<br><br>
5850 * In order for the browser to process the returned data, the server must wrap the data object
5851 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5852 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5853 * depending on whether the callback name was passed:
5856 boolean scriptTag = false;
5857 String cb = request.getParameter("callback");
5860 response.setContentType("text/javascript");
5862 response.setContentType("application/x-json");
5864 Writer out = response.getWriter();
5866 out.write(cb + "(");
5868 out.print(dataBlock.toJsonString());
5875 * @param {Object} config A configuration object.
5877 Roo.data.ScriptTagProxy = function(config){
5878 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5879 Roo.apply(this, config);
5880 this.head = document.getElementsByTagName("head")[0];
5883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5887 * @cfg {String} url The URL from which to request the data object.
5890 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5894 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5895 * the server the name of the callback function set up by the load call to process the returned data object.
5896 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5897 * javascript output which calls this named function passing the data object as its only parameter.
5899 callbackParam : "callback",
5901 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5902 * name to the request.
5907 * Load data from the configured URL, read the data object into
5908 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5909 * process that block using the passed callback.
5910 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5911 * for the request to the remote server.
5912 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5913 * object into a block of Roo.data.Records.
5914 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5915 * The function must be passed <ul>
5916 * <li>The Record block object</li>
5917 * <li>The "arg" argument from the load function</li>
5918 * <li>A boolean success indicator</li>
5920 * @param {Object} scope The scope in which to call the callback
5921 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5923 load : function(params, reader, callback, scope, arg){
5924 if(this.fireEvent("beforeload", this, params) !== false){
5926 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5929 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5931 url += "&_dc=" + (new Date().getTime());
5933 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5936 cb : "stcCallback"+transId,
5937 scriptId : "stcScript"+transId,
5941 callback : callback,
5947 window[trans.cb] = function(o){
5948 conn.handleResponse(o, trans);
5951 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5953 if(this.autoAbort !== false){
5957 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5959 var script = document.createElement("script");
5960 script.setAttribute("src", url);
5961 script.setAttribute("type", "text/javascript");
5962 script.setAttribute("id", trans.scriptId);
5963 this.head.appendChild(script);
5967 callback.call(scope||this, null, arg, false);
5972 isLoading : function(){
5973 return this.trans ? true : false;
5977 * Abort the current server request.
5980 if(this.isLoading()){
5981 this.destroyTrans(this.trans);
5986 destroyTrans : function(trans, isLoaded){
5987 this.head.removeChild(document.getElementById(trans.scriptId));
5988 clearTimeout(trans.timeoutId);
5990 window[trans.cb] = undefined;
5992 delete window[trans.cb];
5995 // if hasn't been loaded, wait for load to remove it to prevent script error
5996 window[trans.cb] = function(){
5997 window[trans.cb] = undefined;
5999 delete window[trans.cb];
6006 handleResponse : function(o, trans){
6008 this.destroyTrans(trans, true);
6011 result = trans.reader.readRecords(o);
6013 this.fireEvent("loadexception", this, o, trans.arg, e);
6014 trans.callback.call(trans.scope||window, null, trans.arg, false);
6017 this.fireEvent("load", this, o, trans.arg);
6018 trans.callback.call(trans.scope||window, result, trans.arg, true);
6022 handleFailure : function(trans){
6024 this.destroyTrans(trans, false);
6025 this.fireEvent("loadexception", this, null, trans.arg);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6040 * @class Roo.data.JsonReader
6041 * @extends Roo.data.DataReader
6042 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6043 * based on mappings in a provided Roo.data.Record constructor.
6045 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6046 * in the reply previously.
6051 var RecordDef = Roo.data.Record.create([
6052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6053 {name: 'occupation'} // This field will use "occupation" as the mapping.
6055 var myReader = new Roo.data.JsonReader({
6056 totalProperty: "results", // The property which contains the total dataset size (optional)
6057 root: "rows", // The property which contains an Array of row objects
6058 id: "id" // The property within each row object that provides an ID for the record (optional)
6062 * This would consume a JSON file like this:
6064 { 'results': 2, 'rows': [
6065 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6066 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6069 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6070 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6071 * paged from the remote server.
6072 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6073 * @cfg {String} root name of the property which contains the Array of row objects.
6074 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6076 * Create a new JsonReader
6077 * @param {Object} meta Metadata configuration options
6078 * @param {Object} recordType Either an Array of field definition objects,
6079 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6081 Roo.data.JsonReader = function(meta, recordType){
6084 // set some defaults:
6086 totalProperty: 'total',
6087 successProperty : 'success',
6092 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6097 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6098 * Used by Store query builder to append _requestMeta to params.
6101 metaFromRemote : false,
6103 * This method is only used by a DataProxy which has retrieved data from a remote server.
6104 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6105 * @return {Object} data A data block which is used by an Roo.data.Store object as
6106 * a cache of Roo.data.Records.
6108 read : function(response){
6109 var json = response.responseText;
6111 var o = /* eval:var:o */ eval("("+json+")");
6113 throw {message: "JsonReader.read: Json object not found"};
6119 this.metaFromRemote = true;
6120 this.meta = o.metaData;
6121 this.recordType = Roo.data.Record.create(o.metaData.fields);
6122 this.onMetaChange(this.meta, this.recordType, o);
6124 return this.readRecords(o);
6127 // private function a store will implement
6128 onMetaChange : function(meta, recordType, o){
6135 simpleAccess: function(obj, subsc) {
6142 getJsonAccessor: function(){
6144 return function(expr) {
6146 return(re.test(expr))
6147 ? new Function("obj", "return obj." + expr)
6157 * Create a data block containing Roo.data.Records from an XML document.
6158 * @param {Object} o An object which contains an Array of row objects in the property specified
6159 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6160 * which contains the total size of the dataset.
6161 * @return {Object} data A data block which is used by an Roo.data.Store object as
6162 * a cache of Roo.data.Records.
6164 readRecords : function(o){
6166 * After any data loads, the raw JSON data is available for further custom processing.
6170 var s = this.meta, Record = this.recordType,
6171 f = Record.prototype.fields, fi = f.items, fl = f.length;
6173 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6175 if(s.totalProperty) {
6176 this.getTotal = this.getJsonAccessor(s.totalProperty);
6178 if(s.successProperty) {
6179 this.getSuccess = this.getJsonAccessor(s.successProperty);
6181 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6183 var g = this.getJsonAccessor(s.id);
6184 this.getId = function(rec) {
6186 return (r === undefined || r === "") ? null : r;
6189 this.getId = function(){return null;};
6192 for(var jj = 0; jj < fl; jj++){
6194 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6195 this.ef[jj] = this.getJsonAccessor(map);
6199 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6200 if(s.totalProperty){
6201 var vt = parseInt(this.getTotal(o), 10);
6206 if(s.successProperty){
6207 var vs = this.getSuccess(o);
6208 if(vs === false || vs === 'false'){
6213 for(var i = 0; i < c; i++){
6216 var id = this.getId(n);
6217 for(var j = 0; j < fl; j++){
6219 var v = this.ef[j](n);
6221 Roo.log('missing convert for ' + f.name);
6225 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6227 var record = new Record(values, id);
6229 records[i] = record;
6234 totalRecords : totalRecords
6239 * Ext JS Library 1.1.1
6240 * Copyright(c) 2006-2007, Ext JS, LLC.
6242 * Originally Released Under LGPL - original licence link has changed is not relivant.
6245 * <script type="text/javascript">
6249 * @class Roo.data.XmlReader
6250 * @extends Roo.data.DataReader
6251 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6252 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6254 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6255 * header in the HTTP response must be set to "text/xml".</em>
6259 var RecordDef = Roo.data.Record.create([
6260 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6261 {name: 'occupation'} // This field will use "occupation" as the mapping.
6263 var myReader = new Roo.data.XmlReader({
6264 totalRecords: "results", // The element which contains the total dataset size (optional)
6265 record: "row", // The repeated element which contains row information
6266 id: "id" // The element within the row that provides an ID for the record (optional)
6270 * This would consume an XML file like this:
6274 <results>2</results>
6277 <name>Bill</name>
6278 <occupation>Gardener</occupation>
6282 <name>Ben</name>
6283 <occupation>Horticulturalist</occupation>
6287 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6288 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6289 * paged from the remote server.
6290 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6291 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6292 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6293 * a record identifier value.
6295 * Create a new XmlReader
6296 * @param {Object} meta Metadata configuration options
6297 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6298 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6299 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6301 Roo.data.XmlReader = function(meta, recordType){
6303 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6305 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6307 * This method is only used by a DataProxy which has retrieved data from a remote server.
6308 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6309 * to contain a method called 'responseXML' that returns an XML document object.
6310 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6311 * a cache of Roo.data.Records.
6313 read : function(response){
6314 var doc = response.responseXML;
6316 throw {message: "XmlReader.read: XML Document not available"};
6318 return this.readRecords(doc);
6322 * Create a data block containing Roo.data.Records from an XML document.
6323 * @param {Object} doc A parsed XML document.
6324 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6325 * a cache of Roo.data.Records.
6327 readRecords : function(doc){
6329 * After any data loads/reads, the raw XML Document is available for further custom processing.
6333 var root = doc.documentElement || doc;
6334 var q = Roo.DomQuery;
6335 var recordType = this.recordType, fields = recordType.prototype.fields;
6336 var sid = this.meta.id;
6337 var totalRecords = 0, success = true;
6338 if(this.meta.totalRecords){
6339 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6342 if(this.meta.success){
6343 var sv = q.selectValue(this.meta.success, root, true);
6344 success = sv !== false && sv !== 'false';
6347 var ns = q.select(this.meta.record, root);
6348 for(var i = 0, len = ns.length; i < len; i++) {
6351 var id = sid ? q.selectValue(sid, n) : undefined;
6352 for(var j = 0, jlen = fields.length; j < jlen; j++){
6353 var f = fields.items[j];
6354 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6358 var record = new recordType(values, id);
6360 records[records.length] = record;
6366 totalRecords : totalRecords || records.length
6371 * Ext JS Library 1.1.1
6372 * Copyright(c) 2006-2007, Ext JS, LLC.
6374 * Originally Released Under LGPL - original licence link has changed is not relivant.
6377 * <script type="text/javascript">
6381 * @class Roo.data.ArrayReader
6382 * @extends Roo.data.DataReader
6383 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6384 * Each element of that Array represents a row of data fields. The
6385 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6386 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6390 var RecordDef = Roo.data.Record.create([
6391 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6392 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6394 var myReader = new Roo.data.ArrayReader({
6395 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6399 * This would consume an Array like this:
6401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6403 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6405 * Create a new JsonReader
6406 * @param {Object} meta Metadata configuration options.
6407 * @param {Object} recordType Either an Array of field definition objects
6408 * as specified to {@link Roo.data.Record#create},
6409 * or an {@link Roo.data.Record} object
6410 * created using {@link Roo.data.Record#create}.
6412 Roo.data.ArrayReader = function(meta, recordType){
6413 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6418 * Create a data block containing Roo.data.Records from an XML document.
6419 * @param {Object} o An Array of row objects which represents the dataset.
6420 * @return {Object} data A data block which is used by an Roo.data.Store object as
6421 * a cache of Roo.data.Records.
6423 readRecords : function(o){
6424 var sid = this.meta ? this.meta.id : null;
6425 var recordType = this.recordType, fields = recordType.prototype.fields;
6428 for(var i = 0; i < root.length; i++){
6431 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6432 for(var j = 0, jlen = fields.length; j < jlen; j++){
6433 var f = fields.items[j];
6434 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6435 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6439 var record = new recordType(values, id);
6441 records[records.length] = record;
6445 totalRecords : records.length
6450 * Ext JS Library 1.1.1
6451 * Copyright(c) 2006-2007, Ext JS, LLC.
6453 * Originally Released Under LGPL - original licence link has changed is not relivant.
6456 * <script type="text/javascript">
6461 * @class Roo.data.Tree
6462 * @extends Roo.util.Observable
6463 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6464 * in the tree have most standard DOM functionality.
6466 * @param {Node} root (optional) The root node
6468 Roo.data.Tree = function(root){
6471 * The root node for this tree
6476 this.setRootNode(root);
6481 * Fires when a new child node is appended to a node in this tree.
6482 * @param {Tree} tree The owner tree
6483 * @param {Node} parent The parent node
6484 * @param {Node} node The newly appended node
6485 * @param {Number} index The index of the newly appended node
6490 * Fires when a child node is removed from a node in this tree.
6491 * @param {Tree} tree The owner tree
6492 * @param {Node} parent The parent node
6493 * @param {Node} node The child node removed
6498 * Fires when a node is moved to a new location in the tree
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} node The node moved
6501 * @param {Node} oldParent The old parent of this node
6502 * @param {Node} newParent The new parent of this node
6503 * @param {Number} index The index it was moved to
6508 * Fires when a new child node is inserted in a node in this tree.
6509 * @param {Tree} tree The owner tree
6510 * @param {Node} parent The parent node
6511 * @param {Node} node The child node inserted
6512 * @param {Node} refNode The child node the node was inserted before
6516 * @event beforeappend
6517 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6518 * @param {Tree} tree The owner tree
6519 * @param {Node} parent The parent node
6520 * @param {Node} node The child node to be appended
6522 "beforeappend" : true,
6524 * @event beforeremove
6525 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node to be removed
6530 "beforeremove" : true,
6533 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6534 * @param {Tree} tree The owner tree
6535 * @param {Node} node The node being moved
6536 * @param {Node} oldParent The parent of the node
6537 * @param {Node} newParent The new parent the node is moving to
6538 * @param {Number} index The index it is being moved to
6540 "beforemove" : true,
6542 * @event beforeinsert
6543 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6544 * @param {Tree} tree The owner tree
6545 * @param {Node} parent The parent node
6546 * @param {Node} node The child node to be inserted
6547 * @param {Node} refNode The child node the node is being inserted before
6549 "beforeinsert" : true
6552 Roo.data.Tree.superclass.constructor.call(this);
6555 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6558 proxyNodeEvent : function(){
6559 return this.fireEvent.apply(this, arguments);
6563 * Returns the root node for this tree.
6566 getRootNode : function(){
6571 * Sets the root node for this tree.
6572 * @param {Node} node
6575 setRootNode : function(node){
6577 node.ownerTree = this;
6579 this.registerNode(node);
6584 * Gets a node in this tree by its id.
6585 * @param {String} id
6588 getNodeById : function(id){
6589 return this.nodeHash[id];
6592 registerNode : function(node){
6593 this.nodeHash[node.id] = node;
6596 unregisterNode : function(node){
6597 delete this.nodeHash[node.id];
6600 toString : function(){
6601 return "[Tree"+(this.id?" "+this.id:"")+"]";
6606 * @class Roo.data.Node
6607 * @extends Roo.util.Observable
6608 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6609 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6611 * @param {Object} attributes The attributes/config for the node
6613 Roo.data.Node = function(attributes){
6615 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6618 this.attributes = attributes || {};
6619 this.leaf = this.attributes.leaf;
6621 * The node id. @type String
6623 this.id = this.attributes.id;
6625 this.id = Roo.id(null, "ynode-");
6626 this.attributes.id = this.id;
6629 * All child nodes of this node. @type Array
6631 this.childNodes = [];
6632 if(!this.childNodes.indexOf){ // indexOf is a must
6633 this.childNodes.indexOf = function(o){
6634 for(var i = 0, len = this.length; i < len; i++){
6643 * The parent node for this node. @type Node
6645 this.parentNode = null;
6647 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6649 this.firstChild = null;
6651 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6653 this.lastChild = null;
6655 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6657 this.previousSibling = null;
6659 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6661 this.nextSibling = null;
6666 * Fires when a new child node is appended
6667 * @param {Tree} tree The owner tree
6668 * @param {Node} this This node
6669 * @param {Node} node The newly appended node
6670 * @param {Number} index The index of the newly appended node
6675 * Fires when a child node is removed
6676 * @param {Tree} tree The owner tree
6677 * @param {Node} this This node
6678 * @param {Node} node The removed node
6683 * Fires when this node is moved to a new location in the tree
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} oldParent The old parent of this node
6687 * @param {Node} newParent The new parent of this node
6688 * @param {Number} index The index it was moved to
6693 * Fires when a new child node is inserted.
6694 * @param {Tree} tree The owner tree
6695 * @param {Node} this This node
6696 * @param {Node} node The child node inserted
6697 * @param {Node} refNode The child node the node was inserted before
6701 * @event beforeappend
6702 * Fires before a new child is appended, return false to cancel the append.
6703 * @param {Tree} tree The owner tree
6704 * @param {Node} this This node
6705 * @param {Node} node The child node to be appended
6707 "beforeappend" : true,
6709 * @event beforeremove
6710 * Fires before a child is removed, return false to cancel the remove.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node to be removed
6715 "beforeremove" : true,
6718 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6719 * @param {Tree} tree The owner tree
6720 * @param {Node} this This node
6721 * @param {Node} oldParent The parent of this node
6722 * @param {Node} newParent The new parent this node is moving to
6723 * @param {Number} index The index it is being moved to
6725 "beforemove" : true,
6727 * @event beforeinsert
6728 * Fires before a new child is inserted, return false to cancel the insert.
6729 * @param {Tree} tree The owner tree
6730 * @param {Node} this This node
6731 * @param {Node} node The child node to be inserted
6732 * @param {Node} refNode The child node the node is being inserted before
6734 "beforeinsert" : true
6736 this.listeners = this.attributes.listeners;
6737 Roo.data.Node.superclass.constructor.call(this);
6740 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6741 fireEvent : function(evtName){
6742 // first do standard event for this node
6743 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6746 // then bubble it up to the tree if the event wasn't cancelled
6747 var ot = this.getOwnerTree();
6749 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6757 * Returns true if this node is a leaf
6760 isLeaf : function(){
6761 return this.leaf === true;
6765 setFirstChild : function(node){
6766 this.firstChild = node;
6770 setLastChild : function(node){
6771 this.lastChild = node;
6776 * Returns true if this node is the last child of its parent
6779 isLast : function(){
6780 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6784 * Returns true if this node is the first child of its parent
6787 isFirst : function(){
6788 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6791 hasChildNodes : function(){
6792 return !this.isLeaf() && this.childNodes.length > 0;
6796 * Insert node(s) as the last child node of this node.
6797 * @param {Node/Array} node The node or Array of nodes to append
6798 * @return {Node} The appended node if single append, or null if an array was passed
6800 appendChild : function(node){
6802 if(node instanceof Array){
6804 }else if(arguments.length > 1){
6807 // if passed an array or multiple args do them one by one
6809 for(var i = 0, len = multi.length; i < len; i++) {
6810 this.appendChild(multi[i]);
6813 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6816 var index = this.childNodes.length;
6817 var oldParent = node.parentNode;
6818 // it's a move, make sure we move it cleanly
6820 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6823 oldParent.removeChild(node);
6825 index = this.childNodes.length;
6827 this.setFirstChild(node);
6829 this.childNodes.push(node);
6830 node.parentNode = this;
6831 var ps = this.childNodes[index-1];
6833 node.previousSibling = ps;
6834 ps.nextSibling = node;
6836 node.previousSibling = null;
6838 node.nextSibling = null;
6839 this.setLastChild(node);
6840 node.setOwnerTree(this.getOwnerTree());
6841 this.fireEvent("append", this.ownerTree, this, node, index);
6843 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6850 * Removes a child node from this node.
6851 * @param {Node} node The node to remove
6852 * @return {Node} The removed node
6854 removeChild : function(node){
6855 var index = this.childNodes.indexOf(node);
6859 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6863 // remove it from childNodes collection
6864 this.childNodes.splice(index, 1);
6867 if(node.previousSibling){
6868 node.previousSibling.nextSibling = node.nextSibling;
6870 if(node.nextSibling){
6871 node.nextSibling.previousSibling = node.previousSibling;
6874 // update child refs
6875 if(this.firstChild == node){
6876 this.setFirstChild(node.nextSibling);
6878 if(this.lastChild == node){
6879 this.setLastChild(node.previousSibling);
6882 node.setOwnerTree(null);
6883 // clear any references from the node
6884 node.parentNode = null;
6885 node.previousSibling = null;
6886 node.nextSibling = null;
6887 this.fireEvent("remove", this.ownerTree, this, node);
6892 * Inserts the first node before the second node in this nodes childNodes collection.
6893 * @param {Node} node The node to insert
6894 * @param {Node} refNode The node to insert before (if null the node is appended)
6895 * @return {Node} The inserted node
6897 insertBefore : function(node, refNode){
6898 if(!refNode){ // like standard Dom, refNode can be null for append
6899 return this.appendChild(node);
6902 if(node == refNode){
6906 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6909 var index = this.childNodes.indexOf(refNode);
6910 var oldParent = node.parentNode;
6911 var refIndex = index;
6913 // when moving internally, indexes will change after remove
6914 if(oldParent == this && this.childNodes.indexOf(node) < index){
6918 // it's a move, make sure we move it cleanly
6920 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6923 oldParent.removeChild(node);
6926 this.setFirstChild(node);
6928 this.childNodes.splice(refIndex, 0, node);
6929 node.parentNode = this;
6930 var ps = this.childNodes[refIndex-1];
6932 node.previousSibling = ps;
6933 ps.nextSibling = node;
6935 node.previousSibling = null;
6937 node.nextSibling = refNode;
6938 refNode.previousSibling = node;
6939 node.setOwnerTree(this.getOwnerTree());
6940 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6942 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6948 * Returns the child node at the specified index.
6949 * @param {Number} index
6952 item : function(index){
6953 return this.childNodes[index];
6957 * Replaces one child node in this node with another.
6958 * @param {Node} newChild The replacement node
6959 * @param {Node} oldChild The node to replace
6960 * @return {Node} The replaced node
6962 replaceChild : function(newChild, oldChild){
6963 this.insertBefore(newChild, oldChild);
6964 this.removeChild(oldChild);
6969 * Returns the index of a child node
6970 * @param {Node} node
6971 * @return {Number} The index of the node or -1 if it was not found
6973 indexOf : function(child){
6974 return this.childNodes.indexOf(child);
6978 * Returns the tree this node is in.
6981 getOwnerTree : function(){
6982 // if it doesn't have one, look for one
6983 if(!this.ownerTree){
6987 this.ownerTree = p.ownerTree;
6993 return this.ownerTree;
6997 * Returns depth of this node (the root node has a depth of 0)
7000 getDepth : function(){
7003 while(p.parentNode){
7011 setOwnerTree : function(tree){
7012 // if it's move, we need to update everyone
7013 if(tree != this.ownerTree){
7015 this.ownerTree.unregisterNode(this);
7017 this.ownerTree = tree;
7018 var cs = this.childNodes;
7019 for(var i = 0, len = cs.length; i < len; i++) {
7020 cs[i].setOwnerTree(tree);
7023 tree.registerNode(this);
7029 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7030 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7031 * @return {String} The path
7033 getPath : function(attr){
7034 attr = attr || "id";
7035 var p = this.parentNode;
7036 var b = [this.attributes[attr]];
7038 b.unshift(p.attributes[attr]);
7041 var sep = this.getOwnerTree().pathSeparator;
7042 return sep + b.join(sep);
7046 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7047 * function call will be the scope provided or the current node. The arguments to the function
7048 * will be the args provided or the current node. If the function returns false at any point,
7049 * the bubble is stopped.
7050 * @param {Function} fn The function to call
7051 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7052 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7054 bubble : function(fn, scope, args){
7057 if(fn.call(scope || p, args || p) === false){
7065 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7066 * function call will be the scope provided or the current node. The arguments to the function
7067 * will be the args provided or the current node. If the function returns false at any point,
7068 * the cascade is stopped on that branch.
7069 * @param {Function} fn The function to call
7070 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7071 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7073 cascade : function(fn, scope, args){
7074 if(fn.call(scope || this, args || this) !== false){
7075 var cs = this.childNodes;
7076 for(var i = 0, len = cs.length; i < len; i++) {
7077 cs[i].cascade(fn, scope, args);
7083 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7084 * function call will be the scope provided or the current node. The arguments to the function
7085 * will be the args provided or the current node. If the function returns false at any point,
7086 * the iteration stops.
7087 * @param {Function} fn The function to call
7088 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7091 eachChild : function(fn, scope, args){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 if(fn.call(scope || this, args || cs[i]) === false){
7101 * Finds the first child that has the attribute with the specified value.
7102 * @param {String} attribute The attribute name
7103 * @param {Mixed} value The value to search for
7104 * @return {Node} The found child or null if none was found
7106 findChild : function(attribute, value){
7107 var cs = this.childNodes;
7108 for(var i = 0, len = cs.length; i < len; i++) {
7109 if(cs[i].attributes[attribute] == value){
7117 * Finds the first child by a custom function. The child matches if the function passed
7119 * @param {Function} fn
7120 * @param {Object} scope (optional)
7121 * @return {Node} The found child or null if none was found
7123 findChildBy : function(fn, scope){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(fn.call(scope||cs[i], cs[i]) === true){
7134 * Sorts this nodes children using the supplied sort function
7135 * @param {Function} fn
7136 * @param {Object} scope (optional)
7138 sort : function(fn, scope){
7139 var cs = this.childNodes;
7140 var len = cs.length;
7142 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7144 for(var i = 0; i < len; i++){
7146 n.previousSibling = cs[i-1];
7147 n.nextSibling = cs[i+1];
7149 this.setFirstChild(n);
7152 this.setLastChild(n);
7159 * Returns true if this node is an ancestor (at any point) of the passed node.
7160 * @param {Node} node
7163 contains : function(node){
7164 return node.isAncestor(this);
7168 * Returns true if the passed node is an ancestor (at any point) of this node.
7169 * @param {Node} node
7172 isAncestor : function(node){
7173 var p = this.parentNode;
7183 toString : function(){
7184 return "[Node"+(this.id?" "+this.id:"")+"]";
7188 * Ext JS Library 1.1.1
7189 * Copyright(c) 2006-2007, Ext JS, LLC.
7191 * Originally Released Under LGPL - original licence link has changed is not relivant.
7194 * <script type="text/javascript">
7199 * @class Roo.ComponentMgr
7200 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7203 Roo.ComponentMgr = function(){
7204 var all = new Roo.util.MixedCollection();
7208 * Registers a component.
7209 * @param {Roo.Component} c The component
7211 register : function(c){
7216 * Unregisters a component.
7217 * @param {Roo.Component} c The component
7219 unregister : function(c){
7224 * Returns a component by id
7225 * @param {String} id The component id
7232 * Registers a function that will be called when a specified component is added to ComponentMgr
7233 * @param {String} id The component id
7234 * @param {Funtction} fn The callback function
7235 * @param {Object} scope The scope of the callback
7237 onAvailable : function(id, fn, scope){
7238 all.on("add", function(index, o){
7240 fn.call(scope || o, o);
7241 all.un("add", fn, scope);
7248 * Ext JS Library 1.1.1
7249 * Copyright(c) 2006-2007, Ext JS, LLC.
7251 * Originally Released Under LGPL - original licence link has changed is not relivant.
7254 * <script type="text/javascript">
7258 * @class Roo.Component
7259 * @extends Roo.util.Observable
7260 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7261 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7262 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7263 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7264 * All visual components (widgets) that require rendering into a layout should subclass Component.
7266 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7267 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
7268 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7270 Roo.Component = function(config){
7271 config = config || {};
7272 if(config.tagName || config.dom || typeof config == "string"){ // element object
7273 config = {el: config, id: config.id || config};
7275 this.initialConfig = config;
7277 Roo.apply(this, config);
7281 * Fires after the component is disabled.
7282 * @param {Roo.Component} this
7287 * Fires after the component is enabled.
7288 * @param {Roo.Component} this
7293 * Fires before the component is shown. Return false to stop the show.
7294 * @param {Roo.Component} this
7299 * Fires after the component is shown.
7300 * @param {Roo.Component} this
7305 * Fires before the component is hidden. Return false to stop the hide.
7306 * @param {Roo.Component} this
7311 * Fires after the component is hidden.
7312 * @param {Roo.Component} this
7316 * @event beforerender
7317 * Fires before the component is rendered. Return false to stop the render.
7318 * @param {Roo.Component} this
7320 beforerender : true,
7323 * Fires after the component is rendered.
7324 * @param {Roo.Component} this
7328 * @event beforedestroy
7329 * Fires before the component is destroyed. Return false to stop the destroy.
7330 * @param {Roo.Component} this
7332 beforedestroy : true,
7335 * Fires after the component is destroyed.
7336 * @param {Roo.Component} this
7341 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7343 Roo.ComponentMgr.register(this);
7344 Roo.Component.superclass.constructor.call(this);
7345 this.initComponent();
7346 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7347 this.render(this.renderTo);
7348 delete this.renderTo;
7353 Roo.Component.AUTO_ID = 1000;
7355 Roo.extend(Roo.Component, Roo.util.Observable, {
7357 * @property {Boolean} hidden
7358 * true if this component is hidden. Read-only.
7362 * true if this component is disabled. Read-only.
7366 * true if this component has been rendered. Read-only.
7370 /** @cfg {String} disableClass
7371 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7373 disabledClass : "x-item-disabled",
7374 /** @cfg {Boolean} allowDomMove
7375 * Whether the component can move the Dom node when rendering (defaults to true).
7377 allowDomMove : true,
7378 /** @cfg {String} hideMode
7379 * How this component should hidden. Supported values are
7380 * "visibility" (css visibility), "offsets" (negative offset position) and
7381 * "display" (css display) - defaults to "display".
7383 hideMode: 'display',
7386 ctype : "Roo.Component",
7388 /** @cfg {String} actionMode
7389 * which property holds the element that used for hide() / show() / disable() / enable()
7395 getActionEl : function(){
7396 return this[this.actionMode];
7399 initComponent : Roo.emptyFn,
7401 * If this is a lazy rendering component, render it to its container element.
7402 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
7404 render : function(container, position){
7405 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7406 if(!container && this.el){
7407 this.el = Roo.get(this.el);
7408 container = this.el.dom.parentNode;
7409 this.allowDomMove = false;
7411 this.container = Roo.get(container);
7412 this.rendered = true;
7413 if(position !== undefined){
7414 if(typeof position == 'number'){
7415 position = this.container.dom.childNodes[position];
7417 position = Roo.getDom(position);
7420 this.onRender(this.container, position || null);
7422 this.el.addClass(this.cls);
7426 this.el.applyStyles(this.style);
7429 this.fireEvent("render", this);
7430 this.afterRender(this.container);
7442 // default function is not really useful
7443 onRender : function(ct, position){
7445 this.el = Roo.get(this.el);
7446 if(this.allowDomMove !== false){
7447 ct.dom.insertBefore(this.el.dom, position);
7453 getAutoCreate : function(){
7454 var cfg = typeof this.autoCreate == "object" ?
7455 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7456 if(this.id && !cfg.id){
7463 afterRender : Roo.emptyFn,
7466 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7467 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7469 destroy : function(){
7470 if(this.fireEvent("beforedestroy", this) !== false){
7471 this.purgeListeners();
7472 this.beforeDestroy();
7474 this.el.removeAllListeners();
7476 if(this.actionMode == "container"){
7477 this.container.remove();
7481 Roo.ComponentMgr.unregister(this);
7482 this.fireEvent("destroy", this);
7487 beforeDestroy : function(){
7492 onDestroy : function(){
7497 * Returns the underlying {@link Roo.Element}.
7498 * @return {Roo.Element} The element
7505 * Returns the id of this component.
7513 * Try to focus this component.
7514 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7515 * @return {Roo.Component} this
7517 focus : function(selectText){
7520 if(selectText === true){
7521 this.el.dom.select();
7536 * Disable this component.
7537 * @return {Roo.Component} this
7539 disable : function(){
7543 this.disabled = true;
7544 this.fireEvent("disable", this);
7549 onDisable : function(){
7550 this.getActionEl().addClass(this.disabledClass);
7551 this.el.dom.disabled = true;
7555 * Enable this component.
7556 * @return {Roo.Component} this
7558 enable : function(){
7562 this.disabled = false;
7563 this.fireEvent("enable", this);
7568 onEnable : function(){
7569 this.getActionEl().removeClass(this.disabledClass);
7570 this.el.dom.disabled = false;
7574 * Convenience function for setting disabled/enabled by boolean.
7575 * @param {Boolean} disabled
7577 setDisabled : function(disabled){
7578 this[disabled ? "disable" : "enable"]();
7582 * Show this component.
7583 * @return {Roo.Component} this
7586 if(this.fireEvent("beforeshow", this) !== false){
7587 this.hidden = false;
7591 this.fireEvent("show", this);
7597 onShow : function(){
7598 var ae = this.getActionEl();
7599 if(this.hideMode == 'visibility'){
7600 ae.dom.style.visibility = "visible";
7601 }else if(this.hideMode == 'offsets'){
7602 ae.removeClass('x-hidden');
7604 ae.dom.style.display = "";
7609 * Hide this component.
7610 * @return {Roo.Component} this
7613 if(this.fireEvent("beforehide", this) !== false){
7618 this.fireEvent("hide", this);
7624 onHide : function(){
7625 var ae = this.getActionEl();
7626 if(this.hideMode == 'visibility'){
7627 ae.dom.style.visibility = "hidden";
7628 }else if(this.hideMode == 'offsets'){
7629 ae.addClass('x-hidden');
7631 ae.dom.style.display = "none";
7636 * Convenience function to hide or show this component by boolean.
7637 * @param {Boolean} visible True to show, false to hide
7638 * @return {Roo.Component} this
7640 setVisible: function(visible){
7650 * Returns true if this component is visible.
7652 isVisible : function(){
7653 return this.getActionEl().isVisible();
7656 cloneConfig : function(overrides){
7657 overrides = overrides || {};
7658 var id = overrides.id || Roo.id();
7659 var cfg = Roo.applyIf(overrides, this.initialConfig);
7660 cfg.id = id; // prevent dup id
7661 return new this.constructor(cfg);