/**
* A simple class that provides the basic implementation needed to make any element draggable.
*/
Ext.define('Ext.dd.DragSource', {
extend: 'Ext.dd.DDProxy',
requires: [
'Ext.dd.StatusProxy',
'Ext.dd.DragDropManager'
],
/**
* @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.
*/
/**
* @property {Object} dragData
* 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 ddel property,
* but can contain any other data according to the application's needs.
*/
/**
* @cfg {String} dropAllowed
* The CSS class returned to the drag source when drop is allowed.
*/
dropAllowed: Ext.baseCSSPrefix + 'dd-drop-ok',
/**
* @cfg {String} dropNotAllowed
* The CSS class returned to the drag source when drop is not allowed.
*/
dropNotAllowed: Ext.baseCSSPrefix + 'dd-drop-nodrop',
/**
* @cfg {Boolean} animRepair
* If true, animates the proxy element back to the position of the handle element used to
* trigger the drag.
*/
animRepair: true,
/**
* @cfg {String} repairHighlightColor
* The color to use when visually highlighting the drag source in the afterRepair
* method after a failed drop (defaults to light blue). The color must be a 6 digit hex value,
* without a preceding '#'.
*/
repairHighlightColor: 'c3daf9',
/**
* Creates new drag-source.
* @param {String/HTMLElement/Ext.dom.Element} el The container element or ID of it.
* @param {Object} config (optional) Config object.
*/
constructor: 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({
id: this.el.id + '-drag-status-proxy',
animRepair: this.animRepair
});
}
this.callParent(
[this.el.dom, this.ddGroup || this.group,
{ dragElId: this.proxy.id, resizeFrame: false, isTarget: false,
scroll: this.scroll === true }]
);
this.dragging = false;
},
/**
* 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.DragDropManager.getDDById(id),
status;
this.cachedTarget = target;
if (this.beforeDragEnter(target, e, id) !== false) {
if (target.isNotifyTarget) {
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
* @template
*/
beforeDragEnter: function(target, e, id) {
return true;
},
/**
* @private
*/
onDragOver: function(e, id) {
var target = this.cachedTarget || Ext.dd.DragDropManager.getDDById(id),
status;
if (this.beforeDragOver(target, e, id) !== false) {
if (target.isNotifyTarget) {
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
* @template
*/
beforeDragOver: function(target, e, id) {
return true;
},
/**
* @private
*/
onDragOut: function(e, id) {
var target = this.cachedTarget || Ext.dd.DragDropManager.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
* @template
*/
beforeDragOut: function(target, e, id) {
return true;
},
/**
* @private
*/
onDragDrop: function(e, id) {
var target = this.cachedTarget || Ext.dd.DragDropManager.getDDById(id);
if (this.beforeDragDrop(target, e, id) !== false) {
if (target.isNotifyTarget) {
if (target.notifyDrop(this, e, this.dragData) !== false) { // 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
* @template
*/
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 afterValidDrop
*/
this.afterValidDrop(target, e, id);
}
},
/**
* @private
*/
getRepairXY: function(e, data) {
return this.el.getXY();
},
/**
* @private
*/
onInvalidDrop: function(target, e, id) {
// This method may be called by the DragDropManager.
// To preserve backwards compat, it only passes the event object
// Here we correct the arguments.
var me = this;
if (!e) {
e = target;
target = null;
id = e.getTarget().id;
}
if (me.beforeInvalidDrop(target, e, id) !== false) {
if (me.cachedTarget) {
if (me.cachedTarget.isNotifyTarget) {
me.cachedTarget.notifyOut(me, e, me.dragData);
}
me.cacheTarget = null;
}
me.proxy.repair(me.getRepairXY(e, me.dragData), me.afterRepair, me);
if (me.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
*/
me.afterInvalidDrop(e, id);
}
}
},
/**
* @private
*/
afterRepair: function() {
var me = this;
if (Ext.enableFx) {
me.el.highlight(me.repairHighlightColor);
}
me.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
* @template
*/
beforeInvalidDrop: function(target, e, id) {
return true;
},
/**
* @private
*/
handleMouseDown: function(e) {
var data;
if (this.dragging) {
return;
}
data = this.getDragData(e);
if (data && this.onBeforeDrag(data, e) !== false) {
this.dragData = data;
this.proxy.stop();
this.callParent(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
* @template
*/
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
* @method
* @template
*/
onStartDrag: Ext.emptyFn,
alignElWithMouse: function() {
this.proxy.ensureAttachedToBody(true);
return this.callParent(arguments);
},
/**
* @private
*/
startDrag: function(x, y) {
this.proxy.reset();
this.proxy.hidden = false;
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
*/
b4EndDrag: function(e) {
},
/**
* @private
*/
endDrag: function(e) {
this.onEndDrag(this.dragData, e);
},
/**
* @private
*/
onEndDrag: function(data, e) {
},
/**
* @private
*/
autoOffset: function(x, y) {
this.setDelta(-12, -20);
},
destroy: function() {
Ext.destroy(this.proxy);
this.callParent();
}
});