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);
77 Roo.dd.DragDrop.prototype = {
80 * The id of the element associated with this object. This is what we
81 * refer to as the "linked element" because the size and position of
82 * this element is used to determine when the drag and drop objects have
90 * Configuration attributes passed into the constructor
97 * The id of the element that will be dragged. By default this is same
98 * as the linked element , but could be changed to another element. Ex:
107 * the id of the element that initiates the drag operation. By default
108 * this is the linked element, but could be changed to be a child of this
109 * element. This lets us do things like only starting the drag when the
110 * header element within the linked html element is clicked.
111 * @property handleElId
118 * An associative array of HTML tags that will be ignored if clicked.
119 * @property invalidHandleTypes
120 * @type {string: string}
122 invalidHandleTypes: null,
125 * An associative array of ids for elements that will be ignored if clicked
126 * @property invalidHandleIds
127 * @type {string: string}
129 invalidHandleIds: null,
132 * An indexted array of css class names for elements that will be ignored
134 * @property invalidHandleClasses
137 invalidHandleClasses: null,
140 * The linked element's absolute X position at the time the drag was
142 * @property startPageX
149 * The linked element's absolute X position at the time the drag was
151 * @property startPageY
158 * The group defines a logical collection of DragDrop objects that are
159 * related. Instances only get events when interacting with other
160 * DragDrop object in the same group. This lets us define multiple
161 * groups using a single DragDrop subclass if we want.
163 * @type {string: string}
168 * Individual drag/drop instances can be locked. This will prevent
169 * onmousedown start drag.
180 lock: function() { this.locked = true; },
183 * Unlock this instace
186 unlock: function() { this.locked = false; },
189 * By default, all insances can be a drop target. This can be disabled by
190 * setting isTarget to false.
197 * The padding configured for this drag and drop object for calculating
198 * the drop zone intersection with this object.
205 * Cached reference to the linked element
212 * Internal typeof flag
213 * @property __ygDragDrop
219 * Set to true when horizontal contraints are applied
220 * @property constrainX
227 * Set to true when vertical contraints are applied
228 * @property constrainY
235 * The left constraint
243 * The right constraint
260 * The down constraint
268 * Maintain offsets when we resetconstraints. Set to true when you want
269 * the position of the element relative to its parent to stay the same
270 * when the page changes
272 * @property maintainOffset
275 maintainOffset: false,
278 * Array of pixel locations the element will snap to if we specified a
279 * horizontal graduation/interval. This array is generated automatically
280 * when you define a tick interval.
287 * Array of pixel locations the element will snap to if we specified a
288 * vertical graduation/interval. This array is generated automatically
289 * when you define a tick interval.
296 * By default the drag and drop instance will only respond to the primary
297 * button click (left button for a right-handed mouse). Set to true to
298 * allow drag and drop to start with any mouse click that is propogated
300 * @property primaryButtonOnly
303 primaryButtonOnly: true,
306 * The availabe property is false until the linked dom element is accessible.
307 * @property available
313 * By default, drags can only be initiated if the mousedown occurs in the
314 * region the linked element is. This is done in part to work around a
315 * bug in some browsers that mis-report the mousedown if the previous
316 * mouseup happened outside of the window. This property is set to true
317 * if outer handles are defined.
319 * @property hasOuterHandles
323 hasOuterHandles: false,
326 * Code that executes immediately before the startDrag event
327 * @method b4StartDrag
330 b4StartDrag: function(x, y) { },
333 * Abstract method called after a drag/drop object is clicked
334 * and the drag or mousedown time thresholds have beeen met.
336 * @param {int} X click location
337 * @param {int} Y click location
339 startDrag: function(x, y) { /* override this */ },
342 * Code that executes immediately before the onDrag event
346 b4Drag: function(e) { },
349 * Abstract method called during the onMouseMove event while dragging an
352 * @param {Event} e the mousemove event
354 onDrag: function(e) { /* override this */ },
357 * Abstract method called when this element fist begins hovering over
358 * another DragDrop obj
359 * @method onDragEnter
360 * @param {Event} e the mousemove event
361 * @param {String|DragDrop[]} id In POINT mode, the element
362 * id this is hovering over. In INTERSECT mode, an array of one or more
363 * dragdrop items being hovered over.
365 onDragEnter: function(e, id) { /* override this */ },
368 * Code that executes immediately before the onDragOver event
372 b4DragOver: function(e) { },
375 * Abstract method called when this element is hovering over another
378 * @param {Event} e the mousemove event
379 * @param {String|DragDrop[]} id In POINT mode, the element
380 * id this is hovering over. In INTERSECT mode, an array of dd items
381 * being hovered over.
383 onDragOver: function(e, id) { /* override this */ },
386 * Code that executes immediately before the onDragOut event
390 b4DragOut: function(e) { },
393 * Abstract method called when we are no longer hovering over an element
395 * @param {Event} e the mousemove event
396 * @param {String|DragDrop[]} id In POINT mode, the element
397 * id this was hovering over. In INTERSECT mode, an array of dd items
398 * that the mouse is no longer over.
400 onDragOut: function(e, id) { /* override this */ },
403 * Code that executes immediately before the onDragDrop event
407 b4DragDrop: function(e) { },
410 * Abstract method called when this item is dropped on another DragDrop
413 * @param {Event} e the mouseup event
414 * @param {String|DragDrop[]} id In POINT mode, the element
415 * id this was dropped on. In INTERSECT mode, an array of dd items this
418 onDragDrop: function(e, id) { /* override this */ },
421 * Abstract method called when this item is dropped on an area with no
423 * @method onInvalidDrop
424 * @param {Event} e the mouseup event
426 onInvalidDrop: function(e) { /* override this */ },
429 * Code that executes immediately before the endDrag event
433 b4EndDrag: function(e) { },
436 * Fired when we are done dragging the object
438 * @param {Event} e the mouseup event
440 endDrag: function(e) { /* override this */ },
443 * Code executed immediately before the onMouseDown event
444 * @method b4MouseDown
445 * @param {Event} e the mousedown event
448 b4MouseDown: function(e) { },
451 * Event handler that fires when a drag/drop obj gets a mousedown
452 * @method onMouseDown
453 * @param {Event} e the mousedown event
455 onMouseDown: function(e) { /* override this */ },
458 * Event handler that fires when a drag/drop obj gets a mouseup
460 * @param {Event} e the mouseup event
462 onMouseUp: function(e) { /* override this */ },
465 * Override the onAvailable method to do what is needed after the initial
466 * position was determined.
467 * @method onAvailable
469 onAvailable: function () {
473 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
476 defaultPadding : {left:0, right:0, top:0, bottom:0},
479 * Initializes the drag drop object's constraints to restrict movement to a certain element.
483 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
484 { dragElId: "existingProxyDiv" });
485 dd.startDrag = function(){
486 this.constrainTo("parent-id");
489 * Or you can initalize it using the {@link Roo.Element} object:
491 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
492 startDrag : function(){
493 this.constrainTo("parent-id");
497 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
498 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
499 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
500 * an object containing the sides to pad. For example: {right:10, bottom:10}
501 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
503 constrainTo : function(constrainTo, pad, inContent){
504 if(typeof pad == "number"){
505 pad = {left: pad, right:pad, top:pad, bottom:pad};
507 pad = pad || this.defaultPadding;
508 var b = Roo.get(this.getEl()).getBox();
509 var ce = Roo.get(constrainTo);
510 var s = ce.getScroll();
512 if(cd == document.body){
513 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
516 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
520 var topSpace = b.y - c.y;
521 var leftSpace = b.x - c.x;
523 this.resetConstraints();
524 this.setXConstraint(leftSpace - (pad.left||0), // left
525 c.width - leftSpace - b.width - (pad.right||0) //right
527 this.setYConstraint(topSpace - (pad.top||0), //top
528 c.height - topSpace - b.height - (pad.bottom||0) //bottom
533 * Returns a reference to the linked element
535 * @return {HTMLElement} the html element
539 this._domRef = Roo.getDom(this.id);
546 * Returns a reference to the actual element to drag. By default this is
547 * the same as the html element, but it can be assigned to another
548 * element. An example of this can be found in Roo.dd.DDProxy
550 * @return {HTMLElement} the html element
552 getDragEl: function() {
553 return Roo.getDom(this.dragElId);
557 * Sets up the DragDrop object. Must be called in the constructor of any
558 * Roo.dd.DragDrop subclass
560 * @param id the id of the linked element
561 * @param {String} sGroup the group of related items
562 * @param {object} config configuration attributes
564 init: function(id, sGroup, config) {
565 this.initTarget(id, sGroup, config);
566 Event.on(this.id, "mousedown", this.handleMouseDown, this);
567 // Event.on(this.id, "selectstart", Event.preventDefault);
571 * Initializes Targeting functionality only... the object does not
572 * get a mousedown handler.
574 * @param id the id of the linked element
575 * @param {String} sGroup the group of related items
576 * @param {object} config configuration attributes
578 initTarget: function(id, sGroup, config) {
580 // configuration attributes
581 this.config = config || {};
583 // create a local reference to the drag and drop manager
584 this.DDM = Roo.dd.DDM;
585 // initialize the groups array
588 // assume that we have an element reference instead of an id if the
589 // parameter is not a string
590 if (typeof id !== "string") {
597 // add to an interaction group
598 this.addToGroup((sGroup) ? sGroup : "default");
600 // We don't want to register this as the handle with the manager
601 // so we just set the id rather than calling the setter.
602 this.handleElId = id;
604 // the linked element is the element that gets dragged by default
605 this.setDragElId(id);
607 // by default, clicked anchors will not start drag operations.
608 this.invalidHandleTypes = { A: "A" };
609 this.invalidHandleIds = {};
610 this.invalidHandleClasses = [];
614 this.handleOnAvailable();
618 * Applies the configuration parameters that were passed into the constructor.
619 * This is supposed to happen at each level through the inheritance chain. So
620 * a DDProxy implentation will execute apply config on DDProxy, DD, and
621 * DragDrop in order to get all of the parameters that are available in
623 * @method applyConfig
625 applyConfig: function() {
627 // configurable properties:
628 // padding, isTarget, maintainOffset, primaryButtonOnly
629 this.padding = this.config.padding || [0, 0, 0, 0];
630 this.isTarget = (this.config.isTarget !== false);
631 this.maintainOffset = (this.config.maintainOffset);
632 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
637 * Executed when the linked element is available
638 * @method handleOnAvailable
641 handleOnAvailable: function() {
642 this.available = true;
643 this.resetConstraints();
648 * Configures the padding for the target zone in px. Effectively expands
649 * (or reduces) the virtual object size for targeting calculations.
650 * Supports css-style shorthand; if only one parameter is passed, all sides
651 * will have that padding, and if only two are passed, the top and bottom
652 * will have the first param, the left and right the second.
654 * @param {int} iTop Top pad
655 * @param {int} iRight Right pad
656 * @param {int} iBot Bot pad
657 * @param {int} iLeft Left pad
659 setPadding: function(iTop, iRight, iBot, iLeft) {
660 // this.padding = [iLeft, iRight, iTop, iBot];
661 if (!iRight && 0 !== iRight) {
662 this.padding = [iTop, iTop, iTop, iTop];
663 } else if (!iBot && 0 !== iBot) {
664 this.padding = [iTop, iRight, iTop, iRight];
666 this.padding = [iTop, iRight, iBot, iLeft];
671 * Stores the initial placement of the linked element.
672 * @method setInitialPosition
673 * @param {int} diffX the X offset, default 0
674 * @param {int} diffY the Y offset, default 0
676 setInitPosition: function(diffX, diffY) {
677 var el = this.getEl();
679 if (!this.DDM.verifyEl(el)) {
686 var p = Dom.getXY( el );
688 this.initPageX = p[0] - dx;
689 this.initPageY = p[1] - dy;
691 this.lastPageX = p[0];
692 this.lastPageY = p[1];
695 this.setStartPosition(p);
699 * Sets the start position of the element. This is set when the obj
700 * is initialized, the reset when a drag is started.
701 * @method setStartPosition
702 * @param pos current position (from previous lookup)
705 setStartPosition: function(pos) {
706 var p = pos || Dom.getXY( this.getEl() );
707 this.deltaSetXY = null;
709 this.startPageX = p[0];
710 this.startPageY = p[1];
714 * Add this instance to a group of related drag/drop objects. All
715 * instances belong to at least one group, and can belong to as many
718 * @param sGroup {string} the name of the group
720 addToGroup: function(sGroup) {
721 this.groups[sGroup] = true;
722 this.DDM.regDragDrop(this, sGroup);
726 * Remove's this instance from the supplied interaction group
727 * @method removeFromGroup
728 * @param {string} sGroup The group to drop
730 removeFromGroup: function(sGroup) {
731 if (this.groups[sGroup]) {
732 delete this.groups[sGroup];
735 this.DDM.removeDDFromGroup(this, sGroup);
739 * Allows you to specify that an element other than the linked element
740 * will be moved with the cursor during a drag
741 * @method setDragElId
742 * @param id {string} the id of the element that will be used to initiate the drag
744 setDragElId: function(id) {
749 * Allows you to specify a child of the linked element that should be
750 * used to initiate the drag operation. An example of this would be if
751 * you have a content div with text and links. Clicking anywhere in the
752 * content area would normally start the drag operation. Use this method
753 * to specify that an element inside of the content div is the element
754 * that starts the drag operation.
755 * @method setHandleElId
756 * @param id {string} the id of the element that will be used to
759 setHandleElId: function(id) {
760 if (typeof id !== "string") {
763 this.handleElId = id;
764 this.DDM.regHandle(this.id, id);
768 * Allows you to set an element outside of the linked element as a drag
770 * @method setOuterHandleElId
771 * @param id the id of the element that will be used to initiate the drag
773 setOuterHandleElId: function(id) {
774 if (typeof id !== "string") {
777 Event.on(id, "mousedown",
778 this.handleMouseDown, this);
779 this.setHandleElId(id);
781 this.hasOuterHandles = true;
785 * Remove all drag and drop hooks for this element
789 Event.un(this.id, "mousedown",
790 this.handleMouseDown);
792 this.DDM._remove(this);
795 destroy : function(){
800 * Returns true if this instance is locked, or the drag drop mgr is locked
801 * (meaning that all drag/drop is disabled on the page.)
803 * @return {boolean} true if this obj or all drag/drop is locked, else
806 isLocked: function() {
807 return (this.DDM.isLocked() || this.locked);
811 * Fired when this object is clicked
812 * @method handleMouseDown
814 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
817 handleMouseDown: function(e, oDD){
818 if (this.primaryButtonOnly && e.button != 0) {
822 if (this.isLocked()) {
826 this.DDM.refreshCache(this.groups);
828 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
829 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
831 if (this.clickValidator(e)) {
833 // set the initial element position
834 this.setStartPosition();
840 this.DDM.handleMouseDown(e, this);
842 this.DDM.stopEvent(e);
850 clickValidator: function(e) {
851 var target = e.getTarget();
852 return ( this.isValidHandleChild(target) &&
853 (this.id == this.handleElId ||
854 this.DDM.handleWasClicked(target, this.id)) );
858 * Allows you to specify a tag name that should not start a drag operation
859 * when clicked. This is designed to facilitate embedding links within a
860 * drag handle that do something other than start the drag.
861 * @method addInvalidHandleType
862 * @param {string} tagName the type of element to exclude
864 addInvalidHandleType: function(tagName) {
865 var type = tagName.toUpperCase();
866 this.invalidHandleTypes[type] = type;
870 * Lets you to specify an element id for a child of a drag handle
871 * that should not initiate a drag
872 * @method addInvalidHandleId
873 * @param {string} id the element id of the element you wish to ignore
875 addInvalidHandleId: function(id) {
876 if (typeof id !== "string") {
879 this.invalidHandleIds[id] = id;
883 * Lets you specify a css class of elements that will not initiate a drag
884 * @method addInvalidHandleClass
885 * @param {string} cssClass the class of the elements you wish to ignore
887 addInvalidHandleClass: function(cssClass) {
888 this.invalidHandleClasses.push(cssClass);
892 * Unsets an excluded tag name set by addInvalidHandleType
893 * @method removeInvalidHandleType
894 * @param {string} tagName the type of element to unexclude
896 removeInvalidHandleType: function(tagName) {
897 var type = tagName.toUpperCase();
898 // this.invalidHandleTypes[type] = null;
899 delete this.invalidHandleTypes[type];
903 * Unsets an invalid handle id
904 * @method removeInvalidHandleId
905 * @param {string} id the id of the element to re-enable
907 removeInvalidHandleId: function(id) {
908 if (typeof id !== "string") {
911 delete this.invalidHandleIds[id];
915 * Unsets an invalid css class
916 * @method removeInvalidHandleClass
917 * @param {string} cssClass the class of the element(s) you wish to
920 removeInvalidHandleClass: function(cssClass) {
921 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
922 if (this.invalidHandleClasses[i] == cssClass) {
923 delete this.invalidHandleClasses[i];
929 * Checks the tag exclusion list to see if this click should be ignored
930 * @method isValidHandleChild
931 * @param {HTMLElement} node the HTMLElement to evaluate
932 * @return {boolean} true if this is a valid tag type, false if not
934 isValidHandleChild: function(node) {
937 // var n = (node.nodeName == "#text") ? node.parentNode : node;
940 nodeName = node.nodeName.toUpperCase();
942 nodeName = node.nodeName;
944 valid = valid && !this.invalidHandleTypes[nodeName];
945 valid = valid && !this.invalidHandleIds[node.id];
947 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
948 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
957 * Create the array of horizontal tick marks if an interval was specified
958 * in setXConstraint().
962 setXTicks: function(iStartX, iTickSize) {
964 this.xTickSize = iTickSize;
968 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
970 this.xTicks[this.xTicks.length] = i;
975 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
977 this.xTicks[this.xTicks.length] = i;
982 this.xTicks.sort(this.DDM.numericSort) ;
986 * Create the array of vertical tick marks if an interval was specified in
991 setYTicks: function(iStartY, iTickSize) {
993 this.yTickSize = iTickSize;
997 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
999 this.yTicks[this.yTicks.length] = i;
1004 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1006 this.yTicks[this.yTicks.length] = i;
1011 this.yTicks.sort(this.DDM.numericSort) ;
1015 * By default, the element can be dragged any place on the screen. Use
1016 * this method to limit the horizontal travel of the element. Pass in
1017 * 0,0 for the parameters if you want to lock the drag to the y axis.
1018 * @method setXConstraint
1019 * @param {int} iLeft the number of pixels the element can move to the left
1020 * @param {int} iRight the number of pixels the element can move to the
1022 * @param {int} iTickSize optional parameter for specifying that the
1024 * should move iTickSize pixels at a time.
1026 setXConstraint: function(iLeft, iRight, iTickSize) {
1027 this.leftConstraint = iLeft;
1028 this.rightConstraint = iRight;
1030 this.minX = this.initPageX - iLeft;
1031 this.maxX = this.initPageX + iRight;
1032 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1034 this.constrainX = true;
1038 * Clears any constraints applied to this instance. Also clears ticks
1039 * since they can't exist independent of a constraint at this time.
1040 * @method clearConstraints
1042 clearConstraints: function() {
1043 this.constrainX = false;
1044 this.constrainY = false;
1049 * Clears any tick interval defined for this instance
1050 * @method clearTicks
1052 clearTicks: function() {
1060 * By default, the element can be dragged any place on the screen. Set
1061 * this to limit the vertical travel of the element. Pass in 0,0 for the
1062 * parameters if you want to lock the drag to the x axis.
1063 * @method setYConstraint
1064 * @param {int} iUp the number of pixels the element can move up
1065 * @param {int} iDown the number of pixels the element can move down
1066 * @param {int} iTickSize optional parameter for specifying that the
1067 * element should move iTickSize pixels at a time.
1069 setYConstraint: function(iUp, iDown, iTickSize) {
1070 this.topConstraint = iUp;
1071 this.bottomConstraint = iDown;
1073 this.minY = this.initPageY - iUp;
1074 this.maxY = this.initPageY + iDown;
1075 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1077 this.constrainY = true;
1082 * resetConstraints must be called if you manually reposition a dd element.
1083 * @method resetConstraints
1084 * @param {boolean} maintainOffset
1086 resetConstraints: function() {
1089 // Maintain offsets if necessary
1090 if (this.initPageX || this.initPageX === 0) {
1091 // figure out how much this thing has moved
1092 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1093 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1095 this.setInitPosition(dx, dy);
1097 // This is the first time we have detected the element's position
1099 this.setInitPosition();
1102 if (this.constrainX) {
1103 this.setXConstraint( this.leftConstraint,
1104 this.rightConstraint,
1108 if (this.constrainY) {
1109 this.setYConstraint( this.topConstraint,
1110 this.bottomConstraint,
1116 * Normally the drag element is moved pixel by pixel, but we can specify
1117 * that it move a number of pixels at a time. This method resolves the
1118 * location when we have it set up like this.
1120 * @param {int} val where we want to place the object
1121 * @param {int[]} tickArray sorted array of valid points
1122 * @return {int} the closest tick
1125 getTick: function(val, tickArray) {
1128 // If tick interval is not defined, it is effectively 1 pixel,
1129 // so we return the value passed to us.
1131 } else if (tickArray[0] >= val) {
1132 // The value is lower than the first tick, so we return the first
1134 return tickArray[0];
1136 for (var i=0, len=tickArray.length; i<len; ++i) {
1138 if (tickArray[next] && tickArray[next] >= val) {
1139 var diff1 = val - tickArray[i];
1140 var diff2 = tickArray[next] - val;
1141 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1145 // The value is larger than the last tick, so we return the last
1147 return tickArray[tickArray.length - 1];
1154 * @return {string} string representation of the dd obj
1156 toString: function() {
1157 return ("DragDrop " + this.id);
1165 * Ext JS Library 1.1.1
1166 * Copyright(c) 2006-2007, Ext JS, LLC.
1168 * Originally Released Under LGPL - original licence link has changed is not relivant.
1171 * <script type="text/javascript">
1176 * The drag and drop utility provides a framework for building drag and drop
1177 * applications. In addition to enabling drag and drop for specific elements,
1178 * the drag and drop elements are tracked by the manager class, and the
1179 * interactions between the various elements are tracked during the drag and
1180 * the implementing code is notified about these important moments.
1183 // Only load the library once. Rewriting the manager class would orphan
1184 // existing drag and drop instances.
1185 if (!Roo.dd.DragDropMgr) {
1188 * @class Roo.dd.DragDropMgr
1189 * DragDropMgr is a singleton that tracks the element interaction for
1190 * all DragDrop items in the window. Generally, you will not call
1191 * this class directly, but it does have helper methods that could
1192 * be useful in your DragDrop implementations.
1195 Roo.dd.DragDropMgr = function() {
1197 var Event = Roo.EventManager;
1202 * Two dimensional Array of registered DragDrop objects. The first
1203 * dimension is the DragDrop item group, the second the DragDrop
1206 * @type {string: string}
1213 * Array of element ids defined as drag handles. Used to determine
1214 * if the element that generated the mousedown event is actually the
1215 * handle and not the html element itself.
1216 * @property handleIds
1217 * @type {string: string}
1224 * the DragDrop object that is currently being dragged
1225 * @property dragCurrent
1233 * the DragDrop object(s) that are being hovered over
1234 * @property dragOvers
1242 * the X distance between the cursor and the object being dragged
1251 * the Y distance between the cursor and the object being dragged
1260 * Flag to determine if we should prevent the default behavior of the
1261 * events we define. By default this is true, but this can be set to
1262 * false if you need the default behavior (not recommended)
1263 * @property preventDefault
1267 preventDefault: true,
1270 * Flag to determine if we should stop the propagation of the events
1271 * we generate. This is true by default but you may want to set it to
1272 * false if the html element contains other features that require the
1274 * @property stopPropagation
1278 stopPropagation: true,
1281 * Internal flag that is set to true when drag and drop has been
1283 * @property initialized
1290 * All drag and drop can be disabled.
1298 * Called the first time an element is registered.
1304 this.initialized = true;
1308 * In point mode, drag and drop interaction is defined by the
1309 * location of the cursor during the drag/drop
1317 * In intersect mode, drag and drop interactio nis defined by the
1318 * overlap of two or more drag and drop objects.
1319 * @property INTERSECT
1326 * The current drag and drop mode. Default: POINT
1334 * Runs method on all drag and drop objects
1335 * @method _execOnAll
1339 _execOnAll: function(sMethod, args) {
1340 for (var i in this.ids) {
1341 for (var j in this.ids[i]) {
1342 var oDD = this.ids[i][j];
1343 if (! this.isTypeOfDD(oDD)) {
1346 oDD[sMethod].apply(oDD, args);
1352 * Drag and drop initialization. Sets up the global event handlers
1357 _onLoad: function() {
1362 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1363 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1364 Event.on(window, "unload", this._onUnload, this, true);
1365 Event.on(window, "resize", this._onResize, this, true);
1366 // Event.on(window, "mouseout", this._test);
1371 * Reset constraints on all drag and drop objs
1376 _onResize: function(e) {
1377 this._execOnAll("resetConstraints", []);
1381 * Lock all drag and drop functionality
1385 lock: function() { this.locked = true; },
1388 * Unlock all drag and drop functionality
1392 unlock: function() { this.locked = false; },
1395 * Is drag and drop locked?
1397 * @return {boolean} True if drag and drop is locked, false otherwise.
1400 isLocked: function() { return this.locked; },
1403 * Location cache that is set for all drag drop objects when a drag is
1404 * initiated, cleared when the drag is finished.
1405 * @property locationCache
1412 * Set useCache to false if you want to force object the lookup of each
1413 * drag and drop linked element constantly during a drag.
1414 * @property useCache
1421 * The number of pixels that the mouse needs to move after the
1422 * mousedown before the drag is initiated. Default=3;
1423 * @property clickPixelThresh
1427 clickPixelThresh: 3,
1430 * The number of milliseconds after the mousedown event to initiate the
1431 * drag if we don't get a mouseup event. Default=1000
1432 * @property clickTimeThresh
1436 clickTimeThresh: 350,
1439 * Flag that indicates that either the drag pixel threshold or the
1440 * mousdown time threshold has been met
1441 * @property dragThreshMet
1446 dragThreshMet: false,
1449 * Timeout used for the click time threshold
1450 * @property clickTimeout
1458 * The X position of the mousedown event stored for later use when a
1459 * drag threshold is met.
1468 * The Y position of the mousedown event stored for later use when a
1469 * drag threshold is met.
1478 * Each DragDrop instance must be registered with the DragDropMgr.
1479 * This is executed in DragDrop.init()
1480 * @method regDragDrop
1481 * @param {DragDrop} oDD the DragDrop object to register
1482 * @param {String} sGroup the name of the group this element belongs to
1485 regDragDrop: function(oDD, sGroup) {
1486 if (!this.initialized) { this.init(); }
1488 if (!this.ids[sGroup]) {
1489 this.ids[sGroup] = {};
1491 this.ids[sGroup][oDD.id] = oDD;
1495 * Removes the supplied dd instance from the supplied group. Executed
1496 * by DragDrop.removeFromGroup, so don't call this function directly.
1497 * @method removeDDFromGroup
1501 removeDDFromGroup: function(oDD, sGroup) {
1502 if (!this.ids[sGroup]) {
1503 this.ids[sGroup] = {};
1506 var obj = this.ids[sGroup];
1507 if (obj && obj[oDD.id]) {
1513 * Unregisters a drag and drop item. This is executed in
1514 * DragDrop.unreg, use that method instead of calling this directly.
1519 _remove: function(oDD) {
1520 for (var g in oDD.groups) {
1521 if (g && this.ids[g][oDD.id]) {
1522 delete this.ids[g][oDD.id];
1525 delete this.handleIds[oDD.id];
1529 * Each DragDrop handle element must be registered. This is done
1530 * automatically when executing DragDrop.setHandleElId()
1532 * @param {String} sDDId the DragDrop id this element is a handle for
1533 * @param {String} sHandleId the id of the element that is the drag
1537 regHandle: function(sDDId, sHandleId) {
1538 if (!this.handleIds[sDDId]) {
1539 this.handleIds[sDDId] = {};
1541 this.handleIds[sDDId][sHandleId] = sHandleId;
1545 * Utility function to determine if a given element has been
1546 * registered as a drag drop item.
1547 * @method isDragDrop
1548 * @param {String} id the element id to check
1549 * @return {boolean} true if this element is a DragDrop item,
1553 isDragDrop: function(id) {
1554 return ( this.getDDById(id) ) ? true : false;
1558 * Returns the drag and drop instances that are in all groups the
1559 * passed in instance belongs to.
1560 * @method getRelated
1561 * @param {DragDrop} p_oDD the obj to get related data for
1562 * @param {boolean} bTargetsOnly if true, only return targetable objs
1563 * @return {DragDrop[]} the related instances
1566 getRelated: function(p_oDD, bTargetsOnly) {
1568 for (var i in p_oDD.groups) {
1569 for (j in this.ids[i]) {
1570 var dd = this.ids[i][j];
1571 if (! this.isTypeOfDD(dd)) {
1574 if (!bTargetsOnly || dd.isTarget) {
1575 oDDs[oDDs.length] = dd;
1584 * Returns true if the specified dd target is a legal target for
1585 * the specifice drag obj
1586 * @method isLegalTarget
1587 * @param {DragDrop} the drag obj
1588 * @param {DragDrop} the target
1589 * @return {boolean} true if the target is a legal target for the
1593 isLegalTarget: function (oDD, oTargetDD) {
1594 var targets = this.getRelated(oDD, true);
1595 for (var i=0, len=targets.length;i<len;++i) {
1596 if (targets[i].id == oTargetDD.id) {
1605 * My goal is to be able to transparently determine if an object is
1606 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1607 * returns "object", oDD.constructor.toString() always returns
1608 * "DragDrop" and not the name of the subclass. So for now it just
1609 * evaluates a well-known variable in DragDrop.
1610 * @method isTypeOfDD
1611 * @param {Object} the object to evaluate
1612 * @return {boolean} true if typeof oDD = DragDrop
1615 isTypeOfDD: function (oDD) {
1616 return (oDD && oDD.__ygDragDrop);
1620 * Utility function to determine if a given element has been
1621 * registered as a drag drop handle for the given Drag Drop object.
1623 * @param {String} id the element id to check
1624 * @return {boolean} true if this element is a DragDrop handle, false
1628 isHandle: function(sDDId, sHandleId) {
1629 return ( this.handleIds[sDDId] &&
1630 this.handleIds[sDDId][sHandleId] );
1634 * Returns the DragDrop instance for a given id
1636 * @param {String} id the id of the DragDrop object
1637 * @return {DragDrop} the drag drop object, null if it is not found
1640 getDDById: function(id) {
1641 for (var i in this.ids) {
1642 if (this.ids[i][id]) {
1643 return this.ids[i][id];
1650 * Fired after a registered DragDrop object gets the mousedown event.
1651 * Sets up the events required to track the object being dragged
1652 * @method handleMouseDown
1653 * @param {Event} e the event
1654 * @param oDD the DragDrop object being dragged
1658 handleMouseDown: function(e, oDD) {
1660 Roo.QuickTips.disable();
1662 this.currentTarget = e.getTarget();
1664 this.dragCurrent = oDD;
1666 var el = oDD.getEl();
1668 // track start position
1669 this.startX = e.getPageX();
1670 this.startY = e.getPageY();
1672 this.deltaX = this.startX - el.offsetLeft;
1673 this.deltaY = this.startY - el.offsetTop;
1675 this.dragThreshMet = false;
1677 this.clickTimeout = setTimeout(
1679 var DDM = Roo.dd.DDM;
1680 DDM.startDrag(DDM.startX, DDM.startY);
1682 this.clickTimeThresh );
1686 * Fired when either the drag pixel threshol or the mousedown hold
1687 * time threshold has been met.
1689 * @param x {int} the X position of the original mousedown
1690 * @param y {int} the Y position of the original mousedown
1693 startDrag: function(x, y) {
1694 clearTimeout(this.clickTimeout);
1695 if (this.dragCurrent) {
1696 this.dragCurrent.b4StartDrag(x, y);
1697 this.dragCurrent.startDrag(x, y);
1699 this.dragThreshMet = true;
1703 * Internal function to handle the mouseup event. Will be invoked
1704 * from the context of the document.
1705 * @method handleMouseUp
1706 * @param {Event} e the event
1710 handleMouseUp: function(e) {
1713 Roo.QuickTips.enable();
1715 if (! this.dragCurrent) {
1719 clearTimeout(this.clickTimeout);
1721 if (this.dragThreshMet) {
1722 this.fireEvents(e, true);
1732 * Utility to stop event propagation and event default, if these
1733 * features are turned on.
1735 * @param {Event} e the event as returned by this.getEvent()
1738 stopEvent: function(e){
1739 if(this.stopPropagation) {
1740 e.stopPropagation();
1743 if (this.preventDefault) {
1749 * Internal function to clean up event handlers after the drag
1750 * operation is complete
1752 * @param {Event} e the event
1756 stopDrag: function(e) {
1757 // Fire the drag end event for the item that was dragged
1758 if (this.dragCurrent) {
1759 if (this.dragThreshMet) {
1760 this.dragCurrent.b4EndDrag(e);
1761 this.dragCurrent.endDrag(e);
1764 this.dragCurrent.onMouseUp(e);
1767 this.dragCurrent = null;
1768 this.dragOvers = {};
1772 * Internal function to handle the mousemove event. Will be invoked
1773 * from the context of the html element.
1775 * @TODO figure out what we can do about mouse events lost when the
1776 * user drags objects beyond the window boundary. Currently we can
1777 * detect this in internet explorer by verifying that the mouse is
1778 * down during the mousemove event. Firefox doesn't give us the
1779 * button state on the mousemove event.
1780 * @method handleMouseMove
1781 * @param {Event} e the event
1785 handleMouseMove: function(e) {
1786 if (! this.dragCurrent) {
1790 // var button = e.which || e.button;
1792 // check for IE mouseup outside of page boundary
1793 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1795 return this.handleMouseUp(e);
1798 if (!this.dragThreshMet) {
1799 var diffX = Math.abs(this.startX - e.getPageX());
1800 var diffY = Math.abs(this.startY - e.getPageY());
1801 if (diffX > this.clickPixelThresh ||
1802 diffY > this.clickPixelThresh) {
1803 this.startDrag(this.startX, this.startY);
1807 if (this.dragThreshMet) {
1808 this.dragCurrent.b4Drag(e);
1809 this.dragCurrent.onDrag(e);
1810 if(!this.dragCurrent.moveOnly){
1811 this.fireEvents(e, false);
1821 * Iterates over all of the DragDrop elements to find ones we are
1822 * hovering over or dropping on
1823 * @method fireEvents
1824 * @param {Event} e the event
1825 * @param {boolean} isDrop is this a drop op or a mouseover op?
1829 fireEvents: function(e, isDrop) {
1830 var dc = this.dragCurrent;
1832 // If the user did the mouse up outside of the window, we could
1833 // get here even though we have ended the drag.
1834 if (!dc || dc.isLocked()) {
1838 var pt = e.getPoint();
1840 // cache the previous dragOver array
1848 // Check to see if the object(s) we were hovering over is no longer
1849 // being hovered over so we can fire the onDragOut event
1850 for (var i in this.dragOvers) {
1852 var ddo = this.dragOvers[i];
1854 if (! this.isTypeOfDD(ddo)) {
1858 if (! this.isOverTarget(pt, ddo, this.mode)) {
1859 outEvts.push( ddo );
1863 delete this.dragOvers[i];
1866 for (var sGroup in dc.groups) {
1868 if ("string" != typeof sGroup) {
1872 for (i in this.ids[sGroup]) {
1873 var oDD = this.ids[sGroup][i];
1874 if (! this.isTypeOfDD(oDD)) {
1878 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1879 if (this.isOverTarget(pt, oDD, this.mode)) {
1880 // look for drop interactions
1882 dropEvts.push( oDD );
1883 // look for drag enter and drag over interactions
1886 // initial drag over: dragEnter fires
1887 if (!oldOvers[oDD.id]) {
1888 enterEvts.push( oDD );
1889 // subsequent drag overs: dragOver fires
1891 overEvts.push( oDD );
1894 this.dragOvers[oDD.id] = oDD;
1902 if (outEvts.length) {
1903 dc.b4DragOut(e, outEvts);
1904 dc.onDragOut(e, outEvts);
1907 if (enterEvts.length) {
1908 dc.onDragEnter(e, enterEvts);
1911 if (overEvts.length) {
1912 dc.b4DragOver(e, overEvts);
1913 dc.onDragOver(e, overEvts);
1916 if (dropEvts.length) {
1917 dc.b4DragDrop(e, dropEvts);
1918 dc.onDragDrop(e, dropEvts);
1922 // fire dragout events
1924 for (i=0, len=outEvts.length; i<len; ++i) {
1925 dc.b4DragOut(e, outEvts[i].id);
1926 dc.onDragOut(e, outEvts[i].id);
1929 // fire enter events
1930 for (i=0,len=enterEvts.length; i<len; ++i) {
1931 // dc.b4DragEnter(e, oDD.id);
1932 dc.onDragEnter(e, enterEvts[i].id);
1936 for (i=0,len=overEvts.length; i<len; ++i) {
1937 dc.b4DragOver(e, overEvts[i].id);
1938 dc.onDragOver(e, overEvts[i].id);
1942 for (i=0, len=dropEvts.length; i<len; ++i) {
1943 dc.b4DragDrop(e, dropEvts[i].id);
1944 dc.onDragDrop(e, dropEvts[i].id);
1949 // notify about a drop that did not find a target
1950 if (isDrop && !dropEvts.length) {
1951 dc.onInvalidDrop(e);
1957 * Helper function for getting the best match from the list of drag
1958 * and drop objects returned by the drag and drop events when we are
1959 * in INTERSECT mode. It returns either the first object that the
1960 * cursor is over, or the object that has the greatest overlap with
1961 * the dragged element.
1962 * @method getBestMatch
1963 * @param {DragDrop[]} dds The array of drag and drop objects
1965 * @return {DragDrop} The best single match
1968 getBestMatch: function(dds) {
1970 // Return null if the input is not what we expect
1971 //if (!dds || !dds.length || dds.length == 0) {
1973 // If there is only one item, it wins
1974 //} else if (dds.length == 1) {
1976 var len = dds.length;
1981 // Loop through the targeted items
1982 for (var i=0; i<len; ++i) {
1984 // If the cursor is over the object, it wins. If the
1985 // cursor is over multiple matches, the first one we come
1987 if (dd.cursorIsOver) {
1990 // Otherwise the object with the most overlap wins
1993 winner.overlap.getArea() < dd.overlap.getArea()) {
2004 * Refreshes the cache of the top-left and bottom-right points of the
2005 * drag and drop objects in the specified group(s). This is in the
2006 * format that is stored in the drag and drop instance, so typical
2009 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2013 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2015 * @TODO this really should be an indexed array. Alternatively this
2016 * method could accept both.
2017 * @method refreshCache
2018 * @param {Object} groups an associative array of groups to refresh
2021 refreshCache: function(groups) {
2022 for (var sGroup in groups) {
2023 if ("string" != typeof sGroup) {
2026 for (var i in this.ids[sGroup]) {
2027 var oDD = this.ids[sGroup][i];
2029 if (this.isTypeOfDD(oDD)) {
2030 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2031 var loc = this.getLocation(oDD);
2033 this.locationCache[oDD.id] = loc;
2035 delete this.locationCache[oDD.id];
2036 // this will unregister the drag and drop object if
2037 // the element is not in a usable state
2046 * This checks to make sure an element exists and is in the DOM. The
2047 * main purpose is to handle cases where innerHTML is used to remove
2048 * drag and drop objects from the DOM. IE provides an 'unspecified
2049 * error' when trying to access the offsetParent of such an element
2051 * @param {HTMLElement} el the element to check
2052 * @return {boolean} true if the element looks usable
2055 verifyEl: function(el) {
2060 parent = el.offsetParent;
2063 parent = el.offsetParent;
2074 * Returns a Region object containing the drag and drop element's position
2075 * and size, including the padding configured for it
2076 * @method getLocation
2077 * @param {DragDrop} oDD the drag and drop object to get the
2079 * @return {Roo.lib.Region} a Region object representing the total area
2080 * the element occupies, including any padding
2081 * the instance is configured for.
2084 getLocation: function(oDD) {
2085 if (! this.isTypeOfDD(oDD)) {
2089 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2092 pos= Roo.lib.Dom.getXY(el);
2100 x2 = x1 + el.offsetWidth;
2102 y2 = y1 + el.offsetHeight;
2104 t = y1 - oDD.padding[0];
2105 r = x2 + oDD.padding[1];
2106 b = y2 + oDD.padding[2];
2107 l = x1 - oDD.padding[3];
2109 return new Roo.lib.Region( t, r, b, l );
2113 * Checks the cursor location to see if it over the target
2114 * @method isOverTarget
2115 * @param {Roo.lib.Point} pt The point to evaluate
2116 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2117 * @return {boolean} true if the mouse is over the target
2121 isOverTarget: function(pt, oTarget, intersect) {
2122 // use cache if available
2123 var loc = this.locationCache[oTarget.id];
2124 if (!loc || !this.useCache) {
2125 loc = this.getLocation(oTarget);
2126 this.locationCache[oTarget.id] = loc;
2134 oTarget.cursorIsOver = loc.contains( pt );
2136 // DragDrop is using this as a sanity check for the initial mousedown
2137 // in this case we are done. In POINT mode, if the drag obj has no
2138 // contraints, we are also done. Otherwise we need to evaluate the
2139 // location of the target as related to the actual location of the
2141 var dc = this.dragCurrent;
2142 if (!dc || !dc.getTargetCoord ||
2143 (!intersect && !dc.constrainX && !dc.constrainY)) {
2144 return oTarget.cursorIsOver;
2147 oTarget.overlap = null;
2149 // Get the current location of the drag element, this is the
2150 // location of the mouse event less the delta that represents
2151 // where the original mousedown happened on the element. We
2152 // need to consider constraints and ticks as well.
2153 var pos = dc.getTargetCoord(pt.x, pt.y);
2155 var el = dc.getDragEl();
2156 var curRegion = new Roo.lib.Region( pos.y,
2157 pos.x + el.offsetWidth,
2158 pos.y + el.offsetHeight,
2161 var overlap = curRegion.intersect(loc);
2164 oTarget.overlap = overlap;
2165 return (intersect) ? true : oTarget.cursorIsOver;
2172 * unload event handler
2177 _onUnload: function(e, me) {
2178 Roo.dd.DragDropMgr.unregAll();
2182 * Cleans up the drag and drop events and objects.
2187 unregAll: function() {
2189 if (this.dragCurrent) {
2191 this.dragCurrent = null;
2194 this._execOnAll("unreg", []);
2196 for (i in this.elementCache) {
2197 delete this.elementCache[i];
2200 this.elementCache = {};
2205 * A cache of DOM elements
2206 * @property elementCache
2213 * Get the wrapper for the DOM element specified
2214 * @method getElWrapper
2215 * @param {String} id the id of the element to get
2216 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2218 * @deprecated This wrapper isn't that useful
2221 getElWrapper: function(id) {
2222 var oWrapper = this.elementCache[id];
2223 if (!oWrapper || !oWrapper.el) {
2224 oWrapper = this.elementCache[id] =
2225 new this.ElementWrapper(Roo.getDom(id));
2231 * Returns the actual DOM element
2232 * @method getElement
2233 * @param {String} id the id of the elment to get
2234 * @return {Object} The element
2235 * @deprecated use Roo.getDom instead
2238 getElement: function(id) {
2239 return Roo.getDom(id);
2243 * Returns the style property for the DOM element (i.e.,
2244 * document.getElById(id).style)
2246 * @param {String} id the id of the elment to get
2247 * @return {Object} The style property of the element
2248 * @deprecated use Roo.getDom instead
2251 getCss: function(id) {
2252 var el = Roo.getDom(id);
2253 return (el) ? el.style : null;
2257 * Inner class for cached elements
2258 * @class DragDropMgr.ElementWrapper
2263 ElementWrapper: function(el) {
2268 this.el = el || null;
2273 this.id = this.el && el.id;
2275 * A reference to the style property
2278 this.css = this.el && el.style;
2282 * Returns the X position of an html element
2284 * @param el the element for which to get the position
2285 * @return {int} the X coordinate
2287 * @deprecated use Roo.lib.Dom.getX instead
2290 getPosX: function(el) {
2291 return Roo.lib.Dom.getX(el);
2295 * Returns the Y position of an html element
2297 * @param el the element for which to get the position
2298 * @return {int} the Y coordinate
2299 * @deprecated use Roo.lib.Dom.getY instead
2302 getPosY: function(el) {
2303 return Roo.lib.Dom.getY(el);
2307 * Swap two nodes. In IE, we use the native method, for others we
2308 * emulate the IE behavior
2310 * @param n1 the first node to swap
2311 * @param n2 the other node to swap
2314 swapNode: function(n1, n2) {
2318 var p = n2.parentNode;
2319 var s = n2.nextSibling;
2322 p.insertBefore(n1, n2);
2323 } else if (n2 == n1.nextSibling) {
2324 p.insertBefore(n2, n1);
2326 n1.parentNode.replaceChild(n2, n1);
2327 p.insertBefore(n1, s);
2333 * Returns the current scroll position
2338 getScroll: function () {
2339 var t, l, dde=document.documentElement, db=document.body;
2340 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2349 return { top: t, left: l };
2353 * Returns the specified element style property
2355 * @param {HTMLElement} el the element
2356 * @param {string} styleProp the style property
2357 * @return {string} The value of the style property
2358 * @deprecated use Roo.lib.Dom.getStyle
2361 getStyle: function(el, styleProp) {
2362 return Roo.fly(el).getStyle(styleProp);
2366 * Gets the scrollTop
2367 * @method getScrollTop
2368 * @return {int} the document's scrollTop
2371 getScrollTop: function () { return this.getScroll().top; },
2374 * Gets the scrollLeft
2375 * @method getScrollLeft
2376 * @return {int} the document's scrollTop
2379 getScrollLeft: function () { return this.getScroll().left; },
2382 * Sets the x/y position of an element to the location of the
2385 * @param {HTMLElement} moveEl The element to move
2386 * @param {HTMLElement} targetEl The position reference element
2389 moveToEl: function (moveEl, targetEl) {
2390 var aCoord = Roo.lib.Dom.getXY(targetEl);
2391 Roo.lib.Dom.setXY(moveEl, aCoord);
2395 * Numeric array sort function
2396 * @method numericSort
2399 numericSort: function(a, b) { return (a - b); },
2403 * @property _timeoutCount
2410 * Trying to make the load order less important. Without this we get
2411 * an error if this file is loaded before the Event Utility.
2412 * @method _addListeners
2416 _addListeners: function() {
2417 var DDM = Roo.dd.DDM;
2418 if ( Roo.lib.Event && document ) {
2421 if (DDM._timeoutCount > 2000) {
2423 setTimeout(DDM._addListeners, 10);
2424 if (document && document.body) {
2425 DDM._timeoutCount += 1;
2432 * Recursively searches the immediate parent and all child nodes for
2433 * the handle element in order to determine wheter or not it was
2435 * @method handleWasClicked
2436 * @param node the html element to inspect
2439 handleWasClicked: function(node, id) {
2440 if (this.isHandle(id, node.id)) {
2443 // check to see if this is a text node child of the one we want
2444 var p = node.parentNode;
2447 if (this.isHandle(id, p.id)) {
2462 // shorter alias, save a few bytes
2463 Roo.dd.DDM = Roo.dd.DragDropMgr;
2464 Roo.dd.DDM._addListeners();
2468 * Ext JS Library 1.1.1
2469 * Copyright(c) 2006-2007, Ext JS, LLC.
2471 * Originally Released Under LGPL - original licence link has changed is not relivant.
2474 * <script type="text/javascript">
2479 * A DragDrop implementation where the linked element follows the
2480 * mouse cursor during a drag.
2481 * @extends Roo.dd.DragDrop
2483 * @param {String} id the id of the linked element
2484 * @param {String} sGroup the group of related DragDrop items
2485 * @param {object} config an object containing configurable attributes
2486 * Valid properties for DD:
2489 Roo.dd.DD = function(id, sGroup, config) {
2491 this.init(id, sGroup, config);
2495 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2498 * When set to true, the utility automatically tries to scroll the browser
2499 * window wehn a drag and drop element is dragged near the viewport boundary.
2507 * Sets the pointer offset to the distance between the linked element's top
2508 * left corner and the location the element was clicked
2509 * @method autoOffset
2510 * @param {int} iPageX the X coordinate of the click
2511 * @param {int} iPageY the Y coordinate of the click
2513 autoOffset: function(iPageX, iPageY) {
2514 var x = iPageX - this.startPageX;
2515 var y = iPageY - this.startPageY;
2516 this.setDelta(x, y);
2520 * Sets the pointer offset. You can call this directly to force the
2521 * offset to be in a particular location (e.g., pass in 0,0 to set it
2522 * to the center of the object)
2524 * @param {int} iDeltaX the distance from the left
2525 * @param {int} iDeltaY the distance from the top
2527 setDelta: function(iDeltaX, iDeltaY) {
2528 this.deltaX = iDeltaX;
2529 this.deltaY = iDeltaY;
2533 * Sets the drag element to the location of the mousedown or click event,
2534 * maintaining the cursor location relative to the location on the element
2535 * that was clicked. Override this if you want to place the element in a
2536 * location other than where the cursor is.
2537 * @method setDragElPos
2538 * @param {int} iPageX the X coordinate of the mousedown or drag event
2539 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2541 setDragElPos: function(iPageX, iPageY) {
2542 // the first time we do this, we are going to check to make sure
2543 // the element has css positioning
2545 var el = this.getDragEl();
2546 this.alignElWithMouse(el, iPageX, iPageY);
2550 * Sets the element to the location of the mousedown or click event,
2551 * maintaining the cursor location relative to the location on the element
2552 * that was clicked. Override this if you want to place the element in a
2553 * location other than where the cursor is.
2554 * @method alignElWithMouse
2555 * @param {HTMLElement} el the element to move
2556 * @param {int} iPageX the X coordinate of the mousedown or drag event
2557 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2559 alignElWithMouse: function(el, iPageX, iPageY) {
2560 var oCoord = this.getTargetCoord(iPageX, iPageY);
2561 var fly = el.dom ? el : Roo.fly(el);
2562 if (!this.deltaSetXY) {
2563 var aCoord = [oCoord.x, oCoord.y];
2565 var newLeft = fly.getLeft(true);
2566 var newTop = fly.getTop(true);
2567 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2569 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2572 this.cachePosition(oCoord.x, oCoord.y);
2573 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2578 * Saves the most recent position so that we can reset the constraints and
2579 * tick marks on-demand. We need to know this so that we can calculate the
2580 * number of pixels the element is offset from its original position.
2581 * @method cachePosition
2582 * @param iPageX the current x position (optional, this just makes it so we
2583 * don't have to look it up again)
2584 * @param iPageY the current y position (optional, this just makes it so we
2585 * don't have to look it up again)
2587 cachePosition: function(iPageX, iPageY) {
2589 this.lastPageX = iPageX;
2590 this.lastPageY = iPageY;
2592 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2593 this.lastPageX = aCoord[0];
2594 this.lastPageY = aCoord[1];
2599 * Auto-scroll the window if the dragged object has been moved beyond the
2600 * visible window boundary.
2601 * @method autoScroll
2602 * @param {int} x the drag element's x position
2603 * @param {int} y the drag element's y position
2604 * @param {int} h the height of the drag element
2605 * @param {int} w the width of the drag element
2608 autoScroll: function(x, y, h, w) {
2611 // The client height
2612 var clientH = Roo.lib.Dom.getViewWidth();
2615 var clientW = Roo.lib.Dom.getViewHeight();
2617 // The amt scrolled down
2618 var st = this.DDM.getScrollTop();
2620 // The amt scrolled right
2621 var sl = this.DDM.getScrollLeft();
2623 // Location of the bottom of the element
2626 // Location of the right of the element
2629 // The distance from the cursor to the bottom of the visible area,
2630 // adjusted so that we don't scroll if the cursor is beyond the
2631 // element drag constraints
2632 var toBot = (clientH + st - y - this.deltaY);
2634 // The distance from the cursor to the right of the visible area
2635 var toRight = (clientW + sl - x - this.deltaX);
2638 // How close to the edge the cursor must be before we scroll
2639 // var thresh = (document.all) ? 100 : 40;
2642 // How many pixels to scroll per autoscroll op. This helps to reduce
2643 // clunky scrolling. IE is more sensitive about this ... it needs this
2644 // value to be higher.
2645 var scrAmt = (document.all) ? 80 : 30;
2647 // Scroll down if we are near the bottom of the visible page and the
2648 // obj extends below the crease
2649 if ( bot > clientH && toBot < thresh ) {
2650 window.scrollTo(sl, st + scrAmt);
2653 // Scroll up if the window is scrolled down and the top of the object
2654 // goes above the top border
2655 if ( y < st && st > 0 && y - st < thresh ) {
2656 window.scrollTo(sl, st - scrAmt);
2659 // Scroll right if the obj is beyond the right border and the cursor is
2661 if ( right > clientW && toRight < thresh ) {
2662 window.scrollTo(sl + scrAmt, st);
2665 // Scroll left if the window has been scrolled to the right and the obj
2666 // extends past the left border
2667 if ( x < sl && sl > 0 && x - sl < thresh ) {
2668 window.scrollTo(sl - scrAmt, st);
2674 * Finds the location the element should be placed if we want to move
2675 * it to where the mouse location less the click offset would place us.
2676 * @method getTargetCoord
2677 * @param {int} iPageX the X coordinate of the click
2678 * @param {int} iPageY the Y coordinate of the click
2679 * @return an object that contains the coordinates (Object.x and Object.y)
2682 getTargetCoord: function(iPageX, iPageY) {
2685 var x = iPageX - this.deltaX;
2686 var y = iPageY - this.deltaY;
2688 if (this.constrainX) {
2689 if (x < this.minX) { x = this.minX; }
2690 if (x > this.maxX) { x = this.maxX; }
2693 if (this.constrainY) {
2694 if (y < this.minY) { y = this.minY; }
2695 if (y > this.maxY) { y = this.maxY; }
2698 x = this.getTick(x, this.xTicks);
2699 y = this.getTick(y, this.yTicks);
2706 * Sets up config options specific to this class. Overrides
2707 * Roo.dd.DragDrop, but all versions of this method through the
2708 * inheritance chain are called
2710 applyConfig: function() {
2711 Roo.dd.DD.superclass.applyConfig.call(this);
2712 this.scroll = (this.config.scroll !== false);
2716 * Event that fires prior to the onMouseDown event. Overrides
2719 b4MouseDown: function(e) {
2720 // this.resetConstraints();
2721 this.autoOffset(e.getPageX(),
2726 * Event that fires prior to the onDrag event. Overrides
2729 b4Drag: function(e) {
2730 this.setDragElPos(e.getPageX(),
2734 toString: function() {
2735 return ("DD " + this.id);
2738 //////////////////////////////////////////////////////////////////////////
2739 // Debugging ygDragDrop events that can be overridden
2740 //////////////////////////////////////////////////////////////////////////
2742 startDrag: function(x, y) {
2745 onDrag: function(e) {
2748 onDragEnter: function(e, id) {
2751 onDragOver: function(e, id) {
2754 onDragOut: function(e, id) {
2757 onDragDrop: function(e, id) {
2760 endDrag: function(e) {
2767 * Ext JS Library 1.1.1
2768 * Copyright(c) 2006-2007, Ext JS, LLC.
2770 * Originally Released Under LGPL - original licence link has changed is not relivant.
2773 * <script type="text/javascript">
2777 * @class Roo.dd.DDProxy
2778 * A DragDrop implementation that inserts an empty, bordered div into
2779 * the document that follows the cursor during drag operations. At the time of
2780 * the click, the frame div is resized to the dimensions of the linked html
2781 * element, and moved to the exact location of the linked element.
2783 * References to the "frame" element refer to the single proxy element that
2784 * was created to be dragged in place of all DDProxy elements on the
2787 * @extends Roo.dd.DD
2789 * @param {String} id the id of the linked html element
2790 * @param {String} sGroup the group of related DragDrop objects
2791 * @param {object} config an object containing configurable attributes
2792 * Valid properties for DDProxy in addition to those in DragDrop:
2793 * resizeFrame, centerFrame, dragElId
2795 Roo.dd.DDProxy = function(id, sGroup, config) {
2797 this.init(id, sGroup, config);
2803 * The default drag frame div id
2804 * @property Roo.dd.DDProxy.dragElId
2808 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2810 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2813 * By default we resize the drag frame to be the same size as the element
2814 * we want to drag (this is to get the frame effect). We can turn it off
2815 * if we want a different behavior.
2816 * @property resizeFrame
2822 * By default the frame is positioned exactly where the drag element is, so
2823 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2824 * you do not have constraints on the obj is to have the drag frame centered
2825 * around the cursor. Set centerFrame to true for this effect.
2826 * @property centerFrame
2832 * Creates the proxy element if it does not yet exist
2833 * @method createFrame
2835 createFrame: function() {
2837 var body = document.body;
2839 if (!body || !body.firstChild) {
2840 setTimeout( function() { self.createFrame(); }, 50 );
2844 var div = this.getDragEl();
2847 div = document.createElement("div");
2848 div.id = this.dragElId;
2851 s.position = "absolute";
2852 s.visibility = "hidden";
2854 s.border = "2px solid #aaa";
2857 // appendChild can blow up IE if invoked prior to the window load event
2858 // while rendering a table. It is possible there are other scenarios
2859 // that would cause this to happen as well.
2860 body.insertBefore(div, body.firstChild);
2865 * Initialization for the drag frame element. Must be called in the
2866 * constructor of all subclasses
2869 initFrame: function() {
2873 applyConfig: function() {
2874 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2876 this.resizeFrame = (this.config.resizeFrame !== false);
2877 this.centerFrame = (this.config.centerFrame);
2878 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2882 * Resizes the drag frame to the dimensions of the clicked object, positions
2883 * it over the object, and finally displays it
2885 * @param {int} iPageX X click position
2886 * @param {int} iPageY Y click position
2889 showFrame: function(iPageX, iPageY) {
2890 var el = this.getEl();
2891 var dragEl = this.getDragEl();
2892 var s = dragEl.style;
2894 this._resizeProxy();
2896 if (this.centerFrame) {
2897 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2898 Math.round(parseInt(s.height, 10)/2) );
2901 this.setDragElPos(iPageX, iPageY);
2903 Roo.fly(dragEl).show();
2907 * The proxy is automatically resized to the dimensions of the linked
2908 * element when a drag is initiated, unless resizeFrame is set to false
2909 * @method _resizeProxy
2912 _resizeProxy: function() {
2913 if (this.resizeFrame) {
2914 var el = this.getEl();
2915 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2919 // overrides Roo.dd.DragDrop
2920 b4MouseDown: function(e) {
2921 var x = e.getPageX();
2922 var y = e.getPageY();
2923 this.autoOffset(x, y);
2924 this.setDragElPos(x, y);
2927 // overrides Roo.dd.DragDrop
2928 b4StartDrag: function(x, y) {
2929 // show the drag frame
2930 this.showFrame(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4EndDrag: function(e) {
2935 Roo.fly(this.getDragEl()).hide();
2938 // overrides Roo.dd.DragDrop
2939 // By default we try to move the element to the last location of the frame.
2940 // This is so that the default behavior mirrors that of Roo.dd.DD.
2941 endDrag: function(e) {
2943 var lel = this.getEl();
2944 var del = this.getDragEl();
2946 // Show the drag frame briefly so we can get its position
2947 del.style.visibility = "";
2950 // Hide the linked element before the move to get around a Safari
2952 lel.style.visibility = "hidden";
2953 Roo.dd.DDM.moveToEl(lel, del);
2954 del.style.visibility = "hidden";
2955 lel.style.visibility = "";
2960 beforeMove : function(){
2964 afterDrag : function(){
2968 toString: function() {
2969 return ("DDProxy " + this.id);
2975 * Ext JS Library 1.1.1
2976 * Copyright(c) 2006-2007, Ext JS, LLC.
2978 * Originally Released Under LGPL - original licence link has changed is not relivant.
2981 * <script type="text/javascript">
2985 * @class Roo.dd.DDTarget
2986 * A DragDrop implementation that does not move, but can be a drop
2987 * target. You would get the same result by simply omitting implementation
2988 * for the event callbacks, but this way we reduce the processing cost of the
2989 * event listener and the callbacks.
2990 * @extends Roo.dd.DragDrop
2992 * @param {String} id the id of the element that is a drop target
2993 * @param {String} sGroup the group of related DragDrop objects
2994 * @param {object} config an object containing configurable attributes
2995 * Valid properties for DDTarget in addition to those in
2999 Roo.dd.DDTarget = function(id, sGroup, config) {
3001 this.initTarget(id, sGroup, config);
3005 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3006 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3007 toString: function() {
3008 return ("DDTarget " + this.id);
3013 * Ext JS Library 1.1.1
3014 * Copyright(c) 2006-2007, Ext JS, LLC.
3016 * Originally Released Under LGPL - original licence link has changed is not relivant.
3019 * <script type="text/javascript">
3024 * @class Roo.dd.ScrollManager
3025 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3026 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3029 Roo.dd.ScrollManager = function(){
3030 var ddm = Roo.dd.DragDropMgr;
3035 var onStop = function(e){
3040 var triggerRefresh = function(){
3041 if(ddm.dragCurrent){
3042 ddm.refreshCache(ddm.dragCurrent.groups);
3046 var doScroll = function(){
3047 if(ddm.dragCurrent){
3048 var dds = Roo.dd.ScrollManager;
3050 if(proc.el.scroll(proc.dir, dds.increment)){
3054 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3059 var clearProc = function(){
3061 clearInterval(proc.id);
3068 var startProc = function(el, dir){
3072 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3075 var onFire = function(e, isDrop){
3076 if(isDrop || !ddm.dragCurrent){ return; }
3077 var dds = Roo.dd.ScrollManager;
3078 if(!dragEl || dragEl != ddm.dragCurrent){
3079 dragEl = ddm.dragCurrent;
3080 // refresh regions on drag start
3084 var xy = Roo.lib.Event.getXY(e);
3085 var pt = new Roo.lib.Point(xy[0], xy[1]);
3087 var el = els[id], r = el._region;
3088 if(r && r.contains(pt) && el.isScrollable()){
3089 if(r.bottom - pt.y <= dds.thresh){
3091 startProc(el, "down");
3094 }else if(r.right - pt.x <= dds.thresh){
3096 startProc(el, "left");
3099 }else if(pt.y - r.top <= dds.thresh){
3101 startProc(el, "up");
3104 }else if(pt.x - r.left <= dds.thresh){
3106 startProc(el, "right");
3115 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3116 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3120 * Registers new overflow element(s) to auto scroll
3121 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3123 register : function(el){
3124 if(el instanceof Array){
3125 for(var i = 0, len = el.length; i < len; i++) {
3126 this.register(el[i]);
3135 * Unregisters overflow element(s) so they are no longer scrolled
3136 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3138 unregister : function(el){
3139 if(el instanceof Array){
3140 for(var i = 0, len = el.length; i < len; i++) {
3141 this.unregister(el[i]);
3150 * The number of pixels from the edge of a container the pointer needs to be to
3151 * trigger scrolling (defaults to 25)
3157 * The number of pixels to scroll in each scroll increment (defaults to 50)
3163 * The frequency of scrolls in milliseconds (defaults to 500)
3169 * True to animate the scroll (defaults to true)
3175 * The animation duration in seconds -
3176 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3182 * Manually trigger a cache refresh.
3184 refreshCache : function(){
3186 if(typeof els[id] == 'object'){ // for people extending the object prototype
3187 els[id]._region = els[id].getRegion();
3194 * Ext JS Library 1.1.1
3195 * Copyright(c) 2006-2007, Ext JS, LLC.
3197 * Originally Released Under LGPL - original licence link has changed is not relivant.
3200 * <script type="text/javascript">
3205 * @class Roo.dd.Registry
3206 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3207 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3210 Roo.dd.Registry = function(){
3215 var getId = function(el, autogen){
3216 if(typeof el == "string"){
3220 if(!id && autogen !== false){
3221 id = "roodd-" + (++autoIdSeed);
3229 * Register a drag drop element
3230 * @param {String|HTMLElement} element The id or DOM node to register
3231 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3232 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3233 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3234 * populated in the data object (if applicable):
3236 Value Description<br />
3237 --------- ------------------------------------------<br />
3238 handles Array of DOM nodes that trigger dragging<br />
3239 for the element being registered<br />
3240 isHandle True if the element passed in triggers<br />
3241 dragging itself, else false
3244 register : function(el, data){
3246 if(typeof el == "string"){
3247 el = document.getElementById(el);
3250 elements[getId(el)] = data;
3251 if(data.isHandle !== false){
3252 handles[data.ddel.id] = data;
3255 var hs = data.handles;
3256 for(var i = 0, len = hs.length; i < len; i++){
3257 handles[getId(hs[i])] = data;
3263 * Unregister a drag drop element
3264 * @param {String|HTMLElement} element The id or DOM node to unregister
3266 unregister : function(el){
3267 var id = getId(el, false);
3268 var data = elements[id];
3270 delete elements[id];
3272 var hs = data.handles;
3273 for(var i = 0, len = hs.length; i < len; i++){
3274 delete handles[getId(hs[i], false)];
3281 * Returns the handle registered for a DOM Node by id
3282 * @param {String|HTMLElement} id The DOM node or id to look up
3283 * @return {Object} handle The custom handle data
3285 getHandle : function(id){
3286 if(typeof id != "string"){ // must be element?
3293 * Returns the handle that is registered for the DOM node that is the target of the event
3294 * @param {Event} e The event
3295 * @return {Object} handle The custom handle data
3297 getHandleFromEvent : function(e){
3298 var t = Roo.lib.Event.getTarget(e);
3299 return t ? handles[t.id] : null;
3303 * Returns a custom data object that is registered for a DOM node by id
3304 * @param {String|HTMLElement} id The DOM node or id to look up
3305 * @return {Object} data The custom data
3307 getTarget : function(id){
3308 if(typeof id != "string"){ // must be element?
3311 return elements[id];
3315 * Returns a custom data object that is registered for the DOM node that is the target of the event
3316 * @param {Event} e The event
3317 * @return {Object} data The custom data
3319 getTargetFromEvent : function(e){
3320 var t = Roo.lib.Event.getTarget(e);
3321 return t ? elements[t.id] || handles[t.id] : null;
3326 * Ext JS Library 1.1.1
3327 * Copyright(c) 2006-2007, Ext JS, LLC.
3329 * Originally Released Under LGPL - original licence link has changed is not relivant.
3332 * <script type="text/javascript">
3337 * @class Roo.dd.StatusProxy
3338 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3339 * default drag proxy used by all Roo.dd components.
3341 * @param {Object} config
3343 Roo.dd.StatusProxy = function(config){
3344 Roo.apply(this, config);
3345 this.id = this.id || Roo.id();
3346 this.el = new Roo.Layer({
3348 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3349 {tag: "div", cls: "x-dd-drop-icon"},
3350 {tag: "div", cls: "x-dd-drag-ghost"}
3353 shadow: !config || config.shadow !== false
3355 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3356 this.dropStatus = this.dropNotAllowed;
3359 Roo.dd.StatusProxy.prototype = {
3361 * @cfg {String} dropAllowed
3362 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3364 dropAllowed : "x-dd-drop-ok",
3366 * @cfg {String} dropNotAllowed
3367 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3369 dropNotAllowed : "x-dd-drop-nodrop",
3372 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3373 * over the current target element.
3374 * @param {String} cssClass The css class for the new drop status indicator image
3376 setStatus : function(cssClass){
3377 cssClass = cssClass || this.dropNotAllowed;
3378 if(this.dropStatus != cssClass){
3379 this.el.replaceClass(this.dropStatus, cssClass);
3380 this.dropStatus = cssClass;
3385 * Resets the status indicator to the default dropNotAllowed value
3386 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3388 reset : function(clearGhost){
3389 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3390 this.dropStatus = this.dropNotAllowed;
3392 this.ghost.update("");
3397 * Updates the contents of the ghost element
3398 * @param {String} html The html that will replace the current innerHTML of the ghost element
3400 update : function(html){
3401 if(typeof html == "string"){
3402 this.ghost.update(html);
3404 this.ghost.update("");
3405 html.style.margin = "0";
3406 this.ghost.dom.appendChild(html);
3408 // ensure float = none set?? cant remember why though.
3409 var el = this.ghost.dom.firstChild;
3411 Roo.fly(el).setStyle('float', 'none');
3416 * Returns the underlying proxy {@link Roo.Layer}
3417 * @return {Roo.Layer} el
3424 * Returns the ghost element
3425 * @return {Roo.Element} el
3427 getGhost : function(){
3433 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3435 hide : function(clear){
3443 * Stops the repair animation if it's currently running
3446 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3452 * Displays this proxy
3459 * Force the Layer to sync its shadow and shim positions to the element
3466 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3467 * invalid drop operation by the item being dragged.
3468 * @param {Array} xy The XY position of the element ([x, y])
3469 * @param {Function} callback The function to call after the repair is complete
3470 * @param {Object} scope The scope in which to execute the callback
3472 repair : function(xy, callback, scope){
3473 this.callback = callback;
3475 if(xy && this.animRepair !== false){
3476 this.el.addClass("x-dd-drag-repair");
3477 this.el.hideUnders(true);
3478 this.anim = this.el.shift({
3479 duration: this.repairDuration || .5,
3483 callback: this.afterRepair,
3492 afterRepair : function(){
3494 if(typeof this.callback == "function"){
3495 this.callback.call(this.scope || this);
3497 this.callback = null;
3502 * Ext JS Library 1.1.1
3503 * Copyright(c) 2006-2007, Ext JS, LLC.
3505 * Originally Released Under LGPL - original licence link has changed is not relivant.
3508 * <script type="text/javascript">
3512 * @class Roo.dd.DragSource
3513 * @extends Roo.dd.DDProxy
3514 * A simple class that provides the basic implementation needed to make any element draggable.
3516 * @param {String/HTMLElement/Element} el The container element
3517 * @param {Object} config
3519 Roo.dd.DragSource = function(el, config){
3520 this.el = Roo.get(el);
3523 Roo.apply(this, config);
3526 this.proxy = new Roo.dd.StatusProxy();
3529 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3530 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3532 this.dragging = false;
3535 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3537 * @cfg {String} dropAllowed
3538 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3540 dropAllowed : "x-dd-drop-ok",
3542 * @cfg {String} dropNotAllowed
3543 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3545 dropNotAllowed : "x-dd-drop-nodrop",
3548 * Returns the data object associated with this drag source
3549 * @return {Object} data An object containing arbitrary data
3551 getDragData : function(e){
3552 return this.dragData;
3556 onDragEnter : function(e, id){
3557 var target = Roo.dd.DragDropMgr.getDDById(id);
3558 this.cachedTarget = target;
3559 if(this.beforeDragEnter(target, e, id) !== false){
3560 if(target.isNotifyTarget){
3561 var status = target.notifyEnter(this, e, this.dragData);
3562 this.proxy.setStatus(status);
3564 this.proxy.setStatus(this.dropAllowed);
3567 if(this.afterDragEnter){
3569 * An empty function by default, but provided so that you can perform a custom action
3570 * when the dragged item enters the drop target by providing an implementation.
3571 * @param {Roo.dd.DragDrop} target The drop target
3572 * @param {Event} e The event object
3573 * @param {String} id The id of the dragged element
3574 * @method afterDragEnter
3576 this.afterDragEnter(target, e, id);
3582 * An empty function by default, but provided so that you can perform a custom action
3583 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3584 * @param {Roo.dd.DragDrop} target The drop target
3585 * @param {Event} e The event object
3586 * @param {String} id The id of the dragged element
3587 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3589 beforeDragEnter : function(target, e, id){
3594 alignElWithMouse: function() {
3595 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3600 onDragOver : function(e, id){
3601 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3602 if(this.beforeDragOver(target, e, id) !== false){
3603 if(target.isNotifyTarget){
3604 var status = target.notifyOver(this, e, this.dragData);
3605 this.proxy.setStatus(status);
3608 if(this.afterDragOver){
3610 * An empty function by default, but provided so that you can perform a custom action
3611 * while the dragged item is over the drop target by providing an implementation.
3612 * @param {Roo.dd.DragDrop} target The drop target
3613 * @param {Event} e The event object
3614 * @param {String} id The id of the dragged element
3615 * @method afterDragOver
3617 this.afterDragOver(target, e, id);
3623 * An empty function by default, but provided so that you can perform a custom action
3624 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3625 * @param {Roo.dd.DragDrop} target The drop target
3626 * @param {Event} e The event object
3627 * @param {String} id The id of the dragged element
3628 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3630 beforeDragOver : function(target, e, id){
3635 onDragOut : function(e, id){
3636 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3637 if(this.beforeDragOut(target, e, id) !== false){
3638 if(target.isNotifyTarget){
3639 target.notifyOut(this, e, this.dragData);
3642 if(this.afterDragOut){
3644 * An empty function by default, but provided so that you can perform a custom action
3645 * after the dragged item is dragged out of the target without dropping.
3646 * @param {Roo.dd.DragDrop} target The drop target
3647 * @param {Event} e The event object
3648 * @param {String} id The id of the dragged element
3649 * @method afterDragOut
3651 this.afterDragOut(target, e, id);
3654 this.cachedTarget = null;
3658 * An empty function by default, but provided so that you can perform a custom action before the dragged
3659 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3660 * @param {Roo.dd.DragDrop} target The drop target
3661 * @param {Event} e The event object
3662 * @param {String} id The id of the dragged element
3663 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3665 beforeDragOut : function(target, e, id){
3670 onDragDrop : function(e, id){
3671 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3672 if(this.beforeDragDrop(target, e, id) !== false){
3673 if(target.isNotifyTarget){
3674 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3675 this.onValidDrop(target, e, id);
3677 this.onInvalidDrop(target, e, id);
3680 this.onValidDrop(target, e, id);
3683 if(this.afterDragDrop){
3685 * An empty function by default, but provided so that you can perform a custom action
3686 * after a valid drag drop has occurred by providing an implementation.
3687 * @param {Roo.dd.DragDrop} target The drop target
3688 * @param {Event} e The event object
3689 * @param {String} id The id of the dropped element
3690 * @method afterDragDrop
3692 this.afterDragDrop(target, e, id);
3695 delete this.cachedTarget;
3699 * An empty function by default, but provided so that you can perform a custom action before the dragged
3700 * item is dropped onto the target and optionally cancel the onDragDrop.
3701 * @param {Roo.dd.DragDrop} target The drop target
3702 * @param {Event} e The event object
3703 * @param {String} id The id of the dragged element
3704 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3706 beforeDragDrop : function(target, e, id){
3711 onValidDrop : function(target, e, id){
3713 if(this.afterValidDrop){
3715 * An empty function by default, but provided so that you can perform a custom action
3716 * after a valid drop has occurred by providing an implementation.
3717 * @param {Object} target The target DD
3718 * @param {Event} e The event object
3719 * @param {String} id The id of the dropped element
3720 * @method afterInvalidDrop
3722 this.afterValidDrop(target, e, id);
3727 getRepairXY : function(e, data){
3728 return this.el.getXY();
3732 onInvalidDrop : function(target, e, id){
3733 this.beforeInvalidDrop(target, e, id);
3734 if(this.cachedTarget){
3735 if(this.cachedTarget.isNotifyTarget){
3736 this.cachedTarget.notifyOut(this, e, this.dragData);
3738 this.cacheTarget = null;
3740 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3742 if(this.afterInvalidDrop){
3744 * An empty function by default, but provided so that you can perform a custom action
3745 * after an invalid drop has occurred by providing an implementation.
3746 * @param {Event} e The event object
3747 * @param {String} id The id of the dropped element
3748 * @method afterInvalidDrop
3750 this.afterInvalidDrop(e, id);
3755 afterRepair : function(){
3757 this.el.highlight(this.hlColor || "c3daf9");
3759 this.dragging = false;
3763 * An empty function by default, but provided so that you can perform a custom action after an invalid
3764 * drop has occurred.
3765 * @param {Roo.dd.DragDrop} target The drop target
3766 * @param {Event} e The event object
3767 * @param {String} id The id of the dragged element
3768 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3770 beforeInvalidDrop : function(target, e, id){
3775 handleMouseDown : function(e){
3779 var data = this.getDragData(e);
3780 if(data && this.onBeforeDrag(data, e) !== false){
3781 this.dragData = data;
3783 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3788 * An empty function by default, but provided so that you can perform a custom action before the initial
3789 * drag event begins and optionally cancel it.
3790 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3791 * @param {Event} e The event object
3792 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3794 onBeforeDrag : function(data, e){
3799 * An empty function by default, but provided so that you can perform a custom action once the initial
3800 * drag event has begun. The drag cannot be canceled from this function.
3801 * @param {Number} x The x position of the click on the dragged object
3802 * @param {Number} y The y position of the click on the dragged object
3804 onStartDrag : Roo.emptyFn,
3806 // private - YUI override
3807 startDrag : function(x, y){
3809 this.dragging = true;
3810 this.proxy.update("");
3811 this.onInitDrag(x, y);
3816 onInitDrag : function(x, y){
3817 var clone = this.el.dom.cloneNode(true);
3818 clone.id = Roo.id(); // prevent duplicate ids
3819 this.proxy.update(clone);
3820 this.onStartDrag(x, y);
3825 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3826 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3828 getProxy : function(){
3833 * Hides the drag source's {@link Roo.dd.StatusProxy}
3835 hideProxy : function(){
3837 this.proxy.reset(true);
3838 this.dragging = false;
3842 triggerCacheRefresh : function(){
3843 Roo.dd.DDM.refreshCache(this.groups);
3846 // private - override to prevent hiding
3847 b4EndDrag: function(e) {
3850 // private - override to prevent moving
3851 endDrag : function(e){
3852 this.onEndDrag(this.dragData, e);
3856 onEndDrag : function(data, e){
3859 // private - pin to cursor
3860 autoOffset : function(x, y) {
3861 this.setDelta(-12, -20);
3865 * Ext JS Library 1.1.1
3866 * Copyright(c) 2006-2007, Ext JS, LLC.
3868 * Originally Released Under LGPL - original licence link has changed is not relivant.
3871 * <script type="text/javascript">
3876 * @class Roo.dd.DropTarget
3877 * @extends Roo.dd.DDTarget
3878 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3879 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3881 * @param {String/HTMLElement/Element} el The container element
3882 * @param {Object} config
3884 Roo.dd.DropTarget = function(el, config){
3885 this.el = Roo.get(el);
3887 Roo.apply(this, config);
3889 if(this.containerScroll){
3890 Roo.dd.ScrollManager.register(this.el);
3893 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3898 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3900 * @cfg {String} overClass
3901 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3904 * @cfg {String} dropAllowed
3905 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3907 dropAllowed : "x-dd-drop-ok",
3909 * @cfg {String} dropNotAllowed
3910 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3912 dropNotAllowed : "x-dd-drop-nodrop",
3918 isNotifyTarget : true,
3921 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3922 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3923 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3924 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3925 * @param {Event} e The event
3926 * @param {Object} data An object containing arbitrary data supplied by the drag source
3927 * @return {String} status The CSS class that communicates the drop status back to the source so that the
3928 * underlying {@link Roo.dd.StatusProxy} can be updated
3930 notifyEnter : function(dd, e, data){
3932 this.el.addClass(this.overClass);
3934 return this.dropAllowed;
3938 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3939 * This method will be called on every mouse movement while the drag source is over the drop target.
3940 * This default implementation simply returns the dropAllowed config value.
3941 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3942 * @param {Event} e The event
3943 * @param {Object} data An object containing arbitrary data supplied by the drag source
3944 * @return {String} status The CSS class that communicates the drop status back to the source so that the
3945 * underlying {@link Roo.dd.StatusProxy} can be updated
3947 notifyOver : function(dd, e, data){
3948 return this.dropAllowed;
3952 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3953 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3954 * overClass (if any) from the drop element.
3955 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3956 * @param {Event} e The event
3957 * @param {Object} data An object containing arbitrary data supplied by the drag source
3959 notifyOut : function(dd, e, data){
3961 this.el.removeClass(this.overClass);
3966 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3967 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3968 * implementation that does something to process the drop event and returns true so that the drag source's
3969 * repair action does not run.
3970 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3971 * @param {Event} e The event
3972 * @param {Object} data An object containing arbitrary data supplied by the drag source
3973 * @return {Boolean} True if the drop was valid, else false
3975 notifyDrop : function(dd, e, data){
3980 * Ext JS Library 1.1.1
3981 * Copyright(c) 2006-2007, Ext JS, LLC.
3983 * Originally Released Under LGPL - original licence link has changed is not relivant.
3986 * <script type="text/javascript">
3991 * @class Roo.dd.DragZone
3992 * @extends Roo.dd.DragSource
3993 * This class provides a container DD instance that proxies for multiple child node sources.<br />
3994 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
3996 * @param {String/HTMLElement/Element} el The container element
3997 * @param {Object} config
3999 Roo.dd.DragZone = function(el, config){
4000 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4001 if(this.containerScroll){
4002 Roo.dd.ScrollManager.register(this.el);
4006 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4008 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4009 * for auto scrolling during drag operations.
4012 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4013 * method after a failed drop (defaults to "c3daf9" - light blue)
4017 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4018 * for a valid target to drag based on the mouse down. Override this method
4019 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4020 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4021 * @param {EventObject} e The mouse down event
4022 * @return {Object} The dragData
4024 getDragData : function(e){
4025 return Roo.dd.Registry.getHandleFromEvent(e);
4029 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4030 * this.dragData.ddel
4031 * @param {Number} x The x position of the click on the dragged object
4032 * @param {Number} y The y position of the click on the dragged object
4033 * @return {Boolean} true to continue the drag, false to cancel
4035 onInitDrag : function(x, y){
4036 this.proxy.update(this.dragData.ddel.cloneNode(true));
4037 this.onStartDrag(x, y);
4042 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4044 afterRepair : function(){
4046 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4048 this.dragging = false;
4052 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4053 * the XY of this.dragData.ddel
4054 * @param {EventObject} e The mouse up event
4055 * @return {Array} The xy location (e.g. [100, 200])
4057 getRepairXY : function(e){
4058 return Roo.Element.fly(this.dragData.ddel).getXY();
4062 * Ext JS Library 1.1.1
4063 * Copyright(c) 2006-2007, Ext JS, LLC.
4065 * Originally Released Under LGPL - original licence link has changed is not relivant.
4068 * <script type="text/javascript">
4071 * @class Roo.dd.DropZone
4072 * @extends Roo.dd.DropTarget
4073 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4074 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4076 * @param {String/HTMLElement/Element} el The container element
4077 * @param {Object} config
4079 Roo.dd.DropZone = function(el, config){
4080 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4083 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4085 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4086 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4087 * provide your own custom lookup.
4088 * @param {Event} e The event
4089 * @return {Object} data The custom data
4091 getTargetFromEvent : function(e){
4092 return Roo.dd.Registry.getTargetFromEvent(e);
4096 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4097 * that it has registered. This method has no default implementation and should be overridden to provide
4098 * node-specific processing if necessary.
4099 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4100 * {@link #getTargetFromEvent} for this node)
4101 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4102 * @param {Event} e The event
4103 * @param {Object} data An object containing arbitrary data supplied by the drag source
4105 onNodeEnter : function(n, dd, e, data){
4110 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4111 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4112 * overridden to provide the proper feedback.
4113 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4114 * {@link #getTargetFromEvent} for this node)
4115 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4116 * @param {Event} e The event
4117 * @param {Object} data An object containing arbitrary data supplied by the drag source
4118 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4119 * underlying {@link Roo.dd.StatusProxy} can be updated
4121 onNodeOver : function(n, dd, e, data){
4122 return this.dropAllowed;
4126 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4127 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4128 * node-specific processing if necessary.
4129 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4130 * {@link #getTargetFromEvent} for this node)
4131 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4132 * @param {Event} e The event
4133 * @param {Object} data An object containing arbitrary data supplied by the drag source
4135 onNodeOut : function(n, dd, e, data){
4140 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4141 * the drop node. The default implementation returns false, so it should be overridden to provide the
4142 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4143 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4144 * {@link #getTargetFromEvent} for this node)
4145 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4146 * @param {Event} e The event
4147 * @param {Object} data An object containing arbitrary data supplied by the drag source
4148 * @return {Boolean} True if the drop was valid, else false
4150 onNodeDrop : function(n, dd, e, data){
4155 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4156 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4157 * it should be overridden to provide the proper feedback if necessary.
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
4161 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4162 * underlying {@link Roo.dd.StatusProxy} can be updated
4164 onContainerOver : function(dd, e, data){
4165 return this.dropNotAllowed;
4169 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4170 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4171 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4172 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4173 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4174 * @param {Event} e The event
4175 * @param {Object} data An object containing arbitrary data supplied by the drag source
4176 * @return {Boolean} True if the drop was valid, else false
4178 onContainerDrop : function(dd, e, data){
4183 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4184 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4185 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4186 * you should override this method and provide a custom implementation.
4187 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4188 * @param {Event} e The event
4189 * @param {Object} data An object containing arbitrary data supplied by the drag source
4190 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4191 * underlying {@link Roo.dd.StatusProxy} can be updated
4193 notifyEnter : function(dd, e, data){
4194 return this.dropNotAllowed;
4198 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4199 * This method will be called on every mouse movement while the drag source is over the drop zone.
4200 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4201 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4202 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4203 * registered node, it will call {@link #onContainerOver}.
4204 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4205 * @param {Event} e The event
4206 * @param {Object} data An object containing arbitrary data supplied by the drag source
4207 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4208 * underlying {@link Roo.dd.StatusProxy} can be updated
4210 notifyOver : function(dd, e, data){
4211 var n = this.getTargetFromEvent(e);
4212 if(!n){ // not over valid drop target
4213 if(this.lastOverNode){
4214 this.onNodeOut(this.lastOverNode, dd, e, data);
4215 this.lastOverNode = null;
4217 return this.onContainerOver(dd, e, data);
4219 if(this.lastOverNode != n){
4220 if(this.lastOverNode){
4221 this.onNodeOut(this.lastOverNode, dd, e, data);
4223 this.onNodeEnter(n, dd, e, data);
4224 this.lastOverNode = n;
4226 return this.onNodeOver(n, dd, e, data);
4230 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4231 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4232 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4233 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4234 * @param {Event} e The event
4235 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4237 notifyOut : function(dd, e, data){
4238 if(this.lastOverNode){
4239 this.onNodeOut(this.lastOverNode, dd, e, data);
4240 this.lastOverNode = null;
4245 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4246 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4247 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4248 * otherwise it will call {@link #onContainerDrop}.
4249 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4250 * @param {Event} e The event
4251 * @param {Object} data An object containing arbitrary data supplied by the drag source
4252 * @return {Boolean} True if the drop was valid, else false
4254 notifyDrop : function(dd, e, data){
4255 if(this.lastOverNode){
4256 this.onNodeOut(this.lastOverNode, dd, e, data);
4257 this.lastOverNode = null;
4259 var n = this.getTargetFromEvent(e);
4261 this.onNodeDrop(n, dd, e, data) :
4262 this.onContainerDrop(dd, e, data);
4266 triggerCacheRefresh : function(){
4267 Roo.dd.DDM.refreshCache(this.groups);
4271 * Ext JS Library 1.1.1
4272 * Copyright(c) 2006-2007, Ext JS, LLC.
4274 * Originally Released Under LGPL - original licence link has changed is not relivant.
4277 * <script type="text/javascript">
4282 * @class Roo.data.SortTypes
4284 * Defines the default sorting (casting?) comparison functions used when sorting data.
4286 Roo.data.SortTypes = {
4288 * Default sort that does nothing
4289 * @param {Mixed} s The value being converted
4290 * @return {Mixed} The comparison value
4297 * The regular expression used to strip tags
4301 stripTagsRE : /<\/?[^>]+>/gi,
4304 * Strips all HTML tags to sort on text only
4305 * @param {Mixed} s The value being converted
4306 * @return {String} The comparison value
4308 asText : function(s){
4309 return String(s).replace(this.stripTagsRE, "");
4313 * Strips all HTML tags to sort on text only - Case insensitive
4314 * @param {Mixed} s The value being converted
4315 * @return {String} The comparison value
4317 asUCText : function(s){
4318 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4322 * Case insensitive string
4323 * @param {Mixed} s The value being converted
4324 * @return {String} The comparison value
4326 asUCString : function(s) {
4327 return String(s).toUpperCase();
4332 * @param {Mixed} s The value being converted
4333 * @return {Number} The comparison value
4335 asDate : function(s) {
4339 if(s instanceof Date){
4342 return Date.parse(String(s));
4347 * @param {Mixed} s The value being converted
4348 * @return {Float} The comparison value
4350 asFloat : function(s) {
4351 var val = parseFloat(String(s).replace(/,/g, ""));
4352 if(isNaN(val)) val = 0;
4358 * @param {Mixed} s The value being converted
4359 * @return {Number} The comparison value
4361 asInt : function(s) {
4362 var val = parseInt(String(s).replace(/,/g, ""));
4363 if(isNaN(val)) val = 0;
4368 * Ext JS Library 1.1.1
4369 * Copyright(c) 2006-2007, Ext JS, LLC.
4371 * Originally Released Under LGPL - original licence link has changed is not relivant.
4374 * <script type="text/javascript">
4378 * @class Roo.data.Record
4379 * Instances of this class encapsulate both record <em>definition</em> information, and record
4380 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4381 * to access Records cached in an {@link Roo.data.Store} object.<br>
4383 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4384 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4387 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4389 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4390 * {@link #create}. The parameters are the same.
4391 * @param {Array} data An associative Array of data values keyed by the field name.
4392 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4393 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4394 * not specified an integer id is generated.
4396 Roo.data.Record = function(data, id){
4397 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4402 * Generate a constructor for a specific record layout.
4403 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4404 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4405 * Each field definition object may contain the following properties: <ul>
4406 * <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,
4407 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4408 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4409 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4410 * is being used, then this is a string containing the javascript expression to reference the data relative to
4411 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4412 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4413 * this may be omitted.</p></li>
4414 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4415 * <ul><li>auto (Default, implies no conversion)</li>
4420 * <li>date</li></ul></p></li>
4421 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4422 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4423 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4424 * by the Reader into an object that will be stored in the Record. It is passed the
4425 * following parameters:<ul>
4426 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4428 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4430 * <br>usage:<br><pre><code>
4431 var TopicRecord = Roo.data.Record.create(
4432 {name: 'title', mapping: 'topic_title'},
4433 {name: 'author', mapping: 'username'},
4434 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4435 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4436 {name: 'lastPoster', mapping: 'user2'},
4437 {name: 'excerpt', mapping: 'post_text'}
4440 var myNewRecord = new TopicRecord({
4441 title: 'Do my job please',
4444 lastPost: new Date(),
4445 lastPoster: 'Animal',
4446 excerpt: 'No way dude!'
4448 myStore.add(myNewRecord);
4453 Roo.data.Record.create = function(o){
4455 f.superclass.constructor.apply(this, arguments);
4457 Roo.extend(f, Roo.data.Record);
4458 var p = f.prototype;
4459 p.fields = new Roo.util.MixedCollection(false, function(field){
4462 for(var i = 0, len = o.length; i < len; i++){
4463 p.fields.add(new Roo.data.Field(o[i]));
4465 f.getField = function(name){
4466 return p.fields.get(name);
4471 Roo.data.Record.AUTO_ID = 1000;
4472 Roo.data.Record.EDIT = 'edit';
4473 Roo.data.Record.REJECT = 'reject';
4474 Roo.data.Record.COMMIT = 'commit';
4476 Roo.data.Record.prototype = {
4478 * Readonly flag - true if this record has been modified.
4487 join : function(store){
4492 * Set the named field to the specified value.
4493 * @param {String} name The name of the field to set.
4494 * @param {Object} value The value to set the field to.
4496 set : function(name, value){
4497 if(this.data[name] == value){
4504 if(typeof this.modified[name] == 'undefined'){
4505 this.modified[name] = this.data[name];
4507 this.data[name] = value;
4509 this.store.afterEdit(this);
4514 * Get the value of the named field.
4515 * @param {String} name The name of the field to get the value of.
4516 * @return {Object} The value of the field.
4518 get : function(name){
4519 return this.data[name];
4523 beginEdit : function(){
4524 this.editing = true;
4529 cancelEdit : function(){
4530 this.editing = false;
4531 delete this.modified;
4535 endEdit : function(){
4536 this.editing = false;
4537 if(this.dirty && this.store){
4538 this.store.afterEdit(this);
4543 * Usually called by the {@link Roo.data.Store} which owns the Record.
4544 * Rejects all changes made to the Record since either creation, or the last commit operation.
4545 * Modified fields are reverted to their original values.
4547 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4548 * of reject operations.
4550 reject : function(){
4551 var m = this.modified;
4553 if(typeof m[n] != "function"){
4554 this.data[n] = m[n];
4558 delete this.modified;
4559 this.editing = false;
4561 this.store.afterReject(this);
4566 * Usually called by the {@link Roo.data.Store} which owns the Record.
4567 * Commits all changes made to the Record since either creation, or the last commit operation.
4569 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4570 * of commit operations.
4572 commit : function(){
4574 delete this.modified;
4575 this.editing = false;
4577 this.store.afterCommit(this);
4582 hasError : function(){
4583 return this.error != null;
4587 clearError : function(){
4592 * Creates a copy of this record.
4593 * @param {String} id (optional) A new record id if you don't want to use this record's id
4596 copy : function(newId) {
4597 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4601 * Ext JS Library 1.1.1
4602 * Copyright(c) 2006-2007, Ext JS, LLC.
4604 * Originally Released Under LGPL - original licence link has changed is not relivant.
4607 * <script type="text/javascript">
4613 * @class Roo.data.Store
4614 * @extends Roo.util.Observable
4615 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4616 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4618 * 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
4619 * has no knowledge of the format of the data returned by the Proxy.<br>
4621 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4622 * instances from the data object. These records are cached and made available through accessor functions.
4624 * Creates a new Store.
4625 * @param {Object} config A config object containing the objects needed for the Store to access data,
4626 * and read the data into Records.
4628 Roo.data.Store = function(config){
4629 this.data = new Roo.util.MixedCollection(false);
4630 this.data.getKey = function(o){
4633 this.baseParams = {};
4642 if(config && config.data){
4643 this.inlineData = config.data;
4647 Roo.apply(this, config);
4649 if(this.reader){ // reader passed
4650 this.reader = Roo.factory(this.reader, Roo.data);
4651 this.reader.xmodule = this.xmodule || false;
4652 if(!this.recordType){
4653 this.recordType = this.reader.recordType;
4655 if(this.reader.onMetaChange){
4656 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4660 if(this.recordType){
4661 this.fields = this.recordType.prototype.fields;
4667 * @event datachanged
4668 * Fires when the data cache has changed, and a widget which is using this Store
4669 * as a Record cache should refresh its view.
4670 * @param {Store} this
4675 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4676 * @param {Store} this
4677 * @param {Object} meta The JSON metadata
4682 * Fires when Records have been added to the Store
4683 * @param {Store} this
4684 * @param {Roo.data.Record[]} records The array of Records added
4685 * @param {Number} index The index at which the record(s) were added
4690 * Fires when a Record has been removed from the Store
4691 * @param {Store} this
4692 * @param {Roo.data.Record} record The Record that was removed
4693 * @param {Number} index The index at which the record was removed
4698 * Fires when a Record has been updated
4699 * @param {Store} this
4700 * @param {Roo.data.Record} record The Record that was updated
4701 * @param {String} operation The update operation being performed. Value may be one of:
4703 Roo.data.Record.EDIT
4704 Roo.data.Record.REJECT
4705 Roo.data.Record.COMMIT
4711 * Fires when the data cache has been cleared.
4712 * @param {Store} this
4717 * Fires before a request is made for a new data object. If the beforeload handler returns false
4718 * the load action will be canceled.
4719 * @param {Store} this
4720 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4725 * Fires after a new set of Records has been loaded.
4726 * @param {Store} this
4727 * @param {Roo.data.Record[]} records The Records that were loaded
4728 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4732 * @event loadexception
4733 * Fires if an exception occurs in the Proxy during loading.
4734 * Called with the signature of the Proxy's "loadexception" event.
4735 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4738 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4739 * @param {Object} load options
4740 * @param {Object} jsonData from your request (normally this contains the Exception)
4742 loadexception : true
4746 this.proxy = Roo.factory(this.proxy, Roo.data);
4747 this.proxy.xmodule = this.xmodule || false;
4748 this.relayEvents(this.proxy, ["loadexception"]);
4750 this.sortToggle = {};
4752 Roo.data.Store.superclass.constructor.call(this);
4754 if(this.inlineData){
4755 this.loadData(this.inlineData);
4756 delete this.inlineData;
4759 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4761 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4762 * without a remote query - used by combo/forms at present.
4766 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4769 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4772 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4773 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4776 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4777 * on any HTTP request
4780 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4783 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4784 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4789 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4790 * loaded or when a record is removed. (defaults to false).
4792 pruneModifiedRecords : false,
4798 * Add Records to the Store and fires the add event.
4799 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4801 add : function(records){
4802 records = [].concat(records);
4803 for(var i = 0, len = records.length; i < len; i++){
4804 records[i].join(this);
4806 var index = this.data.length;
4807 this.data.addAll(records);
4808 this.fireEvent("add", this, records, index);
4812 * Remove a Record from the Store and fires the remove event.
4813 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4815 remove : function(record){
4816 var index = this.data.indexOf(record);
4817 this.data.removeAt(index);
4818 if(this.pruneModifiedRecords){
4819 this.modified.remove(record);
4821 this.fireEvent("remove", this, record, index);
4825 * Remove all Records from the Store and fires the clear event.
4827 removeAll : function(){
4829 if(this.pruneModifiedRecords){
4832 this.fireEvent("clear", this);
4836 * Inserts Records to the Store at the given index and fires the add event.
4837 * @param {Number} index The start index at which to insert the passed Records.
4838 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4840 insert : function(index, records){
4841 records = [].concat(records);
4842 for(var i = 0, len = records.length; i < len; i++){
4843 this.data.insert(index, records[i]);
4844 records[i].join(this);
4846 this.fireEvent("add", this, records, index);
4850 * Get the index within the cache of the passed Record.
4851 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4852 * @return {Number} The index of the passed Record. Returns -1 if not found.
4854 indexOf : function(record){
4855 return this.data.indexOf(record);
4859 * Get the index within the cache of the Record with the passed id.
4860 * @param {String} id The id of the Record to find.
4861 * @return {Number} The index of the Record. Returns -1 if not found.
4863 indexOfId : function(id){
4864 return this.data.indexOfKey(id);
4868 * Get the Record with the specified id.
4869 * @param {String} id The id of the Record to find.
4870 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4872 getById : function(id){
4873 return this.data.key(id);
4877 * Get the Record at the specified index.
4878 * @param {Number} index The index of the Record to find.
4879 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4881 getAt : function(index){
4882 return this.data.itemAt(index);
4886 * Returns a range of Records between specified indices.
4887 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4888 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4889 * @return {Roo.data.Record[]} An array of Records
4891 getRange : function(start, end){
4892 return this.data.getRange(start, end);
4896 storeOptions : function(o){
4897 o = Roo.apply({}, o);
4900 this.lastOptions = o;
4904 * Loads the Record cache from the configured Proxy using the configured Reader.
4906 * If using remote paging, then the first load call must specify the <em>start</em>
4907 * and <em>limit</em> properties in the options.params property to establish the initial
4908 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4910 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4911 * and this call will return before the new data has been loaded. Perform any post-processing
4912 * in a callback function, or in a "load" event handler.</strong>
4914 * @param {Object} options An object containing properties which control loading options:<ul>
4915 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4916 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4917 * passed the following arguments:<ul>
4918 * <li>r : Roo.data.Record[]</li>
4919 * <li>options: Options object from the load call</li>
4920 * <li>success: Boolean success indicator</li></ul></li>
4921 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4922 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4925 load : function(options){
4926 options = options || {};
4927 if(this.fireEvent("beforeload", this, options) !== false){
4928 this.storeOptions(options);
4929 var p = Roo.apply(options.params || {}, this.baseParams);
4930 if(this.sortInfo && this.remoteSort){
4931 var pn = this.paramNames;
4932 p[pn["sort"]] = this.sortInfo.field;
4933 p[pn["dir"]] = this.sortInfo.direction;
4935 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4940 * Reloads the Record cache from the configured Proxy using the configured Reader and
4941 * the options from the last load operation performed.
4942 * @param {Object} options (optional) An object containing properties which may override the options
4943 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4944 * the most recently used options are reused).
4946 reload : function(options){
4947 this.load(Roo.applyIf(options||{}, this.lastOptions));
4951 // Called as a callback by the Reader during a load operation.
4952 loadRecords : function(o, options, success){
4953 if(!o || success === false){
4954 if(success !== false){
4955 this.fireEvent("load", this, [], options);
4957 if(options.callback){
4958 options.callback.call(options.scope || this, [], options, false);
4962 // if data returned failure - throw an exception.
4963 if (o.success === false) {
4964 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
4967 var r = o.records, t = o.totalRecords || r.length;
4968 if(!options || options.add !== true){
4969 if(this.pruneModifiedRecords){
4972 for(var i = 0, len = r.length; i < len; i++){
4976 this.data = this.snapshot;
4977 delete this.snapshot;
4980 this.data.addAll(r);
4981 this.totalLength = t;
4983 this.fireEvent("datachanged", this);
4985 this.totalLength = Math.max(t, this.data.length+r.length);
4988 this.fireEvent("load", this, r, options);
4989 if(options.callback){
4990 options.callback.call(options.scope || this, r, options, true);
4995 * Loads data from a passed data block. A Reader which understands the format of the data
4996 * must have been configured in the constructor.
4997 * @param {Object} data The data block from which to read the Records. The format of the data expected
4998 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4999 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5001 loadData : function(o, append){
5002 var r = this.reader.readRecords(o);
5003 this.loadRecords(r, {add: append}, true);
5007 * Gets the number of cached records.
5009 * <em>If using paging, this may not be the total size of the dataset. If the data object
5010 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5011 * the data set size</em>
5013 getCount : function(){
5014 return this.data.length || 0;
5018 * Gets the total number of records in the dataset as returned by the server.
5020 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5021 * the dataset size</em>
5023 getTotalCount : function(){
5024 return this.totalLength || 0;
5028 * Returns the sort state of the Store as an object with two properties:
5030 field {String} The name of the field by which the Records are sorted
5031 direction {String} The sort order, "ASC" or "DESC"
5034 getSortState : function(){
5035 return this.sortInfo;
5039 applySort : function(){
5040 if(this.sortInfo && !this.remoteSort){
5041 var s = this.sortInfo, f = s.field;
5042 var st = this.fields.get(f).sortType;
5043 var fn = function(r1, r2){
5044 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5045 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5047 this.data.sort(s.direction, fn);
5048 if(this.snapshot && this.snapshot != this.data){
5049 this.snapshot.sort(s.direction, fn);
5055 * Sets the default sort column and order to be used by the next load operation.
5056 * @param {String} fieldName The name of the field to sort by.
5057 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5059 setDefaultSort : function(field, dir){
5060 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5065 * If remote sorting is used, the sort is performed on the server, and the cache is
5066 * reloaded. If local sorting is used, the cache is sorted internally.
5067 * @param {String} fieldName The name of the field to sort by.
5068 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5070 sort : function(fieldName, dir){
5071 var f = this.fields.get(fieldName);
5073 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5074 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5079 this.sortToggle[f.name] = dir;
5080 this.sortInfo = {field: f.name, direction: dir};
5081 if(!this.remoteSort){
5083 this.fireEvent("datachanged", this);
5085 this.load(this.lastOptions);
5090 * Calls the specified function for each of the Records in the cache.
5091 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5092 * Returning <em>false</em> aborts and exits the iteration.
5093 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5095 each : function(fn, scope){
5096 this.data.each(fn, scope);
5100 * Gets all records modified since the last commit. Modified records are persisted across load operations
5101 * (e.g., during paging).
5102 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5104 getModifiedRecords : function(){
5105 return this.modified;
5109 createFilterFn : function(property, value, anyMatch){
5110 if(!value.exec){ // not a regex
5111 value = String(value);
5112 if(value.length == 0){
5115 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5118 return value.test(r.data[property]);
5123 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5124 * @param {String} property A field on your records
5125 * @param {Number} start The record index to start at (defaults to 0)
5126 * @param {Number} end The last record index to include (defaults to length - 1)
5127 * @return {Number} The sum
5129 sum : function(property, start, end){
5130 var rs = this.data.items, v = 0;
5132 end = (end || end === 0) ? end : rs.length-1;
5134 for(var i = start; i <= end; i++){
5135 v += (rs[i].data[property] || 0);
5141 * Filter the records by a specified property.
5142 * @param {String} field A field on your records
5143 * @param {String/RegExp} value Either a string that the field
5144 * should start with or a RegExp to test against the field
5145 * @param {Boolean} anyMatch True to match any part not just the beginning
5147 filter : function(property, value, anyMatch){
5148 var fn = this.createFilterFn(property, value, anyMatch);
5149 return fn ? this.filterBy(fn) : this.clearFilter();
5153 * Filter by a function. The specified function will be called with each
5154 * record in this data source. If the function returns true the record is included,
5155 * otherwise it is filtered.
5156 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5157 * @param {Object} scope (optional) The scope of the function (defaults to this)
5159 filterBy : function(fn, scope){
5160 this.snapshot = this.snapshot || this.data;
5161 this.data = this.queryBy(fn, scope||this);
5162 this.fireEvent("datachanged", this);
5166 * Query the records by a specified property.
5167 * @param {String} field A field on your records
5168 * @param {String/RegExp} value Either a string that the field
5169 * should start with or a RegExp to test against the field
5170 * @param {Boolean} anyMatch True to match any part not just the beginning
5171 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5173 query : function(property, value, anyMatch){
5174 var fn = this.createFilterFn(property, value, anyMatch);
5175 return fn ? this.queryBy(fn) : this.data.clone();
5179 * Query by a function. The specified function will be called with each
5180 * record in this data source. If the function returns true the record is included
5182 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5183 * @param {Object} scope (optional) The scope of the function (defaults to this)
5184 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5186 queryBy : function(fn, scope){
5187 var data = this.snapshot || this.data;
5188 return data.filterBy(fn, scope||this);
5192 * Collects unique values for a particular dataIndex from this store.
5193 * @param {String} dataIndex The property to collect
5194 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5195 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5196 * @return {Array} An array of the unique values
5198 collect : function(dataIndex, allowNull, bypassFilter){
5199 var d = (bypassFilter === true && this.snapshot) ?
5200 this.snapshot.items : this.data.items;
5201 var v, sv, r = [], l = {};
5202 for(var i = 0, len = d.length; i < len; i++){
5203 v = d[i].data[dataIndex];
5205 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5214 * Revert to a view of the Record cache with no filtering applied.
5215 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5217 clearFilter : function(suppressEvent){
5218 if(this.snapshot && this.snapshot != this.data){
5219 this.data = this.snapshot;
5220 delete this.snapshot;
5221 if(suppressEvent !== true){
5222 this.fireEvent("datachanged", this);
5228 afterEdit : function(record){
5229 if(this.modified.indexOf(record) == -1){
5230 this.modified.push(record);
5232 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5236 afterReject : function(record){
5237 this.modified.remove(record);
5238 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5242 afterCommit : function(record){
5243 this.modified.remove(record);
5244 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5248 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5249 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5251 commitChanges : function(){
5252 var m = this.modified.slice(0);
5254 for(var i = 0, len = m.length; i < len; i++){
5260 * Cancel outstanding changes on all changed records.
5262 rejectChanges : function(){
5263 var m = this.modified.slice(0);
5265 for(var i = 0, len = m.length; i < len; i++){
5270 onMetaChange : function(meta, rtype, o){
5271 this.recordType = rtype;
5272 this.fields = rtype.prototype.fields;
5273 delete this.snapshot;
5274 this.sortInfo = meta.sortInfo;
5276 this.fireEvent('metachange', this, this.reader.meta);
5280 * Ext JS Library 1.1.1
5281 * Copyright(c) 2006-2007, Ext JS, LLC.
5283 * Originally Released Under LGPL - original licence link has changed is not relivant.
5286 * <script type="text/javascript">
5290 * @class Roo.data.SimpleStore
5291 * @extends Roo.data.Store
5292 * Small helper class to make creating Stores from Array data easier.
5293 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5294 * @cfg {Array} fields An array of field definition objects, or field name strings.
5295 * @cfg {Array} data The multi-dimensional array of data
5297 * @param {Object} config
5299 Roo.data.SimpleStore = function(config){
5300 Roo.data.SimpleStore.superclass.constructor.call(this, {
5302 reader: new Roo.data.ArrayReader({
5305 Roo.data.Record.create(config.fields)
5307 proxy : new Roo.data.MemoryProxy(config.data)
5311 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5313 * Ext JS Library 1.1.1
5314 * Copyright(c) 2006-2007, Ext JS, LLC.
5316 * Originally Released Under LGPL - original licence link has changed is not relivant.
5319 * <script type="text/javascript">
5324 * @extends Roo.data.Store
5325 * @class Roo.data.JsonStore
5326 * Small helper class to make creating Stores for JSON data easier. <br/>
5328 var store = new Roo.data.JsonStore({
5329 url: 'get-images.php',
5331 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5334 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5335 * JsonReader and HttpProxy (unless inline data is provided).</b>
5336 * @cfg {Array} fields An array of field definition objects, or field name strings.
5338 * @param {Object} config
5340 Roo.data.JsonStore = function(c){
5341 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5342 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5343 reader: new Roo.data.JsonReader(c, c.fields)
5346 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5348 * Ext JS Library 1.1.1
5349 * Copyright(c) 2006-2007, Ext JS, LLC.
5351 * Originally Released Under LGPL - original licence link has changed is not relivant.
5354 * <script type="text/javascript">
5358 Roo.data.Field = function(config){
5359 if(typeof config == "string"){
5360 config = {name: config};
5362 Roo.apply(this, config);
5368 var st = Roo.data.SortTypes;
5369 // named sortTypes are supported, here we look them up
5370 if(typeof this.sortType == "string"){
5371 this.sortType = st[this.sortType];
5374 // set default sortType for strings and dates
5378 this.sortType = st.asUCString;
5381 this.sortType = st.asDate;
5384 this.sortType = st.none;
5389 var stripRe = /[\$,%]/g;
5391 // prebuilt conversion function for this field, instead of
5392 // switching every time we're reading a value
5394 var cv, dateFormat = this.dateFormat;
5399 cv = function(v){ return v; };
5402 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5406 return v !== undefined && v !== null && v !== '' ?
5407 parseInt(String(v).replace(stripRe, ""), 10) : '';
5412 return v !== undefined && v !== null && v !== '' ?
5413 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5418 cv = function(v){ return v === true || v === "true" || v == 1; };
5425 if(v instanceof Date){
5429 if(dateFormat == "timestamp"){
5430 return new Date(v*1000);
5432 return Date.parseDate(v, dateFormat);
5434 var parsed = Date.parse(v);
5435 return parsed ? new Date(parsed) : null;
5444 Roo.data.Field.prototype = {
5452 * Ext JS Library 1.1.1
5453 * Copyright(c) 2006-2007, Ext JS, LLC.
5455 * Originally Released Under LGPL - original licence link has changed is not relivant.
5458 * <script type="text/javascript">
5461 // Base class for reading structured data from a data source. This class is intended to be
5462 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5465 * @class Roo.data.DataReader
5466 * Base class for reading structured data from a data source. This class is intended to be
5467 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5470 Roo.data.DataReader = function(meta, recordType){
5474 this.recordType = recordType instanceof Array ?
5475 Roo.data.Record.create(recordType) : recordType;
5478 Roo.data.DataReader.prototype = {
5480 * Create an empty record
5481 * @param {Object} data (optional) - overlay some values
5482 * @return {Roo.data.Record} record created.
5484 newRow : function(d) {
5486 this.recordType.prototype.fields.each(function(c) {
5488 case 'int' : da[c.name] = 0; break;
5489 case 'date' : da[c.name] = new Date(); break;
5490 case 'float' : da[c.name] = 0.0; break;
5491 case 'boolean' : da[c.name] = false; break;
5492 default : da[c.name] = ""; break;
5496 return new this.recordType(Roo.apply(da, d));
5501 * Ext JS Library 1.1.1
5502 * Copyright(c) 2006-2007, Ext JS, LLC.
5504 * Originally Released Under LGPL - original licence link has changed is not relivant.
5507 * <script type="text/javascript">
5511 * @class Roo.data.DataProxy
5512 * @extends Roo.data.Observable
5513 * This class is an abstract base class for implementations which provide retrieval of
5514 * unformatted data objects.<br>
5516 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5517 * (of the appropriate type which knows how to parse the data object) to provide a block of
5518 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5520 * Custom implementations must implement the load method as described in
5521 * {@link Roo.data.HttpProxy#load}.
5523 Roo.data.DataProxy = function(){
5527 * Fires before a network request is made to retrieve a data object.
5528 * @param {Object} This DataProxy object.
5529 * @param {Object} params The params parameter to the load function.
5534 * Fires before the load method's callback is called.
5535 * @param {Object} This DataProxy object.
5536 * @param {Object} o The data object.
5537 * @param {Object} arg The callback argument object passed to the load function.
5541 * @event loadexception
5542 * Fires if an Exception occurs during data retrieval.
5543 * @param {Object} This DataProxy object.
5544 * @param {Object} o The data object.
5545 * @param {Object} arg The callback argument object passed to the load function.
5546 * @param {Object} e The Exception.
5548 loadexception : true
5550 Roo.data.DataProxy.superclass.constructor.call(this);
5553 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5556 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5560 * Ext JS Library 1.1.1
5561 * Copyright(c) 2006-2007, Ext JS, LLC.
5563 * Originally Released Under LGPL - original licence link has changed is not relivant.
5566 * <script type="text/javascript">
5569 * @class Roo.data.MemoryProxy
5570 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5571 * to the Reader when its load method is called.
5573 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5575 Roo.data.MemoryProxy = function(data){
5579 Roo.data.MemoryProxy.superclass.constructor.call(this);
5583 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5585 * Load data from the requested source (in this case an in-memory
5586 * data object passed to the constructor), read the data object into
5587 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5588 * process that block using the passed callback.
5589 * @param {Object} params This parameter is not used by the MemoryProxy class.
5590 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5591 * object into a block of Roo.data.Records.
5592 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5593 * The function must be passed <ul>
5594 * <li>The Record block object</li>
5595 * <li>The "arg" argument from the load function</li>
5596 * <li>A boolean success indicator</li>
5598 * @param {Object} scope The scope in which to call the callback
5599 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5601 load : function(params, reader, callback, scope, arg){
5602 params = params || {};
5605 result = reader.readRecords(this.data);
5607 this.fireEvent("loadexception", this, arg, null, e);
5608 callback.call(scope, null, arg, false);
5611 callback.call(scope, result, arg, true);
5615 update : function(params, records){
5620 * Ext JS Library 1.1.1
5621 * Copyright(c) 2006-2007, Ext JS, LLC.
5623 * Originally Released Under LGPL - original licence link has changed is not relivant.
5626 * <script type="text/javascript">
5629 * @class Roo.data.HttpProxy
5630 * @extends Roo.data.DataProxy
5631 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5632 * configured to reference a certain URL.<br><br>
5634 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5635 * from which the running page was served.<br><br>
5637 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5639 * Be aware that to enable the browser to parse an XML document, the server must set
5640 * the Content-Type header in the HTTP response to "text/xml".
5642 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5643 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5644 * will be used to make the request.
5646 Roo.data.HttpProxy = function(conn){
5647 Roo.data.HttpProxy.superclass.constructor.call(this);
5648 // is conn a conn config or a real conn?
5650 this.useAjax = !conn || !conn.events;
5654 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5655 // thse are take from connection...
5658 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5661 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5662 * extra parameters to each request made by this object. (defaults to undefined)
5665 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5666 * to each request made by this object. (defaults to undefined)
5669 * @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)
5672 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5675 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5681 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5685 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5686 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5687 * a finer-grained basis than the DataProxy events.
5689 getConnection : function(){
5690 return this.useAjax ? Roo.Ajax : this.conn;
5694 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5695 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5696 * process that block using the passed callback.
5697 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5698 * for the request to the remote server.
5699 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5700 * object into a block of Roo.data.Records.
5701 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5702 * The function must be passed <ul>
5703 * <li>The Record block object</li>
5704 * <li>The "arg" argument from the load function</li>
5705 * <li>A boolean success indicator</li>
5707 * @param {Object} scope The scope in which to call the callback
5708 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5710 load : function(params, reader, callback, scope, arg){
5711 if(this.fireEvent("beforeload", this, params) !== false){
5713 params : params || {},
5715 callback : callback,
5720 callback : this.loadResponse,
5724 Roo.applyIf(o, this.conn);
5725 if(this.activeRequest){
5726 Roo.Ajax.abort(this.activeRequest);
5728 this.activeRequest = Roo.Ajax.request(o);
5730 this.conn.request(o);
5733 callback.call(scope||this, null, arg, false);
5738 loadResponse : function(o, success, response){
5739 delete this.activeRequest;
5741 this.fireEvent("loadexception", this, o, response);
5742 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5747 result = o.reader.read(response);
5749 this.fireEvent("loadexception", this, o, response, e);
5750 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5754 this.fireEvent("load", this, o, o.request.arg);
5755 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5759 update : function(dataSet){
5764 updateResponse : function(dataSet){
5769 * Ext JS Library 1.1.1
5770 * Copyright(c) 2006-2007, Ext JS, LLC.
5772 * Originally Released Under LGPL - original licence link has changed is not relivant.
5775 * <script type="text/javascript">
5779 * @class Roo.data.ScriptTagProxy
5780 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5781 * other than the originating domain of the running page.<br><br>
5783 * <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
5784 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5786 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5787 * source code that is used as the source inside a <script> tag.<br><br>
5789 * In order for the browser to process the returned data, the server must wrap the data object
5790 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5791 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5792 * depending on whether the callback name was passed:
5795 boolean scriptTag = false;
5796 String cb = request.getParameter("callback");
5799 response.setContentType("text/javascript");
5801 response.setContentType("application/x-json");
5803 Writer out = response.getWriter();
5805 out.write(cb + "(");
5807 out.print(dataBlock.toJsonString());
5814 * @param {Object} config A configuration object.
5816 Roo.data.ScriptTagProxy = function(config){
5817 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5818 Roo.apply(this, config);
5819 this.head = document.getElementsByTagName("head")[0];
5822 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5824 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5826 * @cfg {String} url The URL from which to request the data object.
5829 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5833 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5834 * the server the name of the callback function set up by the load call to process the returned data object.
5835 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5836 * javascript output which calls this named function passing the data object as its only parameter.
5838 callbackParam : "callback",
5840 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5841 * name to the request.
5846 * Load data from the configured URL, read the data object into
5847 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5848 * process that block using the passed callback.
5849 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5850 * for the request to the remote server.
5851 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5852 * object into a block of Roo.data.Records.
5853 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5854 * The function must be passed <ul>
5855 * <li>The Record block object</li>
5856 * <li>The "arg" argument from the load function</li>
5857 * <li>A boolean success indicator</li>
5859 * @param {Object} scope The scope in which to call the callback
5860 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5862 load : function(params, reader, callback, scope, arg){
5863 if(this.fireEvent("beforeload", this, params) !== false){
5865 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5868 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5870 url += "&_dc=" + (new Date().getTime());
5872 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5875 cb : "stcCallback"+transId,
5876 scriptId : "stcScript"+transId,
5880 callback : callback,
5886 window[trans.cb] = function(o){
5887 conn.handleResponse(o, trans);
5890 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5892 if(this.autoAbort !== false){
5896 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5898 var script = document.createElement("script");
5899 script.setAttribute("src", url);
5900 script.setAttribute("type", "text/javascript");
5901 script.setAttribute("id", trans.scriptId);
5902 this.head.appendChild(script);
5906 callback.call(scope||this, null, arg, false);
5911 isLoading : function(){
5912 return this.trans ? true : false;
5916 * Abort the current server request.
5919 if(this.isLoading()){
5920 this.destroyTrans(this.trans);
5925 destroyTrans : function(trans, isLoaded){
5926 this.head.removeChild(document.getElementById(trans.scriptId));
5927 clearTimeout(trans.timeoutId);
5929 window[trans.cb] = undefined;
5931 delete window[trans.cb];
5934 // if hasn't been loaded, wait for load to remove it to prevent script error
5935 window[trans.cb] = function(){
5936 window[trans.cb] = undefined;
5938 delete window[trans.cb];
5945 handleResponse : function(o, trans){
5947 this.destroyTrans(trans, true);
5950 result = trans.reader.readRecords(o);
5952 this.fireEvent("loadexception", this, o, trans.arg, e);
5953 trans.callback.call(trans.scope||window, null, trans.arg, false);
5956 this.fireEvent("load", this, o, trans.arg);
5957 trans.callback.call(trans.scope||window, result, trans.arg, true);
5961 handleFailure : function(trans){
5963 this.destroyTrans(trans, false);
5964 this.fireEvent("loadexception", this, null, trans.arg);
5965 trans.callback.call(trans.scope||window, null, trans.arg, false);
5969 * Ext JS Library 1.1.1
5970 * Copyright(c) 2006-2007, Ext JS, LLC.
5972 * Originally Released Under LGPL - original licence link has changed is not relivant.
5975 * <script type="text/javascript">
5979 * @class Roo.data.JsonReader
5980 * @extends Roo.data.DataReader
5981 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5982 * based on mappings in a provided Roo.data.Record constructor.
5986 var RecordDef = Roo.data.Record.create([
5987 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5988 {name: 'occupation'} // This field will use "occupation" as the mapping.
5990 var myReader = new Roo.data.JsonReader({
5991 totalProperty: "results", // The property which contains the total dataset size (optional)
5992 root: "rows", // The property which contains an Array of row objects
5993 id: "id" // The property within each row object that provides an ID for the record (optional)
5997 * This would consume a JSON file like this:
5999 { 'results': 2, 'rows': [
6000 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6001 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6004 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6005 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6006 * paged from the remote server.
6007 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6008 * @cfg {String} root name of the property which contains the Array of row objects.
6009 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6011 * Create a new JsonReader
6012 * @param {Object} meta Metadata configuration options
6013 * @param {Object} recordType Either an Array of field definition objects,
6014 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6016 Roo.data.JsonReader = function(meta, recordType){
6019 // set some defaults:
6021 totalProperty: 'total',
6022 successProperty : 'success',
6027 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6029 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6031 * This method is only used by a DataProxy which has retrieved data from a remote server.
6032 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6033 * @return {Object} data A data block which is used by an Roo.data.Store object as
6034 * a cache of Roo.data.Records.
6036 read : function(response){
6037 var json = response.responseText;
6039 var o = eval("("+json+")");
6041 throw {message: "JsonReader.read: Json object not found"};
6046 this.meta = o.metaData;
6047 this.recordType = Roo.data.Record.create(o.metaData.fields);
6048 this.onMetaChange(this.meta, this.recordType, o);
6050 return this.readRecords(o);
6053 // private function a store will implement
6054 onMetaChange : function(meta, recordType, o){
6061 simpleAccess: function(obj, subsc) {
6068 getJsonAccessor: function(){
6070 return function(expr) {
6072 return(re.test(expr))
6073 ? new Function("obj", "return obj." + expr)
6083 * Create a data block containing Roo.data.Records from an XML document.
6084 * @param {Object} o An object which contains an Array of row objects in the property specified
6085 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6086 * which contains the total size of the dataset.
6087 * @return {Object} data A data block which is used by an Roo.data.Store object as
6088 * a cache of Roo.data.Records.
6090 readRecords : function(o){
6092 * After any data loads, the raw JSON data is available for further custom processing.
6096 var s = this.meta, Record = this.recordType,
6097 f = Record.prototype.fields, fi = f.items, fl = f.length;
6099 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6101 if(s.totalProperty) {
6102 this.getTotal = this.getJsonAccessor(s.totalProperty);
6104 if(s.successProperty) {
6105 this.getSuccess = this.getJsonAccessor(s.successProperty);
6107 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6109 var g = this.getJsonAccessor(s.id);
6110 this.getId = function(rec) {
6112 return (r === undefined || r === "") ? null : r;
6115 this.getId = function(){return null;};
6118 for(var i = 0; i < fl; i++){
6120 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6121 this.ef[i] = this.getJsonAccessor(map);
6125 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6126 if(s.totalProperty){
6127 var v = parseInt(this.getTotal(o), 10);
6132 if(s.successProperty){
6133 var v = this.getSuccess(o);
6134 if(v === false || v === 'false'){
6139 for(var i = 0; i < c; i++){
6142 var id = this.getId(n);
6143 for(var j = 0; j < fl; j++){
6145 var v = this.ef[j](n);
6146 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6148 var record = new Record(values, id);
6150 records[i] = record;
6155 totalRecords : totalRecords
6160 * Ext JS Library 1.1.1
6161 * Copyright(c) 2006-2007, Ext JS, LLC.
6163 * Originally Released Under LGPL - original licence link has changed is not relivant.
6166 * <script type="text/javascript">
6170 * @class Roo.data.XmlReader
6171 * @extends Roo.data.DataReader
6172 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6173 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6175 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6176 * header in the HTTP response must be set to "text/xml".</em>
6180 var RecordDef = Roo.data.Record.create([
6181 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6182 {name: 'occupation'} // This field will use "occupation" as the mapping.
6184 var myReader = new Roo.data.XmlReader({
6185 totalRecords: "results", // The element which contains the total dataset size (optional)
6186 record: "row", // The repeated element which contains row information
6187 id: "id" // The element within the row that provides an ID for the record (optional)
6191 * This would consume an XML file like this:
6195 <results>2</results>
6198 <name>Bill</name>
6199 <occupation>Gardener</occupation>
6203 <name>Ben</name>
6204 <occupation>Horticulturalist</occupation>
6208 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6209 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6210 * paged from the remote server.
6211 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6212 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6213 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6214 * a record identifier value.
6216 * Create a new XmlReader
6217 * @param {Object} meta Metadata configuration options
6218 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6219 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6220 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6222 Roo.data.XmlReader = function(meta, recordType){
6224 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6226 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6228 * This method is only used by a DataProxy which has retrieved data from a remote server.
6229 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6230 * to contain a method called 'responseXML' that returns an XML document object.
6231 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6232 * a cache of Roo.data.Records.
6234 read : function(response){
6235 var doc = response.responseXML;
6237 throw {message: "XmlReader.read: XML Document not available"};
6239 return this.readRecords(doc);
6243 * Create a data block containing Roo.data.Records from an XML document.
6244 * @param {Object} doc A parsed XML document.
6245 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6246 * a cache of Roo.data.Records.
6248 readRecords : function(doc){
6250 * After any data loads/reads, the raw XML Document is available for further custom processing.
6254 var root = doc.documentElement || doc;
6255 var q = Roo.DomQuery;
6256 var recordType = this.recordType, fields = recordType.prototype.fields;
6257 var sid = this.meta.id;
6258 var totalRecords = 0, success = true;
6259 if(this.meta.totalRecords){
6260 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6263 if(this.meta.success){
6264 var sv = q.selectValue(this.meta.success, root, true);
6265 success = sv !== false && sv !== 'false';
6268 var ns = q.select(this.meta.record, root);
6269 for(var i = 0, len = ns.length; i < len; i++) {
6272 var id = sid ? q.selectValue(sid, n) : undefined;
6273 for(var j = 0, jlen = fields.length; j < jlen; j++){
6274 var f = fields.items[j];
6275 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6279 var record = new recordType(values, id);
6281 records[records.length] = record;
6287 totalRecords : totalRecords || records.length