-});/**\r
- * @class Ext.dd.DragTracker\r
- * @extends Ext.util.Observable\r
- */\r
-Ext.dd.DragTracker = Ext.extend(Ext.util.Observable, {\r
- /**\r
- * @cfg {Boolean} active\r
- * Defaults to <tt>false</tt>.\r
- */ \r
- active: false,\r
- /**\r
- * @cfg {Number} tolerance\r
- * Defaults to <tt>5</tt>.\r
- */ \r
- tolerance: 5,\r
- /**\r
- * @cfg {Boolean/Number} autoStart\r
- * Defaults to <tt>false</tt>. Specify <tt>true</tt> to defer trigger start by 1000 ms.\r
- * Specify a Number for the number of milliseconds to defer trigger start.\r
- */ \r
- autoStart: false,\r
- \r
- constructor : function(config){\r
- Ext.apply(this, config);\r
- this.addEvents(\r
- /**\r
- * @event mousedown\r
- * @param {Object} this\r
- * @param {Object} e event object\r
- */\r
- 'mousedown',\r
- /**\r
- * @event mouseup\r
- * @param {Object} this\r
- * @param {Object} e event object\r
- */\r
- 'mouseup',\r
- /**\r
- * @event mousemove\r
- * @param {Object} this\r
- * @param {Object} e event object\r
- */\r
- 'mousemove',\r
- /**\r
- * @event dragstart\r
- * @param {Object} this\r
- * @param {Object} startXY the page coordinates of the event\r
- */\r
- 'dragstart',\r
- /**\r
- * @event dragend\r
- * @param {Object} this\r
- * @param {Object} e event object\r
- */\r
- 'dragend',\r
- /**\r
- * @event drag\r
- * @param {Object} this\r
- * @param {Object} e event object\r
- */\r
- 'drag'\r
- );\r
- \r
- this.dragRegion = new Ext.lib.Region(0,0,0,0);\r
- \r
- if(this.el){\r
- this.initEl(this.el);\r
- }\r
- Ext.dd.DragTracker.superclass.constructor.call(this, config);\r
- },\r
-\r
- initEl: function(el){\r
- this.el = Ext.get(el);\r
- el.on('mousedown', this.onMouseDown, this,\r
- this.delegate ? {delegate: this.delegate} : undefined);\r
- },\r
-\r
- destroy : function(){\r
- this.el.un('mousedown', this.onMouseDown, this);\r
- },\r
-\r
- onMouseDown: function(e, target){\r
- if(this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false){\r
- this.startXY = this.lastXY = e.getXY();\r
- this.dragTarget = this.delegate ? target : this.el.dom;\r
- if(this.preventDefault !== false){\r
- e.preventDefault();\r
- }\r
- var doc = Ext.getDoc();\r
- doc.on('mouseup', this.onMouseUp, this);\r
- doc.on('mousemove', this.onMouseMove, this);\r
- doc.on('selectstart', this.stopSelect, this);\r
- if(this.autoStart){\r
- this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this);\r
- }\r
- }\r
- },\r
-\r
- onMouseMove: function(e, target){\r
- // HACK: IE hack to see if button was released outside of window. */\r
- if(this.active && Ext.isIE && !e.browserEvent.button){\r
- e.preventDefault();\r
- this.onMouseUp(e);\r
- return;\r
- }\r
-\r
- e.preventDefault();\r
- var xy = e.getXY(), s = this.startXY;\r
- this.lastXY = xy;\r
- if(!this.active){\r
- if(Math.abs(s[0]-xy[0]) > this.tolerance || Math.abs(s[1]-xy[1]) > this.tolerance){\r
- this.triggerStart();\r
- }else{\r
- return;\r
- }\r
- }\r
- this.fireEvent('mousemove', this, e);\r
- this.onDrag(e);\r
- this.fireEvent('drag', this, e);\r
- },\r
-\r
- onMouseUp: function(e){\r
- var doc = Ext.getDoc();\r
- doc.un('mousemove', this.onMouseMove, this);\r
- doc.un('mouseup', this.onMouseUp, this);\r
- doc.un('selectstart', this.stopSelect, this);\r
- e.preventDefault();\r
- this.clearStart();\r
- var wasActive = this.active;\r
- this.active = false;\r
- delete this.elRegion;\r
- this.fireEvent('mouseup', this, e);\r
- if(wasActive){\r
- this.onEnd(e);\r
- this.fireEvent('dragend', this, e);\r
- }\r
- },\r
-\r
- triggerStart: function(isTimer){\r
- this.clearStart();\r
- this.active = true;\r
- this.onStart(this.startXY);\r
- this.fireEvent('dragstart', this, this.startXY);\r
- },\r
-\r
- clearStart : function(){\r
- if(this.timer){\r
- clearTimeout(this.timer);\r
- delete this.timer;\r
- }\r
- },\r
-\r
- stopSelect : function(e){\r
- e.stopEvent();\r
- return false;\r
- },\r
-\r
- onBeforeStart : function(e){\r
-\r
- },\r
-\r
- onStart : function(xy){\r
-\r
- },\r
-\r
- onDrag : function(e){\r
-\r
- },\r
-\r
- onEnd : function(e){\r
-\r
- },\r
-\r
- getDragTarget : function(){\r
- return this.dragTarget;\r
- },\r
-\r
- getDragCt : function(){\r
- return this.el;\r
- },\r
-\r
- getXY : function(constrain){\r
- return constrain ?\r
- this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY;\r
- },\r
-\r
- getOffset : function(constrain){\r
- var xy = this.getXY(constrain);\r
- var s = this.startXY;\r
- return [s[0]-xy[0], s[1]-xy[1]];\r
- },\r
-\r
- constrainModes: {\r
- 'point' : function(xy){\r
-\r
- if(!this.elRegion){\r
- this.elRegion = this.getDragCt().getRegion();\r
- }\r
-\r
- var dr = this.dragRegion;\r
-\r
- dr.left = xy[0];\r
- dr.top = xy[1];\r
- dr.right = xy[0];\r
- dr.bottom = xy[1];\r
-\r
- dr.constrainTo(this.elRegion);\r
-\r
- return [dr.left, dr.top];\r
- }\r
- }\r
-});/**\r
- * @class Ext.dd.ScrollManager\r
- * <p>Provides automatic scrolling of overflow regions in the page during drag operations.</p>\r
- * <p>The ScrollManager configs will be used as the defaults for any scroll container registered with it,\r
- * but you can also override most of the configs per scroll container by adding a \r
- * <tt>ddScrollConfig</tt> object to the target element that contains these properties: {@link #hthresh},\r
- * {@link #vthresh}, {@link #increment} and {@link #frequency}. Example usage:\r
- * <pre><code>\r
-var el = Ext.get('scroll-ct');\r
-el.ddScrollConfig = {\r
- vthresh: 50,\r
- hthresh: -1,\r
- frequency: 100,\r
- increment: 200\r
-};\r
-Ext.dd.ScrollManager.register(el);\r
-</code></pre>\r
- * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>\r
- * @singleton\r
- */\r
-Ext.dd.ScrollManager = function(){\r
- var ddm = Ext.dd.DragDropMgr;\r
- var els = {};\r
- var dragEl = null;\r
- var proc = {};\r
- \r
- var onStop = function(e){\r
- dragEl = null;\r
- clearProc();\r
- };\r
- \r
- var triggerRefresh = function(){\r
- if(ddm.dragCurrent){\r
- ddm.refreshCache(ddm.dragCurrent.groups);\r
- }\r
- };\r
- \r
- var doScroll = function(){\r
- if(ddm.dragCurrent){\r
- var dds = Ext.dd.ScrollManager;\r
- var inc = proc.el.ddScrollConfig ?\r
- proc.el.ddScrollConfig.increment : dds.increment;\r
- if(!dds.animate){\r
- if(proc.el.scroll(proc.dir, inc)){\r
- triggerRefresh();\r
- }\r
- }else{\r
- proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);\r
- }\r
- }\r
- };\r
- \r
- var clearProc = function(){\r
- if(proc.id){\r
- clearInterval(proc.id);\r
- }\r
- proc.id = 0;\r
- proc.el = null;\r
- proc.dir = "";\r
- };\r
- \r
- var startProc = function(el, dir){\r
- clearProc();\r
- proc.el = el;\r
- proc.dir = dir;\r
- var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ? \r
- el.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;\r
- proc.id = setInterval(doScroll, freq);\r
- };\r
- \r
- var onFire = function(e, isDrop){\r
- if(isDrop || !ddm.dragCurrent){ return; }\r
- var dds = Ext.dd.ScrollManager;\r
- if(!dragEl || dragEl != ddm.dragCurrent){\r
- dragEl = ddm.dragCurrent;\r
- // refresh regions on drag start\r
- dds.refreshCache();\r
- }\r
- \r
- var xy = Ext.lib.Event.getXY(e);\r
- var pt = new Ext.lib.Point(xy[0], xy[1]);\r
- for(var id in els){\r
- var el = els[id], r = el._region;\r
- var c = el.ddScrollConfig ? el.ddScrollConfig : dds;\r
- if(r && r.contains(pt) && el.isScrollable()){\r
- if(r.bottom - pt.y <= c.vthresh){\r
- if(proc.el != el){\r
- startProc(el, "down");\r
- }\r
- return;\r
- }else if(r.right - pt.x <= c.hthresh){\r
- if(proc.el != el){\r
- startProc(el, "left");\r
- }\r
- return;\r
- }else if(pt.y - r.top <= c.vthresh){\r
- if(proc.el != el){\r
- startProc(el, "up");\r
- }\r
- return;\r
- }else if(pt.x - r.left <= c.hthresh){\r
- if(proc.el != el){\r
- startProc(el, "right");\r
- }\r
- return;\r
- }\r
- }\r
- }\r
- clearProc();\r
- };\r
- \r
- ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);\r
- ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);\r
- \r
- return {\r
- /**\r
- * Registers new overflow element(s) to auto scroll\r
- * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either\r
- */\r
- register : function(el){\r
- if(Ext.isArray(el)){\r
- for(var i = 0, len = el.length; i < len; i++) {\r
- this.register(el[i]);\r
- }\r
- }else{\r
- el = Ext.get(el);\r
- els[el.id] = el;\r
- }\r
- },\r
- \r
- /**\r
- * Unregisters overflow element(s) so they are no longer scrolled\r
- * @param {Mixed/Array} el The id of or the element to be removed or an array of either\r
- */\r
- unregister : function(el){\r
- if(Ext.isArray(el)){\r
- for(var i = 0, len = el.length; i < len; i++) {\r
- this.unregister(el[i]);\r
- }\r
- }else{\r
- el = Ext.get(el);\r
- delete els[el.id];\r
- }\r
- },\r
- \r
- /**\r
- * The number of pixels from the top or bottom edge of a container the pointer needs to be to\r
- * trigger scrolling (defaults to 25)\r
- * @type Number\r
- */\r
- vthresh : 25,\r
- /**\r
- * The number of pixels from the right or left edge of a container the pointer needs to be to\r
- * trigger scrolling (defaults to 25)\r
- * @type Number\r
- */\r
- hthresh : 25,\r
-\r
- /**\r
- * The number of pixels to scroll in each scroll increment (defaults to 50)\r
- * @type Number\r
- */\r
- increment : 100,\r
- \r
- /**\r
- * The frequency of scrolls in milliseconds (defaults to 500)\r
- * @type Number\r
- */\r
- frequency : 500,\r
- \r
- /**\r
- * True to animate the scroll (defaults to true)\r
- * @type Boolean\r
- */\r
- animate: true,\r
- \r
- /**\r
- * The animation duration in seconds - \r
- * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)\r
- * @type Number\r
- */\r
- animDuration: .4,\r
- \r
- /**\r
- * Manually trigger a cache refresh.\r
- */\r
- refreshCache : function(){\r
- for(var id in els){\r
- if(typeof els[id] == 'object'){ // for people extending the object prototype\r
- els[id]._region = els[id].getRegion();\r
- }\r
- }\r
- }\r
- };\r
-}();/**\r
- * @class Ext.dd.Registry\r
- * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either\r
- * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.\r
- * @singleton\r
- */\r
-Ext.dd.Registry = function(){\r
- var elements = {}; \r
- var handles = {}; \r
- var autoIdSeed = 0;\r
-\r
- var getId = function(el, autogen){\r
- if(typeof el == "string"){\r
- return el;\r
- }\r
- var id = el.id;\r
- if(!id && autogen !== false){\r
- id = "extdd-" + (++autoIdSeed);\r
- el.id = id;\r
- }\r
- return id;\r
- };\r
- \r
- return {\r
- /**\r
- * Resgister a drag drop element\r
- * @param {String/HTMLElement) element The id or DOM node to register\r
- * @param {Object} data (optional) An custom data object that will be passed between the elements that are involved\r
- * in drag drop operations. You can populate this object with any arbitrary properties that your own code\r
- * knows how to interpret, plus there are some specific properties known to the Registry that should be\r
- * populated in the data object (if applicable):\r
- * <pre>\r
-Value Description<br />\r
---------- ------------------------------------------<br />\r
-handles Array of DOM nodes that trigger dragging<br />\r
- for the element being registered<br />\r
-isHandle True if the element passed in triggers<br />\r
- dragging itself, else false\r
-</pre>\r
- */\r
- register : function(el, data){\r
- data = data || {};\r
- if(typeof el == "string"){\r
- el = document.getElementById(el);\r
- }\r
- data.ddel = el;\r
- elements[getId(el)] = data;\r
- if(data.isHandle !== false){\r
- handles[data.ddel.id] = data;\r
- }\r
- if(data.handles){\r
- var hs = data.handles;\r
- for(var i = 0, len = hs.length; i < len; i++){\r
- handles[getId(hs[i])] = data;\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * Unregister a drag drop element\r
- * @param {String/HTMLElement) element The id or DOM node to unregister\r
- */\r
- unregister : function(el){\r
- var id = getId(el, false);\r
- var data = elements[id];\r
- if(data){\r
- delete elements[id];\r
- if(data.handles){\r
- var hs = data.handles;\r
- for(var i = 0, len = hs.length; i < len; i++){\r
- delete handles[getId(hs[i], false)];\r
- }\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * Returns the handle registered for a DOM Node by id\r
- * @param {String/HTMLElement} id The DOM node or id to look up\r
- * @return {Object} handle The custom handle data\r
- */\r
- getHandle : function(id){\r
- if(typeof id != "string"){ // must be element?\r
- id = id.id;\r
- }\r
- return handles[id];\r
- },\r
-\r
- /**\r
- * Returns the handle that is registered for the DOM node that is the target of the event\r
- * @param {Event} e The event\r
- * @return {Object} handle The custom handle data\r
- */\r
- getHandleFromEvent : function(e){\r
- var t = Ext.lib.Event.getTarget(e);\r
- return t ? handles[t.id] : null;\r
- },\r
-\r
- /**\r
- * Returns a custom data object that is registered for a DOM node by id\r
- * @param {String/HTMLElement} id The DOM node or id to look up\r
- * @return {Object} data The custom data\r
- */\r
- getTarget : function(id){\r
- if(typeof id != "string"){ // must be element?\r
- id = id.id;\r
- }\r
- return elements[id];\r
- },\r
-\r
- /**\r
- * Returns a custom data object that is registered for the DOM node that is the target of the event\r
- * @param {Event} e The event\r
- * @return {Object} data The custom data\r
- */\r
- getTargetFromEvent : function(e){\r
- var t = Ext.lib.Event.getTarget(e);\r
- return t ? elements[t.id] || handles[t.id] : null;\r
- }\r
- };\r
-}();/**\r
- * @class Ext.dd.StatusProxy\r
- * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair. This is the\r
- * default drag proxy used by all Ext.dd components.\r
- * @constructor\r
- * @param {Object} config\r
- */\r
-Ext.dd.StatusProxy = function(config){\r
- Ext.apply(this, config);\r
- this.id = this.id || Ext.id();\r
- this.el = new Ext.Layer({\r
- dh: {\r
- id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [\r
- {tag: "div", cls: "x-dd-drop-icon"},\r
- {tag: "div", cls: "x-dd-drag-ghost"}\r
- ]\r
- }, \r
- shadow: !config || config.shadow !== false\r
- });\r
- this.ghost = Ext.get(this.el.dom.childNodes[1]);\r
- this.dropStatus = this.dropNotAllowed;\r
-};\r
-\r
-Ext.dd.StatusProxy.prototype = {\r
- /**\r
- * @cfg {String} dropAllowed\r
- * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").\r
- */\r
- dropAllowed : "x-dd-drop-ok",\r
- /**\r
- * @cfg {String} dropNotAllowed\r
- * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
- */\r
- dropNotAllowed : "x-dd-drop-nodrop",\r
-\r
- /**\r
- * Updates the proxy's visual element to indicate the status of whether or not drop is allowed\r
- * over the current target element.\r
- * @param {String} cssClass The css class for the new drop status indicator image\r
- */\r
- setStatus : function(cssClass){\r
- cssClass = cssClass || this.dropNotAllowed;\r
- if(this.dropStatus != cssClass){\r
- this.el.replaceClass(this.dropStatus, cssClass);\r
- this.dropStatus = cssClass;\r
- }\r
- },\r
-\r
- /**\r
- * Resets the status indicator to the default dropNotAllowed value\r
- * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it\r
- */\r
- reset : function(clearGhost){\r
- this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;\r
- this.dropStatus = this.dropNotAllowed;\r
- if(clearGhost){\r
- this.ghost.update("");\r
- }\r
- },\r
-\r
- /**\r
- * Updates the contents of the ghost element\r
- * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a\r
- * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).\r
- */\r
- update : function(html){\r
- if(typeof html == "string"){\r
- this.ghost.update(html);\r
- }else{\r
- this.ghost.update("");\r
- html.style.margin = "0";\r
- this.ghost.dom.appendChild(html);\r
- }\r
- var el = this.ghost.dom.firstChild; \r
- if(el){\r
- Ext.fly(el).setStyle('float', 'none');\r
- }\r
- },\r
-\r
- /**\r
- * Returns the underlying proxy {@link Ext.Layer}\r
- * @return {Ext.Layer} el\r
- */\r
- getEl : function(){\r
- return this.el;\r
- },\r
-\r
- /**\r
- * Returns the ghost element\r
- * @return {Ext.Element} el\r
- */\r
- getGhost : function(){\r
- return this.ghost;\r
- },\r
-\r
- /**\r
- * Hides the proxy\r
- * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them\r
- */\r
- hide : function(clear){\r
- this.el.hide();\r
- if(clear){\r
- this.reset(true);\r
- }\r
- },\r
-\r
- /**\r
- * Stops the repair animation if it's currently running\r
- */\r
- stop : function(){\r
- if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){\r
- this.anim.stop();\r
- }\r
- },\r
-\r
- /**\r
- * Displays this proxy\r
- */\r
- show : function(){\r
- this.el.show();\r
- },\r
-\r
- /**\r
- * Force the Layer to sync its shadow and shim positions to the element\r
- */\r
- sync : function(){\r
- this.el.sync();\r
- },\r
-\r
- /**\r
- * Causes the proxy to return to its position of origin via an animation. Should be called after an\r
- * invalid drop operation by the item being dragged.\r
- * @param {Array} xy The XY position of the element ([x, y])\r
- * @param {Function} callback The function to call after the repair is complete.\r
- * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.\r
- */\r
- repair : function(xy, callback, scope){\r
- this.callback = callback;\r
- this.scope = scope;\r
- if(xy && this.animRepair !== false){\r
- this.el.addClass("x-dd-drag-repair");\r
- this.el.hideUnders(true);\r
- this.anim = this.el.shift({\r
- duration: this.repairDuration || .5,\r
- easing: 'easeOut',\r
- xy: xy,\r
- stopFx: true,\r
- callback: this.afterRepair,\r
- scope: this\r
- });\r
- }else{\r
- this.afterRepair();\r
- }\r
- },\r
-\r
- // private\r
- afterRepair : function(){\r
- this.hide(true);\r
- if(typeof this.callback == "function"){\r
- this.callback.call(this.scope || this);\r
- }\r
- this.callback = null;\r
- this.scope = null;\r
- },\r
- \r
- destroy: function(){\r
- Ext.destroy(this.ghost, this.el); \r
- }\r
-};/**\r
- * @class Ext.dd.DragSource\r
- * @extends Ext.dd.DDProxy\r
- * A simple class that provides the basic implementation needed to make any element draggable.\r
- * @constructor\r
- * @param {Mixed} el The container element\r
- * @param {Object} config\r
- */\r
-Ext.dd.DragSource = function(el, config){\r
- this.el = Ext.get(el);\r
- if(!this.dragData){\r
- this.dragData = {};\r
- }\r
- \r
- Ext.apply(this, config);\r
- \r
- if(!this.proxy){\r
- this.proxy = new Ext.dd.StatusProxy();\r
- }\r
- Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, \r
- {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});\r
- \r
- this.dragging = false;\r
-};\r
-\r
-Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {\r
- /**\r
- * @cfg {String} ddGroup\r
- * A named drag drop group to which this object belongs. If a group is specified, then this object will only\r
- * interact with other drag drop objects in the same group (defaults to undefined).\r
- */\r
- /**\r
- * @cfg {String} dropAllowed\r
- * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").\r
- */\r
- dropAllowed : "x-dd-drop-ok",\r
- /**\r
- * @cfg {String} dropNotAllowed\r
- * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
- */\r
- dropNotAllowed : "x-dd-drop-nodrop",\r
-\r
- /**\r
- * Returns the data object associated with this drag source\r
- * @return {Object} data An object containing arbitrary data\r
- */\r
- getDragData : function(e){\r
- return this.dragData;\r
- },\r
-\r
- // private\r
- onDragEnter : function(e, id){\r
- var target = Ext.dd.DragDropMgr.getDDById(id);\r
- this.cachedTarget = target;\r
- if(this.beforeDragEnter(target, e, id) !== false){\r
- if(target.isNotifyTarget){\r
- var status = target.notifyEnter(this, e, this.dragData);\r
- this.proxy.setStatus(status);\r
- }else{\r
- this.proxy.setStatus(this.dropAllowed);\r
- }\r
- \r
- if(this.afterDragEnter){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * when the dragged item enters the drop target by providing an implementation.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @method afterDragEnter\r
- */\r
- this.afterDragEnter(target, e, id);\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * before the dragged item enters the drop target and optionally cancel the onDragEnter.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
- */\r
- beforeDragEnter : function(target, e, id){\r
- return true;\r
- },\r
-\r
- // private\r
- alignElWithMouse: function() {\r
- Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);\r
- this.proxy.sync();\r
- },\r
-\r
- // private\r
- onDragOver : function(e, id){\r
- var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
- if(this.beforeDragOver(target, e, id) !== false){\r
- if(target.isNotifyTarget){\r
- var status = target.notifyOver(this, e, this.dragData);\r
- this.proxy.setStatus(status);\r
- }\r
-\r
- if(this.afterDragOver){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * while the dragged item is over the drop target by providing an implementation.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @method afterDragOver\r
- */\r
- this.afterDragOver(target, e, id);\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * while the dragged item is over the drop target and optionally cancel the onDragOver.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
- */\r
- beforeDragOver : function(target, e, id){\r
- return true;\r
- },\r
-\r
- // private\r
- onDragOut : function(e, id){\r
- var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
- if(this.beforeDragOut(target, e, id) !== false){\r
- if(target.isNotifyTarget){\r
- target.notifyOut(this, e, this.dragData);\r
- }\r
- this.proxy.reset();\r
- if(this.afterDragOut){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * after the dragged item is dragged out of the target without dropping.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @method afterDragOut\r
- */\r
- this.afterDragOut(target, e, id);\r
- }\r
- }\r
- this.cachedTarget = null;\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action before the dragged\r
- * item is dragged out of the target without dropping, and optionally cancel the onDragOut.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
- */\r
- beforeDragOut : function(target, e, id){\r
- return true;\r
- },\r
- \r
- // private\r
- onDragDrop : function(e, id){\r
- var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
- if(this.beforeDragDrop(target, e, id) !== false){\r
- if(target.isNotifyTarget){\r
- if(target.notifyDrop(this, e, this.dragData)){ // valid drop?\r
- this.onValidDrop(target, e, id);\r
- }else{\r
- this.onInvalidDrop(target, e, id);\r
- }\r
- }else{\r
- this.onValidDrop(target, e, id);\r
- }\r
- \r
- if(this.afterDragDrop){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * after a valid drag drop has occurred by providing an implementation.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dropped element\r
- * @method afterDragDrop\r
- */\r
- this.afterDragDrop(target, e, id);\r
- }\r
- }\r
- delete this.cachedTarget;\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action before the dragged\r
- * item is dropped onto the target and optionally cancel the onDragDrop.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel\r
- */\r
- beforeDragDrop : function(target, e, id){\r
- return true;\r
- },\r
-\r
- // private\r
- onValidDrop : function(target, e, id){\r
- this.hideProxy();\r
- if(this.afterValidDrop){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * after a valid drop has occurred by providing an implementation.\r
- * @param {Object} target The target DD \r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dropped element\r
- * @method afterInvalidDrop\r
- */\r
- this.afterValidDrop(target, e, id);\r
- }\r
- },\r
-\r
- // private\r
- getRepairXY : function(e, data){\r
- return this.el.getXY(); \r
- },\r
-\r
- // private\r
- onInvalidDrop : function(target, e, id){\r
- this.beforeInvalidDrop(target, e, id);\r
- if(this.cachedTarget){\r
- if(this.cachedTarget.isNotifyTarget){\r
- this.cachedTarget.notifyOut(this, e, this.dragData);\r
- }\r
- this.cacheTarget = null;\r
- }\r
- this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);\r
-\r
- if(this.afterInvalidDrop){\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action\r
- * after an invalid drop has occurred by providing an implementation.\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dropped element\r
- * @method afterInvalidDrop\r
- */\r
- this.afterInvalidDrop(e, id);\r
- }\r
- },\r
-\r
- // private\r
- afterRepair : function(){\r
- if(Ext.enableFx){\r
- this.el.highlight(this.hlColor || "c3daf9");\r
- }\r
- this.dragging = false;\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action after an invalid\r
- * drop has occurred.\r
- * @param {Ext.dd.DragDrop} target The drop target\r
- * @param {Event} e The event object\r
- * @param {String} id The id of the dragged element\r
- * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel\r
- */\r
- beforeInvalidDrop : function(target, e, id){\r
- return true;\r
- },\r
-\r
- // private\r
- handleMouseDown : function(e){\r
- if(this.dragging) {\r
- return;\r
- }\r
- var data = this.getDragData(e);\r
- if(data && this.onBeforeDrag(data, e) !== false){\r
- this.dragData = data;\r
- this.proxy.stop();\r
- Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);\r
- } \r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action before the initial\r
- * drag event begins and optionally cancel it.\r
- * @param {Object} data An object containing arbitrary data to be shared with drop targets\r
- * @param {Event} e The event object\r
- * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
- */\r
- onBeforeDrag : function(data, e){\r
- return true;\r
- },\r
-\r
- /**\r
- * An empty function by default, but provided so that you can perform a custom action once the initial\r
- * drag event has begun. The drag cannot be canceled from this function.\r
- * @param {Number} x The x position of the click on the dragged object\r
- * @param {Number} y The y position of the click on the dragged object\r
- */\r
- onStartDrag : Ext.emptyFn,\r
-\r
- // private override\r
- startDrag : function(x, y){\r
- this.proxy.reset();\r
- this.dragging = true;\r
- this.proxy.update("");\r
- this.onInitDrag(x, y);\r
- this.proxy.show();\r
- },\r
-\r
- // private\r
- onInitDrag : function(x, y){\r
- var clone = this.el.dom.cloneNode(true);\r
- clone.id = Ext.id(); // prevent duplicate ids\r
- this.proxy.update(clone);\r
- this.onStartDrag(x, y);\r
- return true;\r
- },\r
-\r
- /**\r
- * Returns the drag source's underlying {@link Ext.dd.StatusProxy}\r
- * @return {Ext.dd.StatusProxy} proxy The StatusProxy\r
- */\r
- getProxy : function(){\r
- return this.proxy; \r
- },\r
-\r
- /**\r
- * Hides the drag source's {@link Ext.dd.StatusProxy}\r
- */\r
- hideProxy : function(){\r
- this.proxy.hide(); \r
- this.proxy.reset(true);\r
- this.dragging = false;\r
- },\r
-\r
- // private\r
- triggerCacheRefresh : function(){\r
- Ext.dd.DDM.refreshCache(this.groups);\r
- },\r
-\r
- // private - override to prevent hiding\r
- b4EndDrag: function(e) {\r
- },\r
-\r
- // private - override to prevent moving\r
- endDrag : function(e){\r
- this.onEndDrag(this.dragData, e);\r
- },\r
-\r
- // private\r
- onEndDrag : function(data, e){\r
- },\r
- \r
- // private - pin to cursor\r
- autoOffset : function(x, y) {\r
- this.setDelta(-12, -20);\r
- },\r
- \r
- destroy: function(){\r
- Ext.dd.DragSource.superclass.destroy.call(this);\r
- Ext.destroy(this.proxy);\r
- }\r
-});/**\r
- * @class Ext.dd.DropTarget\r
- * @extends Ext.dd.DDTarget\r
- * A simple class that provides the basic implementation needed to make any element a drop target that can have\r
- * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.\r
- * @constructor\r
- * @param {Mixed} el The container element\r
- * @param {Object} config\r
- */\r
-Ext.dd.DropTarget = function(el, config){\r
- this.el = Ext.get(el);\r
- \r
- Ext.apply(this, config);\r
- \r
- if(this.containerScroll){\r
- Ext.dd.ScrollManager.register(this.el);\r
- }\r
- \r
- Ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, \r
- {isTarget: true});\r
-\r
-};\r
-\r
-Ext.extend(Ext.dd.DropTarget, Ext.dd.DDTarget, {\r
- /**\r
- * @cfg {String} ddGroup\r
- * A named drag drop group to which this object belongs. If a group is specified, then this object will only\r
- * interact with other drag drop objects in the same group (defaults to undefined).\r
- */\r
- /**\r
- * @cfg {String} overClass\r
- * The CSS class applied to the drop target element while the drag source is over it (defaults to "").\r
- */\r
- /**\r
- * @cfg {String} dropAllowed\r
- * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").\r
- */\r
- dropAllowed : "x-dd-drop-ok",\r
- /**\r
- * @cfg {String} dropNotAllowed\r
- * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
- */\r
- dropNotAllowed : "x-dd-drop-nodrop",\r
-\r
- // private\r
- isTarget : true,\r
-\r
- // private\r
- isNotifyTarget : true,\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source is now over the\r
- * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element\r
- * and returns the dropAllowed config value. This method should be overridden if drop validation is required.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- notifyEnter : function(dd, e, data){\r
- if(this.overClass){\r
- this.el.addClass(this.overClass);\r
- }\r
- return this.dropAllowed;\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the target.\r
- * This method will be called on every mouse movement while the drag source is over the drop target.\r
- * This default implementation simply returns the dropAllowed config value.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- notifyOver : function(dd, e, data){\r
- return this.dropAllowed;\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source has been dragged\r
- * out of the target without dropping. This default implementation simply removes the CSS class specified by\r
- * overClass (if any) from the drop element.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- */\r
- notifyOut : function(dd, e, data){\r
- if(this.overClass){\r
- this.el.removeClass(this.overClass);\r
- }\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the dragged item has\r
- * been dropped on it. This method has no default implementation and returns false, so you must provide an\r
- * implementation that does something to process the drop event and returns true so that the drag source's\r
- * repair action does not run.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {Boolean} True if the drop was valid, else false\r
- */\r
- notifyDrop : function(dd, e, data){\r
- return false;\r
- }\r
-});/**\r
- * @class Ext.dd.DragZone\r
- * @extends Ext.dd.DragSource\r
- * <p>This class provides a container DD instance that allows dragging of multiple child source nodes.</p>\r
- * <p>This class does not move the drag target nodes, but a proxy element which may contain\r
- * any DOM structure you wish. The DOM element to show in the proxy is provided by either a\r
- * provided implementation of {@link #getDragData}, or by registered draggables registered with {@link Ext.dd.Registry}</p>\r
- * <p>If you wish to provide draggability for an arbitrary number of DOM nodes, each of which represent some\r
- * application object (For example nodes in a {@link Ext.DataView DataView}) then use of this class\r
- * is the most efficient way to "activate" those nodes.</p>\r
- * <p>By default, this class requires that draggable child nodes are registered with {@link Ext.dd.Registry}.\r
- * However a simpler way to allow a DragZone to manage any number of draggable elements is to configure\r
- * the DragZone with an implementation of the {@link #getDragData} method which interrogates the passed\r
- * mouse event to see if it has taken place within an element, or class of elements. This is easily done\r
- * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a\r
- * {@link Ext.DomQuery} selector. For example, to make the nodes of a DataView draggable, use the following\r
- * technique. Knowledge of the use of the DataView is required:</p><pre><code>\r
-myDataView.on('render', function(v) {\r
- myDataView.dragZone = new Ext.dd.DragZone(v.getEl(), {\r
-\r
-// On receipt of a mousedown event, see if it is within a DataView node.\r
-// Return a drag data object if so.\r
- getDragData: function(e) {\r
-\r
-// Use the DataView's own itemSelector (a mandatory property) to\r
-// test if the mousedown is within one of the DataView's nodes.\r
- var sourceEl = e.getTarget(v.itemSelector, 10);\r
-\r
-// If the mousedown is within a DataView node, clone the node to produce\r
-// a ddel element for use by the drag proxy. Also add application data\r
-// to the returned data object.\r
- if (sourceEl) {\r
- d = sourceEl.cloneNode(true);\r
- d.id = Ext.id();\r
- return {\r
- ddel: d,\r
- sourceEl: sourceEl,\r
- repairXY: Ext.fly(sourceEl).getXY(),\r
- sourceStore: v.store,\r
- draggedRecord: v.{@link Ext.DataView#getRecord getRecord}(sourceEl)\r
- }\r
- }\r
- },\r
-\r
-// Provide coordinates for the proxy to slide back to on failed drag.\r
-// This is the original XY coordinates of the draggable element captured\r
-// in the getDragData method.\r
- getRepairXY: function() {\r
- return this.dragData.repairXY;\r
- }\r
- });\r
-});</code></pre>\r
- * See the {@link Ext.dd.DropZone DropZone} documentation for details about building a DropZone which\r
- * cooperates with this DragZone.\r
- * @constructor\r
- * @param {Mixed} el The container element\r
- * @param {Object} config\r
- */\r
-Ext.dd.DragZone = function(el, config){\r
- Ext.dd.DragZone.superclass.constructor.call(this, el, config);\r
- if(this.containerScroll){\r
- Ext.dd.ScrollManager.register(this.el);\r
- }\r
-};\r
-\r
-Ext.extend(Ext.dd.DragZone, Ext.dd.DragSource, {\r
- /**\r
- * This property contains the data representing the dragged object. This data is set up by the implementation\r
- * of the {@link #getDragData} method. It must contain a <tt>ddel</tt> property, but can contain\r
- * any other data according to the application's needs.\r
- * @type Object\r
- * @property dragData\r
- */\r
- /**\r
- * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager\r
- * for auto scrolling during drag operations.\r
- */\r
- /**\r
- * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair\r
- * method after a failed drop (defaults to "c3daf9" - light blue)\r
- */\r
-\r
- /**\r
- * Called when a mousedown occurs in this container. Looks in {@link Ext.dd.Registry}\r
- * for a valid target to drag based on the mouse down. Override this method\r
- * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned\r
- * object has a "ddel" attribute (with an HTML Element) for other functions to work.\r
- * @param {EventObject} e The mouse down event\r
- * @return {Object} The dragData\r
- */\r
- getDragData : function(e){\r
- return Ext.dd.Registry.getHandleFromEvent(e);\r
- },\r
- \r
- /**\r
- * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the\r
- * this.dragData.ddel\r
- * @param {Number} x The x position of the click on the dragged object\r
- * @param {Number} y The y position of the click on the dragged object\r
- * @return {Boolean} true to continue the drag, false to cancel\r
- */\r
- onInitDrag : function(x, y){\r
- this.proxy.update(this.dragData.ddel.cloneNode(true));\r
- this.onStartDrag(x, y);\r
- return true;\r
- },\r
- \r
- /**\r
- * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel \r
- */\r
- afterRepair : function(){\r
- if(Ext.enableFx){\r
- Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");\r
- }\r
- this.dragging = false;\r
- },\r
-\r
- /**\r
- * Called before a repair of an invalid drop to get the XY to animate to. By default returns\r
- * the XY of this.dragData.ddel\r
- * @param {EventObject} e The mouse up event\r
- * @return {Array} The xy location (e.g. [100, 200])\r
- */\r
- getRepairXY : function(e){\r
- return Ext.Element.fly(this.dragData.ddel).getXY(); \r
- }\r
-});/**\r
- * @class Ext.dd.DropZone\r
- * @extends Ext.dd.DropTarget\r
- * <p>This class provides a container DD instance that allows dropping on multiple child target nodes.</p>\r
- * <p>By default, this class requires that child nodes accepting drop are registered with {@link Ext.dd.Registry}.\r
- * However a simpler way to allow a DropZone to manage any number of target elements is to configure the\r
- * DropZone with an implementation of {@link #getTargetFromEvent} which interrogates the passed\r
- * mouse event to see if it has taken place within an element, or class of elements. This is easily done\r
- * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a\r
- * {@link Ext.DomQuery} selector.</p>\r
- * <p>Once the DropZone has detected through calling getTargetFromEvent, that the mouse is over\r
- * a drop target, that target is passed as the first parameter to {@link #onNodeEnter}, {@link #onNodeOver},\r
- * {@link #onNodeOut}, {@link #onNodeDrop}. You may configure the instance of DropZone with implementations\r
- * of these methods to provide application-specific behaviour for these events to update both\r
- * application state, and UI state.</p>\r
- * <p>For example to make a GridPanel a cooperating target with the example illustrated in\r
- * {@link Ext.dd.DragZone DragZone}, the following technique might be used:</p><pre><code>\r
-myGridPanel.on('render', function() {\r
- myGridPanel.dropZone = new Ext.dd.DropZone(myGridPanel.getView().scroller, {\r
-\r
-// If the mouse is over a grid row, return that node. This is\r
-// provided as the "target" parameter in all "onNodeXXXX" node event handling functions\r
- getTargetFromEvent: function(e) {\r
- return e.getTarget(myGridPanel.getView().rowSelector);\r
- },\r
-\r
-// On entry into a target node, highlight that node.\r
- onNodeEnter : function(target, dd, e, data){ \r
- Ext.fly(target).addClass('my-row-highlight-class');\r
- },\r
-\r
-// On exit from a target node, unhighlight that node.\r
- onNodeOut : function(target, dd, e, data){ \r
- Ext.fly(target).removeClass('my-row-highlight-class');\r
- },\r
-\r
-// While over a target node, return the default drop allowed class which\r
-// places a "tick" icon into the drag proxy.\r
- onNodeOver : function(target, dd, e, data){ \r
- return Ext.dd.DropZone.prototype.dropAllowed;\r
- },\r
-\r
-// On node drop we can interrogate the target to find the underlying\r
-// application object that is the real target of the dragged data.\r
-// In this case, it is a Record in the GridPanel's Store.\r
-// We can use the data set up by the DragZone's getDragData method to read\r
-// any data we decided to attach in the DragZone's getDragData method.\r
- onNodeDrop : function(target, dd, e, data){\r
- var rowIndex = myGridPanel.getView().findRowIndex(target);\r
- var r = myGridPanel.getStore().getAt(rowIndex);\r
- Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +\r
- ' on Record id ' + r.id);\r
- return true;\r
- }\r
- });\r
-}\r
-</code></pre>\r
- * See the {@link Ext.dd.DragZone DragZone} documentation for details about building a DragZone which\r
- * cooperates with this DropZone.\r
- * @constructor\r
- * @param {Mixed} el The container element\r
- * @param {Object} config\r
- */\r
-Ext.dd.DropZone = function(el, config){\r
- Ext.dd.DropZone.superclass.constructor.call(this, el, config);\r
-};\r
-\r
-Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {\r
- /**\r
- * Returns a custom data object associated with the DOM node that is the target of the event. By default\r
- * this looks up the event target in the {@link Ext.dd.Registry}, although you can override this method to\r
- * provide your own custom lookup.\r
- * @param {Event} e The event\r
- * @return {Object} data The custom data\r
- */\r
- getTargetFromEvent : function(e){\r
- return Ext.dd.Registry.getTargetFromEvent(e);\r
- },\r
-\r
- /**\r
- * Called when the DropZone determines that a {@link Ext.dd.DragSource} has entered a drop node\r
- * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.\r
- * This method has no default implementation and should be overridden to provide\r
- * node-specific processing if necessary.\r
- * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from \r
- * {@link #getTargetFromEvent} for this node)\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- */\r
- onNodeEnter : function(n, dd, e, data){\r
- \r
- },\r
-\r
- /**\r
- * Called while the DropZone determines that a {@link Ext.dd.DragSource} is over a drop node\r
- * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.\r
- * The default implementation returns this.dropNotAllowed, so it should be\r
- * overridden to provide the proper feedback.\r
- * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
- * {@link #getTargetFromEvent} for this node)\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- onNodeOver : function(n, dd, e, data){\r
- return this.dropAllowed;\r
- },\r
-\r
- /**\r
- * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dragged out of\r
- * the drop node without dropping. This method has no default implementation and should be overridden to provide\r
- * node-specific processing if necessary.\r
- * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
- * {@link #getTargetFromEvent} for this node)\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- */\r
- onNodeOut : function(n, dd, e, data){\r
- \r
- },\r
-\r
- /**\r
- * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto\r
- * the drop node. The default implementation returns false, so it should be overridden to provide the\r
- * appropriate processing of the drop event and return true so that the drag source's repair action does not run.\r
- * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
- * {@link #getTargetFromEvent} for this node)\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {Boolean} True if the drop was valid, else false\r
- */\r
- onNodeDrop : function(n, dd, e, data){\r
- return false;\r
- },\r
-\r
- /**\r
- * Called while the DropZone determines that a {@link Ext.dd.DragSource} is being dragged over it,\r
- * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so\r
- * it should be overridden to provide the proper feedback if necessary.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- onContainerOver : function(dd, e, data){\r
- return this.dropNotAllowed;\r
- },\r
-\r
- /**\r
- * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped on it,\r
- * but not on any of its registered drop nodes. The default implementation returns false, so it should be\r
- * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to\r
- * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {Boolean} True if the drop was valid, else false\r
- */\r
- onContainerDrop : function(dd, e, data){\r
- return false;\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source is now over\r
- * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop\r
- * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops\r
- * you should override this method and provide a custom implementation.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- notifyEnter : function(dd, e, data){\r
- return this.dropNotAllowed;\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the drop zone.\r
- * This method will be called on every mouse movement while the drag source is over the drop zone.\r
- * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically\r
- * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits\r
- * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a\r
- * registered node, it will call {@link #onContainerOver}.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
- * underlying {@link Ext.dd.StatusProxy} can be updated\r
- */\r
- notifyOver : function(dd, e, data){\r
- var n = this.getTargetFromEvent(e);\r
- if(!n){ // not over valid drop target\r
- if(this.lastOverNode){\r
- this.onNodeOut(this.lastOverNode, dd, e, data);\r
- this.lastOverNode = null;\r
- }\r
- return this.onContainerOver(dd, e, data);\r
- }\r
- if(this.lastOverNode != n){\r
- if(this.lastOverNode){\r
- this.onNodeOut(this.lastOverNode, dd, e, data);\r
- }\r
- this.onNodeEnter(n, dd, e, data);\r
- this.lastOverNode = n;\r
- }\r
- return this.onNodeOver(n, dd, e, data);\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source has been dragged\r
- * out of the zone without dropping. If the drag source is currently over a registered node, the notification\r
- * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag zone\r
- */\r
- notifyOut : function(dd, e, data){\r
- if(this.lastOverNode){\r
- this.onNodeOut(this.lastOverNode, dd, e, data);\r
- this.lastOverNode = null;\r
- }\r
- },\r
-\r
- /**\r
- * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the dragged item has\r
- * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there\r
- * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,\r
- * otherwise it will call {@link #onContainerDrop}.\r
- * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
- * @param {Event} e The event\r
- * @param {Object} data An object containing arbitrary data supplied by the drag source\r
- * @return {Boolean} True if the drop was valid, else false\r
- */\r
- notifyDrop : function(dd, e, data){\r
- if(this.lastOverNode){\r
- this.onNodeOut(this.lastOverNode, dd, e, data);\r
- this.lastOverNode = null;\r
- }\r
- var n = this.getTargetFromEvent(e);\r
- return n ?\r
- this.onNodeDrop(n, dd, e, data) :\r
- this.onContainerDrop(dd, e, data);\r
- },\r
-\r
- // private\r
- triggerCacheRefresh : function(){\r
- Ext.dd.DDM.refreshCache(this.groups);\r
- } \r
-});/**\r
- * @class Ext.Element\r
- */\r
-Ext.Element.addMethods({\r
- /**\r
- * Initializes a {@link Ext.dd.DD} drag drop object for this element.\r
- * @param {String} group The group the DD object is member of\r
- * @param {Object} config The DD config object\r
- * @param {Object} overrides An object containing methods to override/implement on the DD object\r
- * @return {Ext.dd.DD} The DD object\r
- */\r
- initDD : function(group, config, overrides){\r
- var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);\r
- return Ext.apply(dd, overrides);\r
- },\r
-\r
- /**\r
- * Initializes a {@link Ext.dd.DDProxy} object for this element.\r
- * @param {String} group The group the DDProxy object is member of\r
- * @param {Object} config The DDProxy config object\r
- * @param {Object} overrides An object containing methods to override/implement on the DDProxy object\r
- * @return {Ext.dd.DDProxy} The DDProxy object\r
- */\r
- initDDProxy : function(group, config, overrides){\r
- var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);\r
- return Ext.apply(dd, overrides);\r
- },\r
-\r
- /**\r
- * Initializes a {@link Ext.dd.DDTarget} object for this element.\r
- * @param {String} group The group the DDTarget object is member of\r
- * @param {Object} config The DDTarget config object\r
- * @param {Object} overrides An object containing methods to override/implement on the DDTarget object\r
- * @return {Ext.dd.DDTarget} The DDTarget object\r
- */\r
- initDDTarget : function(group, config, overrides){\r
- var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);\r
- return Ext.apply(dd, overrides);\r
- }\r
+});/**
+ * @class Ext.dd.DragTracker
+ * @extends Ext.util.Observable
+ * A DragTracker listens for drag events on an Element and fires events at the start and end of the drag,
+ * as well as during the drag. This is useful for components such as {@link Ext.Slider}, where there is
+ * an element that can be dragged around to change the Slider's value.
+ * DragTracker provides a series of template methods that should be overridden to provide functionality
+ * in response to detected drag operations. These are onBeforeStart, onStart, onDrag and onEnd.
+ * See {@link Ext.Slider}'s initEvents function for an example implementation.
+ */
+Ext.dd.DragTracker = Ext.extend(Ext.util.Observable, {
+ /**
+ * @cfg {Boolean} active
+ * Defaults to <tt>false</tt>.
+ */
+ active: false,
+ /**
+ * @cfg {Number} tolerance
+ * Number of pixels the drag target must be moved before dragging is considered to have started. Defaults to <tt>5</tt>.
+ */
+ tolerance: 5,
+ /**
+ * @cfg {Boolean/Number} autoStart
+ * Defaults to <tt>false</tt>. Specify <tt>true</tt> to defer trigger start by 1000 ms.
+ * Specify a Number for the number of milliseconds to defer trigger start.
+ */
+ autoStart: false,
+
+ constructor : function(config){
+ Ext.apply(this, config);
+ this.addEvents(
+ /**
+ * @event mousedown
+ * @param {Object} this
+ * @param {Object} e event object
+ */
+ 'mousedown',
+ /**
+ * @event mouseup
+ * @param {Object} this
+ * @param {Object} e event object
+ */
+ 'mouseup',
+ /**
+ * @event mousemove
+ * @param {Object} this
+ * @param {Object} e event object
+ */
+ 'mousemove',
+ /**
+ * @event dragstart
+ * @param {Object} this
+ * @param {Object} startXY the page coordinates of the event
+ */
+ 'dragstart',
+ /**
+ * @event dragend
+ * @param {Object} this
+ * @param {Object} e event object
+ */
+ 'dragend',
+ /**
+ * @event drag
+ * @param {Object} this
+ * @param {Object} e event object
+ */
+ 'drag'
+ );
+
+ this.dragRegion = new Ext.lib.Region(0,0,0,0);
+
+ if(this.el){
+ this.initEl(this.el);
+ }
+ Ext.dd.DragTracker.superclass.constructor.call(this, config);
+ },
+
+ initEl: function(el){
+ this.el = Ext.get(el);
+ el.on('mousedown', this.onMouseDown, this,
+ this.delegate ? {delegate: this.delegate} : undefined);
+ },
+
+ destroy : function(){
+ this.el.un('mousedown', this.onMouseDown, this);
+ },
+
+ onMouseDown: function(e, target){
+ if(this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false){
+ this.startXY = this.lastXY = e.getXY();
+ this.dragTarget = this.delegate ? target : this.el.dom;
+ if(this.preventDefault !== false){
+ e.preventDefault();
+ }
+ var doc = Ext.getDoc();
+ doc.on('mouseup', this.onMouseUp, this);
+ doc.on('mousemove', this.onMouseMove, this);
+ doc.on('selectstart', this.stopSelect, this);
+ if(this.autoStart){
+ this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this);
+ }
+ }
+ },
+
+ onMouseMove: function(e, target){
+ // HACK: IE hack to see if button was released outside of window. */
+ if(this.active && Ext.isIE && !e.browserEvent.button){
+ e.preventDefault();
+ this.onMouseUp(e);
+ return;
+ }
+
+ e.preventDefault();
+ var xy = e.getXY(), s = this.startXY;
+ this.lastXY = xy;
+ if(!this.active){
+ if(Math.abs(s[0]-xy[0]) > this.tolerance || Math.abs(s[1]-xy[1]) > this.tolerance){
+ this.triggerStart();
+ }else{
+ return;
+ }
+ }
+ this.fireEvent('mousemove', this, e);
+ this.onDrag(e);
+ this.fireEvent('drag', this, e);
+ },
+
+ onMouseUp: function(e) {
+ var doc = Ext.getDoc();
+ doc.un('mousemove', this.onMouseMove, this);
+ doc.un('mouseup', this.onMouseUp, this);
+ doc.un('selectstart', this.stopSelect, this);
+ e.preventDefault();
+ this.clearStart();
+ var wasActive = this.active;
+ this.active = false;
+ delete this.elRegion;
+ this.fireEvent('mouseup', this, e);
+ if(wasActive){
+ this.onEnd(e);
+ this.fireEvent('dragend', this, e);
+ }
+ },
+
+ triggerStart: function(isTimer) {
+ this.clearStart();
+ this.active = true;
+ this.onStart(this.startXY);
+ this.fireEvent('dragstart', this, this.startXY);
+ },
+
+ clearStart : function() {
+ if(this.timer){
+ clearTimeout(this.timer);
+ delete this.timer;
+ }
+ },
+
+ stopSelect : function(e) {
+ e.stopEvent();
+ return false;
+ },
+
+ /**
+ * Template method which should be overridden by each DragTracker instance. Called when the user first clicks and
+ * holds the mouse button down. Return false to disallow the drag
+ * @param {Ext.EventObject} e The event object
+ */
+ onBeforeStart : function(e) {
+
+ },
+
+ /**
+ * Template method which should be overridden by each DragTracker instance. Called when a drag operation starts
+ * (e.g. the user has moved the tracked element beyond the specified tolerance)
+ * @param {Array} xy x and y co-ordinates of the original location of the tracked element
+ */
+ onStart : function(xy) {
+
+ },
+
+ /**
+ * Template method which should be overridden by each DragTracker instance. Called whenever a drag has been detected.
+ * @param {Ext.EventObject} e The event object
+ */
+ onDrag : function(e) {
+
+ },
+
+ /**
+ * Template method which should be overridden by each DragTracker instance. Called when a drag operation has been completed
+ * (e.g. the user clicked and held the mouse down, dragged the element and then released the mouse button)
+ * @param {Ext.EventObject} e The event object
+ */
+ onEnd : function(e) {
+
+ },
+
+ /**
+ * Returns the drag target
+ * @return {Ext.Element} The element currently being tracked
+ */
+ getDragTarget : function(){
+ return this.dragTarget;
+ },
+
+ getDragCt : function(){
+ return this.el;
+ },
+
+ getXY : function(constrain){
+ return constrain ?
+ this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY;
+ },
+
+ getOffset : function(constrain){
+ var xy = this.getXY(constrain);
+ var s = this.startXY;
+ return [s[0]-xy[0], s[1]-xy[1]];
+ },
+
+ constrainModes: {
+ 'point' : function(xy){
+
+ if(!this.elRegion){
+ this.elRegion = this.getDragCt().getRegion();
+ }
+
+ var dr = this.dragRegion;
+
+ dr.left = xy[0];
+ dr.top = xy[1];
+ dr.right = xy[0];
+ dr.bottom = xy[1];
+
+ dr.constrainTo(this.elRegion);
+
+ return [dr.left, dr.top];
+ }
+ }
+});/**
+ * @class Ext.dd.ScrollManager
+ * <p>Provides automatic scrolling of overflow regions in the page during drag operations.</p>
+ * <p>The ScrollManager configs will be used as the defaults for any scroll container registered with it,
+ * but you can also override most of the configs per scroll container by adding a
+ * <tt>ddScrollConfig</tt> object to the target element that contains these properties: {@link #hthresh},
+ * {@link #vthresh}, {@link #increment} and {@link #frequency}. Example usage:
+ * <pre><code>
+var el = Ext.get('scroll-ct');
+el.ddScrollConfig = {
+ vthresh: 50,
+ hthresh: -1,
+ frequency: 100,
+ increment: 200
+};
+Ext.dd.ScrollManager.register(el);
+</code></pre>
+ * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
+ * @singleton
+ */
+Ext.dd.ScrollManager = function(){
+ var ddm = Ext.dd.DragDropMgr;
+ var els = {};
+ var dragEl = null;
+ var proc = {};
+
+ var onStop = function(e){
+ dragEl = null;
+ clearProc();
+ };
+
+ var triggerRefresh = function(){
+ if(ddm.dragCurrent){
+ ddm.refreshCache(ddm.dragCurrent.groups);
+ }
+ };
+
+ var doScroll = function(){
+ if(ddm.dragCurrent){
+ var dds = Ext.dd.ScrollManager;
+ var inc = proc.el.ddScrollConfig ?
+ proc.el.ddScrollConfig.increment : dds.increment;
+ if(!dds.animate){
+ if(proc.el.scroll(proc.dir, inc)){
+ triggerRefresh();
+ }
+ }else{
+ proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);
+ }
+ }
+ };
+
+ var clearProc = function(){
+ if(proc.id){
+ clearInterval(proc.id);
+ }
+ proc.id = 0;
+ proc.el = null;
+ proc.dir = "";
+ };
+
+ var startProc = function(el, dir){
+ clearProc();
+ proc.el = el;
+ proc.dir = dir;
+ var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ?
+ el.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;
+ proc.id = setInterval(doScroll, freq);
+ };
+
+ var onFire = function(e, isDrop){
+ if(isDrop || !ddm.dragCurrent){ return; }
+ var dds = Ext.dd.ScrollManager;
+ if(!dragEl || dragEl != ddm.dragCurrent){
+ dragEl = ddm.dragCurrent;
+ // refresh regions on drag start
+ dds.refreshCache();
+ }
+
+ var xy = Ext.lib.Event.getXY(e);
+ var pt = new Ext.lib.Point(xy[0], xy[1]);
+ for(var id in els){
+ var el = els[id], r = el._region;
+ var c = el.ddScrollConfig ? el.ddScrollConfig : dds;
+ if(r && r.contains(pt) && el.isScrollable()){
+ if(r.bottom - pt.y <= c.vthresh){
+ if(proc.el != el){
+ startProc(el, "down");
+ }
+ return;
+ }else if(r.right - pt.x <= c.hthresh){
+ if(proc.el != el){
+ startProc(el, "left");
+ }
+ return;
+ }else if(pt.y - r.top <= c.vthresh){
+ if(proc.el != el){
+ startProc(el, "up");
+ }
+ return;
+ }else if(pt.x - r.left <= c.hthresh){
+ if(proc.el != el){
+ startProc(el, "right");
+ }
+ return;
+ }
+ }
+ }
+ clearProc();
+ };
+
+ ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
+ ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
+
+ return {
+ /**
+ * Registers new overflow element(s) to auto scroll
+ * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either
+ */
+ register : function(el){
+ if(Ext.isArray(el)){
+ for(var i = 0, len = el.length; i < len; i++) {
+ this.register(el[i]);
+ }
+ }else{
+ el = Ext.get(el);
+ els[el.id] = el;
+ }
+ },
+
+ /**
+ * Unregisters overflow element(s) so they are no longer scrolled
+ * @param {Mixed/Array} el The id of or the element to be removed or an array of either
+ */
+ unregister : function(el){
+ if(Ext.isArray(el)){
+ for(var i = 0, len = el.length; i < len; i++) {
+ this.unregister(el[i]);
+ }
+ }else{
+ el = Ext.get(el);
+ delete els[el.id];
+ }
+ },
+
+ /**
+ * The number of pixels from the top or bottom edge of a container the pointer needs to be to
+ * trigger scrolling (defaults to 25)
+ * @type Number
+ */
+ vthresh : 25,
+ /**
+ * The number of pixels from the right or left edge of a container the pointer needs to be to
+ * trigger scrolling (defaults to 25)
+ * @type Number
+ */
+ hthresh : 25,
+
+ /**
+ * The number of pixels to scroll in each scroll increment (defaults to 50)
+ * @type Number
+ */
+ increment : 100,
+
+ /**
+ * The frequency of scrolls in milliseconds (defaults to 500)
+ * @type Number
+ */
+ frequency : 500,
+
+ /**
+ * True to animate the scroll (defaults to true)
+ * @type Boolean
+ */
+ animate: true,
+
+ /**
+ * The animation duration in seconds -
+ * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)
+ * @type Number
+ */
+ animDuration: .4,
+
+ /**
+ * Manually trigger a cache refresh.
+ */
+ refreshCache : function(){
+ for(var id in els){
+ if(typeof els[id] == 'object'){ // for people extending the object prototype
+ els[id]._region = els[id].getRegion();
+ }
+ }
+ }
+ };
+}();/**
+ * @class Ext.dd.Registry
+ * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
+ * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
+ * @singleton
+ */
+Ext.dd.Registry = function(){
+ var elements = {};
+ var handles = {};
+ var autoIdSeed = 0;
+
+ var getId = function(el, autogen){
+ if(typeof el == "string"){
+ return el;
+ }
+ var id = el.id;
+ if(!id && autogen !== false){
+ id = "extdd-" + (++autoIdSeed);
+ el.id = id;
+ }
+ return id;
+ };
+
+ return {
+ /**
+ * Resgister a drag drop element
+ * @param {String/HTMLElement} element The id or DOM node to register
+ * @param {Object} data (optional) An custom data object that will be passed between the elements that are involved
+ * in drag drop operations. You can populate this object with any arbitrary properties that your own code
+ * knows how to interpret, plus there are some specific properties known to the Registry that should be
+ * populated in the data object (if applicable):
+ * <pre>
+Value Description<br />
+--------- ------------------------------------------<br />
+handles Array of DOM nodes that trigger dragging<br />
+ for the element being registered<br />
+isHandle True if the element passed in triggers<br />
+ dragging itself, else false
+</pre>
+ */
+ register : function(el, data){
+ data = data || {};
+ if(typeof el == "string"){
+ el = document.getElementById(el);
+ }
+ data.ddel = el;
+ elements[getId(el)] = data;
+ if(data.isHandle !== false){
+ handles[data.ddel.id] = data;
+ }
+ if(data.handles){
+ var hs = data.handles;
+ for(var i = 0, len = hs.length; i < len; i++){
+ handles[getId(hs[i])] = data;
+ }
+ }
+ },
+
+ /**
+ * Unregister a drag drop element
+ * @param {String/HTMLElement} element The id or DOM node to unregister
+ */
+ unregister : function(el){
+ var id = getId(el, false);
+ var data = elements[id];
+ if(data){
+ delete elements[id];
+ if(data.handles){
+ var hs = data.handles;
+ for(var i = 0, len = hs.length; i < len; i++){
+ delete handles[getId(hs[i], false)];
+ }
+ }
+ }
+ },
+
+ /**
+ * Returns the handle registered for a DOM Node by id
+ * @param {String/HTMLElement} id The DOM node or id to look up
+ * @return {Object} handle The custom handle data
+ */
+ getHandle : function(id){
+ if(typeof id != "string"){ // must be element?
+ id = id.id;
+ }
+ return handles[id];
+ },
+
+ /**
+ * Returns the handle that is registered for the DOM node that is the target of the event
+ * @param {Event} e The event
+ * @return {Object} handle The custom handle data
+ */
+ getHandleFromEvent : function(e){
+ var t = Ext.lib.Event.getTarget(e);
+ return t ? handles[t.id] : null;
+ },
+
+ /**
+ * Returns a custom data object that is registered for a DOM node by id
+ * @param {String/HTMLElement} id The DOM node or id to look up
+ * @return {Object} data The custom data
+ */
+ getTarget : function(id){
+ if(typeof id != "string"){ // must be element?
+ id = id.id;
+ }
+ return elements[id];
+ },
+
+ /**
+ * Returns a custom data object that is registered for the DOM node that is the target of the event
+ * @param {Event} e The event
+ * @return {Object} data The custom data
+ */
+ getTargetFromEvent : function(e){
+ var t = Ext.lib.Event.getTarget(e);
+ return t ? elements[t.id] || handles[t.id] : null;
+ }
+ };
+}();/**
+ * @class Ext.dd.StatusProxy
+ * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair. This is the
+ * default drag proxy used by all Ext.dd components.
+ * @constructor
+ * @param {Object} config
+ */
+Ext.dd.StatusProxy = function(config){
+ Ext.apply(this, config);
+ this.id = this.id || Ext.id();
+ this.el = new Ext.Layer({
+ dh: {
+ id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
+ {tag: "div", cls: "x-dd-drop-icon"},
+ {tag: "div", cls: "x-dd-drag-ghost"}
+ ]
+ },
+ shadow: !config || config.shadow !== false
+ });
+ this.ghost = Ext.get(this.el.dom.childNodes[1]);
+ this.dropStatus = this.dropNotAllowed;
+};
+
+Ext.dd.StatusProxy.prototype = {
+ /**
+ * @cfg {String} dropAllowed
+ * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
+ */
+ dropAllowed : "x-dd-drop-ok",
+ /**
+ * @cfg {String} dropNotAllowed
+ * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
+ */
+ dropNotAllowed : "x-dd-drop-nodrop",
+
+ /**
+ * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
+ * over the current target element.
+ * @param {String} cssClass The css class for the new drop status indicator image
+ */
+ setStatus : function(cssClass){
+ cssClass = cssClass || this.dropNotAllowed;
+ if(this.dropStatus != cssClass){
+ this.el.replaceClass(this.dropStatus, cssClass);
+ this.dropStatus = cssClass;
+ }
+ },
+
+ /**
+ * Resets the status indicator to the default dropNotAllowed value
+ * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
+ */
+ reset : function(clearGhost){
+ this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
+ this.dropStatus = this.dropNotAllowed;
+ if(clearGhost){
+ this.ghost.update("");
+ }
+ },
+
+ /**
+ * Updates the contents of the ghost element
+ * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
+ * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
+ */
+ update : function(html){
+ if(typeof html == "string"){
+ this.ghost.update(html);
+ }else{
+ this.ghost.update("");
+ html.style.margin = "0";
+ this.ghost.dom.appendChild(html);
+ }
+ var el = this.ghost.dom.firstChild;
+ if(el){
+ Ext.fly(el).setStyle('float', 'none');
+ }
+ },
+
+ /**
+ * Returns the underlying proxy {@link Ext.Layer}
+ * @return {Ext.Layer} el
+ */
+ getEl : function(){
+ return this.el;
+ },
+
+ /**
+ * Returns the ghost element
+ * @return {Ext.Element} el
+ */
+ getGhost : function(){
+ return this.ghost;
+ },
+
+ /**
+ * Hides the proxy
+ * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
+ */
+ hide : function(clear){
+ this.el.hide();
+ if(clear){
+ this.reset(true);
+ }
+ },
+
+ /**
+ * Stops the repair animation if it's currently running
+ */
+ stop : function(){
+ if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
+ this.anim.stop();
+ }
+ },
+
+ /**
+ * Displays this proxy
+ */
+ show : function(){
+ this.el.show();
+ },
+
+ /**
+ * Force the Layer to sync its shadow and shim positions to the element
+ */
+ sync : function(){
+ this.el.sync();
+ },
+
+ /**
+ * Causes the proxy to return to its position of origin via an animation. Should be called after an
+ * invalid drop operation by the item being dragged.
+ * @param {Array} xy The XY position of the element ([x, y])
+ * @param {Function} callback The function to call after the repair is complete.
+ * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+ */
+ repair : function(xy, callback, scope){
+ this.callback = callback;
+ this.scope = scope;
+ if(xy && this.animRepair !== false){
+ this.el.addClass("x-dd-drag-repair");
+ this.el.hideUnders(true);
+ this.anim = this.el.shift({
+ duration: this.repairDuration || .5,
+ easing: 'easeOut',
+ xy: xy,
+ stopFx: true,
+ callback: this.afterRepair,
+ scope: this
+ });
+ }else{
+ this.afterRepair();
+ }
+ },
+
+ // private
+ afterRepair : function(){
+ this.hide(true);
+ if(typeof this.callback == "function"){
+ this.callback.call(this.scope || this);
+ }
+ this.callback = null;
+ this.scope = null;
+ },
+
+ destroy: function(){
+ Ext.destroy(this.ghost, this.el);
+ }
+};/**
+ * @class Ext.dd.DragSource
+ * @extends Ext.dd.DDProxy
+ * A simple class that provides the basic implementation needed to make any element draggable.
+ * @constructor
+ * @param {Mixed} el The container element
+ * @param {Object} config
+ */
+Ext.dd.DragSource = function(el, config){
+ this.el = Ext.get(el);
+ if(!this.dragData){
+ this.dragData = {};
+ }
+
+ Ext.apply(this, config);
+
+ if(!this.proxy){
+ this.proxy = new Ext.dd.StatusProxy();
+ }
+ Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
+ {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
+
+ this.dragging = false;
+};
+
+Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {
+ /**
+ * @cfg {String} ddGroup
+ * A named drag drop group to which this object belongs. If a group is specified, then this object will only
+ * interact with other drag drop objects in the same group (defaults to undefined).
+ */
+ /**
+ * @cfg {String} dropAllowed
+ * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+ */
+ dropAllowed : "x-dd-drop-ok",
+ /**
+ * @cfg {String} dropNotAllowed
+ * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+ */
+ dropNotAllowed : "x-dd-drop-nodrop",
+
+ /**
+ * Returns the data object associated with this drag source
+ * @return {Object} data An object containing arbitrary data
+ */
+ getDragData : function(e){
+ return this.dragData;
+ },
+
+ // private
+ onDragEnter : function(e, id){
+ var target = Ext.dd.DragDropMgr.getDDById(id);
+ this.cachedTarget = target;
+ if(this.beforeDragEnter(target, e, id) !== false){
+ if(target.isNotifyTarget){
+ var status = target.notifyEnter(this, e, this.dragData);
+ this.proxy.setStatus(status);
+ }else{
+ this.proxy.setStatus(this.dropAllowed);
+ }
+
+ if(this.afterDragEnter){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * when the dragged item enters the drop target by providing an implementation.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @method afterDragEnter
+ */
+ this.afterDragEnter(target, e, id);
+ }
+ }
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * before the dragged item enters the drop target and optionally cancel the onDragEnter.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+ */
+ beforeDragEnter : function(target, e, id){
+ return true;
+ },
+
+ // private
+ alignElWithMouse: function() {
+ Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
+ this.proxy.sync();
+ },
+
+ // private
+ onDragOver : function(e, id){
+ var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
+ if(this.beforeDragOver(target, e, id) !== false){
+ if(target.isNotifyTarget){
+ var status = target.notifyOver(this, e, this.dragData);
+ this.proxy.setStatus(status);
+ }
+
+ if(this.afterDragOver){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * while the dragged item is over the drop target by providing an implementation.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @method afterDragOver
+ */
+ this.afterDragOver(target, e, id);
+ }
+ }
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * while the dragged item is over the drop target and optionally cancel the onDragOver.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+ */
+ beforeDragOver : function(target, e, id){
+ return true;
+ },
+
+ // private
+ onDragOut : function(e, id){
+ var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
+ if(this.beforeDragOut(target, e, id) !== false){
+ if(target.isNotifyTarget){
+ target.notifyOut(this, e, this.dragData);
+ }
+ this.proxy.reset();
+ if(this.afterDragOut){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * after the dragged item is dragged out of the target without dropping.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @method afterDragOut
+ */
+ this.afterDragOut(target, e, id);
+ }
+ }
+ this.cachedTarget = null;
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action before the dragged
+ * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+ */
+ beforeDragOut : function(target, e, id){
+ return true;
+ },
+
+ // private
+ onDragDrop : function(e, id){
+ var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
+ if(this.beforeDragDrop(target, e, id) !== false){
+ if(target.isNotifyTarget){
+ if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
+ this.onValidDrop(target, e, id);
+ }else{
+ this.onInvalidDrop(target, e, id);
+ }
+ }else{
+ this.onValidDrop(target, e, id);
+ }
+
+ if(this.afterDragDrop){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * after a valid drag drop has occurred by providing an implementation.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dropped element
+ * @method afterDragDrop
+ */
+ this.afterDragDrop(target, e, id);
+ }
+ }
+ delete this.cachedTarget;
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action before the dragged
+ * item is dropped onto the target and optionally cancel the onDragDrop.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
+ */
+ beforeDragDrop : function(target, e, id){
+ return true;
+ },
+
+ // private
+ onValidDrop : function(target, e, id){
+ this.hideProxy();
+ if(this.afterValidDrop){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * after a valid drop has occurred by providing an implementation.
+ * @param {Object} target The target DD
+ * @param {Event} e The event object
+ * @param {String} id The id of the dropped element
+ * @method afterInvalidDrop
+ */
+ this.afterValidDrop(target, e, id);
+ }
+ },
+
+ // private
+ getRepairXY : function(e, data){
+ return this.el.getXY();
+ },
+
+ // private
+ onInvalidDrop : function(target, e, id){
+ this.beforeInvalidDrop(target, e, id);
+ if(this.cachedTarget){
+ if(this.cachedTarget.isNotifyTarget){
+ this.cachedTarget.notifyOut(this, e, this.dragData);
+ }
+ this.cacheTarget = null;
+ }
+ this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
+
+ if(this.afterInvalidDrop){
+ /**
+ * An empty function by default, but provided so that you can perform a custom action
+ * after an invalid drop has occurred by providing an implementation.
+ * @param {Event} e The event object
+ * @param {String} id The id of the dropped element
+ * @method afterInvalidDrop
+ */
+ this.afterInvalidDrop(e, id);
+ }
+ },
+
+ // private
+ afterRepair : function(){
+ if(Ext.enableFx){
+ this.el.highlight(this.hlColor || "c3daf9");
+ }
+ this.dragging = false;
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action after an invalid
+ * drop has occurred.
+ * @param {Ext.dd.DragDrop} target The drop target
+ * @param {Event} e The event object
+ * @param {String} id The id of the dragged element
+ * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
+ */
+ beforeInvalidDrop : function(target, e, id){
+ return true;
+ },
+
+ // private
+ handleMouseDown : function(e){
+ if(this.dragging) {
+ return;
+ }
+ var data = this.getDragData(e);
+ if(data && this.onBeforeDrag(data, e) !== false){
+ this.dragData = data;
+ this.proxy.stop();
+ Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
+ }
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action before the initial
+ * drag event begins and optionally cancel it.
+ * @param {Object} data An object containing arbitrary data to be shared with drop targets
+ * @param {Event} e The event object
+ * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+ */
+ onBeforeDrag : function(data, e){
+ return true;
+ },
+
+ /**
+ * An empty function by default, but provided so that you can perform a custom action once the initial
+ * drag event has begun. The drag cannot be canceled from this function.
+ * @param {Number} x The x position of the click on the dragged object
+ * @param {Number} y The y position of the click on the dragged object
+ */
+ onStartDrag : Ext.emptyFn,
+
+ // private override
+ startDrag : function(x, y){
+ this.proxy.reset();
+ this.dragging = true;
+ this.proxy.update("");
+ this.onInitDrag(x, y);
+ this.proxy.show();
+ },
+
+ // private
+ onInitDrag : function(x, y){
+ var clone = this.el.dom.cloneNode(true);
+ clone.id = Ext.id(); // prevent duplicate ids
+ this.proxy.update(clone);
+ this.onStartDrag(x, y);
+ return true;
+ },
+
+ /**
+ * Returns the drag source's underlying {@link Ext.dd.StatusProxy}
+ * @return {Ext.dd.StatusProxy} proxy The StatusProxy
+ */
+ getProxy : function(){
+ return this.proxy;
+ },
+
+ /**
+ * Hides the drag source's {@link Ext.dd.StatusProxy}
+ */
+ hideProxy : function(){
+ this.proxy.hide();
+ this.proxy.reset(true);
+ this.dragging = false;
+ },
+
+ // private
+ triggerCacheRefresh : function(){
+ Ext.dd.DDM.refreshCache(this.groups);
+ },
+
+ // private - override to prevent hiding
+ b4EndDrag: function(e) {
+ },
+
+ // private - override to prevent moving
+ endDrag : function(e){
+ this.onEndDrag(this.dragData, e);
+ },
+
+ // private
+ onEndDrag : function(data, e){
+ },
+
+ // private - pin to cursor
+ autoOffset : function(x, y) {
+ this.setDelta(-12, -20);
+ },
+
+ destroy: function(){
+ Ext.dd.DragSource.superclass.destroy.call(this);
+ Ext.destroy(this.proxy);
+ }
+});/**
+ * @class Ext.dd.DropTarget
+ * @extends Ext.dd.DDTarget
+ * A simple class that provides the basic implementation needed to make any element a drop target that can have
+ * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
+ * @constructor
+ * @param {Mixed} el The container element
+ * @param {Object} config
+ */
+Ext.dd.DropTarget = function(el, config){
+ this.el = Ext.get(el);
+
+ Ext.apply(this, config);
+
+ if(this.containerScroll){
+ Ext.dd.ScrollManager.register(this.el);
+ }
+
+ Ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
+ {isTarget: true});
+
+};
+
+Ext.extend(Ext.dd.DropTarget, Ext.dd.DDTarget, {
+ /**
+ * @cfg {String} ddGroup
+ * A named drag drop group to which this object belongs. If a group is specified, then this object will only
+ * interact with other drag drop objects in the same group (defaults to undefined).
+ */
+ /**
+ * @cfg {String} overClass
+ * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
+ */
+ /**
+ * @cfg {String} dropAllowed
+ * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+ */
+ dropAllowed : "x-dd-drop-ok",
+ /**
+ * @cfg {String} dropNotAllowed
+ * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+ */
+ dropNotAllowed : "x-dd-drop-nodrop",
+
+ // private
+ isTarget : true,
+
+ // private
+ isNotifyTarget : true,
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source is now over the
+ * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
+ * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ notifyEnter : function(dd, e, data){
+ if(this.overClass){
+ this.el.addClass(this.overClass);
+ }
+ return this.dropAllowed;
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the target.
+ * This method will be called on every mouse movement while the drag source is over the drop target.
+ * This default implementation simply returns the dropAllowed config value.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ notifyOver : function(dd, e, data){
+ return this.dropAllowed;
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source has been dragged
+ * out of the target without dropping. This default implementation simply removes the CSS class specified by
+ * overClass (if any) from the drop element.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ */
+ notifyOut : function(dd, e, data){
+ if(this.overClass){
+ this.el.removeClass(this.overClass);
+ }
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the dragged item has
+ * been dropped on it. This method has no default implementation and returns false, so you must provide an
+ * implementation that does something to process the drop event and returns true so that the drag source's
+ * repair action does not run.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {Boolean} True if the drop was valid, else false
+ */
+ notifyDrop : function(dd, e, data){
+ return false;
+ }
+});/**
+ * @class Ext.dd.DragZone
+ * @extends Ext.dd.DragSource
+ * <p>This class provides a container DD instance that allows dragging of multiple child source nodes.</p>
+ * <p>This class does not move the drag target nodes, but a proxy element which may contain
+ * any DOM structure you wish. The DOM element to show in the proxy is provided by either a
+ * provided implementation of {@link #getDragData}, or by registered draggables registered with {@link Ext.dd.Registry}</p>
+ * <p>If you wish to provide draggability for an arbitrary number of DOM nodes, each of which represent some
+ * application object (For example nodes in a {@link Ext.DataView DataView}) then use of this class
+ * is the most efficient way to "activate" those nodes.</p>
+ * <p>By default, this class requires that draggable child nodes are registered with {@link Ext.dd.Registry}.
+ * However a simpler way to allow a DragZone to manage any number of draggable elements is to configure
+ * the DragZone with an implementation of the {@link #getDragData} method which interrogates the passed
+ * mouse event to see if it has taken place within an element, or class of elements. This is easily done
+ * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a
+ * {@link Ext.DomQuery} selector. For example, to make the nodes of a DataView draggable, use the following
+ * technique. Knowledge of the use of the DataView is required:</p><pre><code>
+myDataView.on('render', function(v) {
+ myDataView.dragZone = new Ext.dd.DragZone(v.getEl(), {
+
+// On receipt of a mousedown event, see if it is within a DataView node.
+// Return a drag data object if so.
+ getDragData: function(e) {
+
+// Use the DataView's own itemSelector (a mandatory property) to
+// test if the mousedown is within one of the DataView's nodes.
+ var sourceEl = e.getTarget(v.itemSelector, 10);
+
+// If the mousedown is within a DataView node, clone the node to produce
+// a ddel element for use by the drag proxy. Also add application data
+// to the returned data object.
+ if (sourceEl) {
+ d = sourceEl.cloneNode(true);
+ d.id = Ext.id();
+ return {
+ ddel: d,
+ sourceEl: sourceEl,
+ repairXY: Ext.fly(sourceEl).getXY(),
+ sourceStore: v.store,
+ draggedRecord: v.{@link Ext.DataView#getRecord getRecord}(sourceEl)
+ }
+ }
+ },
+
+// Provide coordinates for the proxy to slide back to on failed drag.
+// This is the original XY coordinates of the draggable element captured
+// in the getDragData method.
+ getRepairXY: function() {
+ return this.dragData.repairXY;
+ }
+ });
+});</code></pre>
+ * See the {@link Ext.dd.DropZone DropZone} documentation for details about building a DropZone which
+ * cooperates with this DragZone.
+ * @constructor
+ * @param {Mixed} el The container element
+ * @param {Object} config
+ */
+Ext.dd.DragZone = function(el, config){
+ Ext.dd.DragZone.superclass.constructor.call(this, el, config);
+ if(this.containerScroll){
+ Ext.dd.ScrollManager.register(this.el);
+ }
+};
+
+Ext.extend(Ext.dd.DragZone, Ext.dd.DragSource, {
+ /**
+ * This property contains the data representing the dragged object. This data is set up by the implementation
+ * of the {@link #getDragData} method. It must contain a <tt>ddel</tt> property, but can contain
+ * any other data according to the application's needs.
+ * @type Object
+ * @property dragData
+ */
+ /**
+ * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
+ * for auto scrolling during drag operations.
+ */
+ /**
+ * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
+ * method after a failed drop (defaults to "c3daf9" - light blue)
+ */
+
+ /**
+ * Called when a mousedown occurs in this container. Looks in {@link Ext.dd.Registry}
+ * for a valid target to drag based on the mouse down. Override this method
+ * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
+ * object has a "ddel" attribute (with an HTML Element) for other functions to work.
+ * @param {EventObject} e The mouse down event
+ * @return {Object} The dragData
+ */
+ getDragData : function(e){
+ return Ext.dd.Registry.getHandleFromEvent(e);
+ },
+
+ /**
+ * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
+ * this.dragData.ddel
+ * @param {Number} x The x position of the click on the dragged object
+ * @param {Number} y The y position of the click on the dragged object
+ * @return {Boolean} true to continue the drag, false to cancel
+ */
+ onInitDrag : function(x, y){
+ this.proxy.update(this.dragData.ddel.cloneNode(true));
+ this.onStartDrag(x, y);
+ return true;
+ },
+
+ /**
+ * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
+ */
+ afterRepair : function(){
+ if(Ext.enableFx){
+ Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
+ }
+ this.dragging = false;
+ },
+
+ /**
+ * Called before a repair of an invalid drop to get the XY to animate to. By default returns
+ * the XY of this.dragData.ddel
+ * @param {EventObject} e The mouse up event
+ * @return {Array} The xy location (e.g. [100, 200])
+ */
+ getRepairXY : function(e){
+ return Ext.Element.fly(this.dragData.ddel).getXY();
+ }
+});/**
+ * @class Ext.dd.DropZone
+ * @extends Ext.dd.DropTarget
+ * <p>This class provides a container DD instance that allows dropping on multiple child target nodes.</p>
+ * <p>By default, this class requires that child nodes accepting drop are registered with {@link Ext.dd.Registry}.
+ * However a simpler way to allow a DropZone to manage any number of target elements is to configure the
+ * DropZone with an implementation of {@link #getTargetFromEvent} which interrogates the passed
+ * mouse event to see if it has taken place within an element, or class of elements. This is easily done
+ * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a
+ * {@link Ext.DomQuery} selector.</p>
+ * <p>Once the DropZone has detected through calling getTargetFromEvent, that the mouse is over
+ * a drop target, that target is passed as the first parameter to {@link #onNodeEnter}, {@link #onNodeOver},
+ * {@link #onNodeOut}, {@link #onNodeDrop}. You may configure the instance of DropZone with implementations
+ * of these methods to provide application-specific behaviour for these events to update both
+ * application state, and UI state.</p>
+ * <p>For example to make a GridPanel a cooperating target with the example illustrated in
+ * {@link Ext.dd.DragZone DragZone}, the following technique might be used:</p><pre><code>
+myGridPanel.on('render', function() {
+ myGridPanel.dropZone = new Ext.dd.DropZone(myGridPanel.getView().scroller, {
+
+// If the mouse is over a grid row, return that node. This is
+// provided as the "target" parameter in all "onNodeXXXX" node event handling functions
+ getTargetFromEvent: function(e) {
+ return e.getTarget(myGridPanel.getView().rowSelector);
+ },
+
+// On entry into a target node, highlight that node.
+ onNodeEnter : function(target, dd, e, data){
+ Ext.fly(target).addClass('my-row-highlight-class');
+ },
+
+// On exit from a target node, unhighlight that node.
+ onNodeOut : function(target, dd, e, data){
+ Ext.fly(target).removeClass('my-row-highlight-class');
+ },
+
+// While over a target node, return the default drop allowed class which
+// places a "tick" icon into the drag proxy.
+ onNodeOver : function(target, dd, e, data){
+ return Ext.dd.DropZone.prototype.dropAllowed;
+ },
+
+// On node drop we can interrogate the target to find the underlying
+// application object that is the real target of the dragged data.
+// In this case, it is a Record in the GridPanel's Store.
+// We can use the data set up by the DragZone's getDragData method to read
+// any data we decided to attach in the DragZone's getDragData method.
+ onNodeDrop : function(target, dd, e, data){
+ var rowIndex = myGridPanel.getView().findRowIndex(target);
+ var r = myGridPanel.getStore().getAt(rowIndex);
+ Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
+ ' on Record id ' + r.id);
+ return true;
+ }
+ });
+}
+</code></pre>
+ * See the {@link Ext.dd.DragZone DragZone} documentation for details about building a DragZone which
+ * cooperates with this DropZone.
+ * @constructor
+ * @param {Mixed} el The container element
+ * @param {Object} config
+ */
+Ext.dd.DropZone = function(el, config){
+ Ext.dd.DropZone.superclass.constructor.call(this, el, config);
+};
+
+Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {
+ /**
+ * Returns a custom data object associated with the DOM node that is the target of the event. By default
+ * this looks up the event target in the {@link Ext.dd.Registry}, although you can override this method to
+ * provide your own custom lookup.
+ * @param {Event} e The event
+ * @return {Object} data The custom data
+ */
+ getTargetFromEvent : function(e){
+ return Ext.dd.Registry.getTargetFromEvent(e);
+ },
+
+ /**
+ * Called when the DropZone determines that a {@link Ext.dd.DragSource} has entered a drop node
+ * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
+ * This method has no default implementation and should be overridden to provide
+ * node-specific processing if necessary.
+ * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+ * {@link #getTargetFromEvent} for this node)
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ */
+ onNodeEnter : function(n, dd, e, data){
+
+ },
+
+ /**
+ * Called while the DropZone determines that a {@link Ext.dd.DragSource} is over a drop node
+ * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
+ * The default implementation returns this.dropNotAllowed, so it should be
+ * overridden to provide the proper feedback.
+ * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+ * {@link #getTargetFromEvent} for this node)
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ onNodeOver : function(n, dd, e, data){
+ return this.dropAllowed;
+ },
+
+ /**
+ * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dragged out of
+ * the drop node without dropping. This method has no default implementation and should be overridden to provide
+ * node-specific processing if necessary.
+ * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+ * {@link #getTargetFromEvent} for this node)
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ */
+ onNodeOut : function(n, dd, e, data){
+
+ },
+
+ /**
+ * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto
+ * the drop node. The default implementation returns false, so it should be overridden to provide the
+ * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
+ * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+ * {@link #getTargetFromEvent} for this node)
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {Boolean} True if the drop was valid, else false
+ */
+ onNodeDrop : function(n, dd, e, data){
+ return false;
+ },
+
+ /**
+ * Called while the DropZone determines that a {@link Ext.dd.DragSource} is being dragged over it,
+ * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
+ * it should be overridden to provide the proper feedback if necessary.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ onContainerOver : function(dd, e, data){
+ return this.dropNotAllowed;
+ },
+
+ /**
+ * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped on it,
+ * but not on any of its registered drop nodes. The default implementation returns false, so it should be
+ * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
+ * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {Boolean} True if the drop was valid, else false
+ */
+ onContainerDrop : function(dd, e, data){
+ return false;
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source is now over
+ * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
+ * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
+ * you should override this method and provide a custom implementation.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ notifyEnter : function(dd, e, data){
+ return this.dropNotAllowed;
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the drop zone.
+ * This method will be called on every mouse movement while the drag source is over the drop zone.
+ * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
+ * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
+ * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
+ * registered node, it will call {@link #onContainerOver}.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {String} status The CSS class that communicates the drop status back to the source so that the
+ * underlying {@link Ext.dd.StatusProxy} can be updated
+ */
+ notifyOver : function(dd, e, data){
+ var n = this.getTargetFromEvent(e);
+ if(!n){ // not over valid drop target
+ if(this.lastOverNode){
+ this.onNodeOut(this.lastOverNode, dd, e, data);
+ this.lastOverNode = null;
+ }
+ return this.onContainerOver(dd, e, data);
+ }
+ if(this.lastOverNode != n){
+ if(this.lastOverNode){
+ this.onNodeOut(this.lastOverNode, dd, e, data);
+ }
+ this.onNodeEnter(n, dd, e, data);
+ this.lastOverNode = n;
+ }
+ return this.onNodeOver(n, dd, e, data);
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source has been dragged
+ * out of the zone without dropping. If the drag source is currently over a registered node, the notification
+ * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag zone
+ */
+ notifyOut : function(dd, e, data){
+ if(this.lastOverNode){
+ this.onNodeOut(this.lastOverNode, dd, e, data);
+ this.lastOverNode = null;
+ }
+ },
+
+ /**
+ * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the dragged item has
+ * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
+ * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
+ * otherwise it will call {@link #onContainerDrop}.
+ * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
+ * @param {Event} e The event
+ * @param {Object} data An object containing arbitrary data supplied by the drag source
+ * @return {Boolean} True if the drop was valid, else false
+ */
+ notifyDrop : function(dd, e, data){
+ if(this.lastOverNode){
+ this.onNodeOut(this.lastOverNode, dd, e, data);
+ this.lastOverNode = null;
+ }
+ var n = this.getTargetFromEvent(e);
+ return n ?
+ this.onNodeDrop(n, dd, e, data) :
+ this.onContainerDrop(dd, e, data);
+ },
+
+ // private
+ triggerCacheRefresh : function(){
+ Ext.dd.DDM.refreshCache(this.groups);
+ }
+});/**
+ * @class Ext.Element
+ */
+Ext.Element.addMethods({
+ /**
+ * Initializes a {@link Ext.dd.DD} drag drop object for this element.
+ * @param {String} group The group the DD object is member of
+ * @param {Object} config The DD config object
+ * @param {Object} overrides An object containing methods to override/implement on the DD object
+ * @return {Ext.dd.DD} The DD object
+ */
+ initDD : function(group, config, overrides){
+ var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);
+ return Ext.apply(dd, overrides);
+ },
+
+ /**
+ * Initializes a {@link Ext.dd.DDProxy} object for this element.
+ * @param {String} group The group the DDProxy object is member of
+ * @param {Object} config The DDProxy config object
+ * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
+ * @return {Ext.dd.DDProxy} The DDProxy object
+ */
+ initDDProxy : function(group, config, overrides){
+ var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);
+ return Ext.apply(dd, overrides);
+ },
+
+ /**
+ * Initializes a {@link Ext.dd.DDTarget} object for this element.
+ * @param {String} group The group the DDTarget object is member of
+ * @param {Object} config The DDTarget config object
+ * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
+ * @return {Ext.dd.DDTarget} The DDTarget object
+ */
+ initDDTarget : function(group, config, overrides){
+ var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);
+ return Ext.apply(dd, overrides);
+ }