/**
@name Edo.managers.DragManager
@class
@single
@description 拖拽管理器.在拖拽过程中,会在拖拽对象上激发dragstart等拖拽事件
@example
*/
Edo.managers.DragManager = {
drops: {},
event: null,
dragObject: null,
dropObject: null, //当enableDrop=true时,此属性可能为有值
dragData: null,
alpha: .5,
isDragging: false,
enableFeedback: false,
feedback: 'none',
drag: null,
/**
@name Edo.managers.DragManager#startDrag
@function
@param {Object} config 拖拽配置对象
@description 启动拖拽器
{
enableDrop: false, //是否允许投放操作
dragObject: null, //启动拖拽器的组件对象,必须从UIComponent派生,
dragData: null, //拖拽的数据
event: e, //当前鼠标事件对象
xOffset: 0, //偏移
yOffset: 0,
alpha: 1, //拖拽物透明度
proxy: true //拖拽代理元素:true:自身的拷贝,false:自身,dom:拖拽dom元素
}
*/
startDrag: function(cfg){
//1)proxy: true:自身的拷贝,false:自身,dom:拖拽dom元素
//2)enableDrop: 是否投放
//dragObject: UIComplete:启动拖拽的组件,dom
//dragData: 拖拽数据
//event: 当前鼠标事件对象
//xOffset: //不传值,则自动计算
//yOffset:
//alpha: 拖拽代理的透明度(默认0.5)
//feedback: 表明此次拖拽的操作效果:copy,move,none ?
if(!cfg.dragObject) throw new Error("必须有拖拽启动对象");
if(!cfg.event) throw new Error("必须有拖拽初始事件对象");
if(cfg.event.button != 0) return false;
if(this.isDragging){
this.drag.stop(this.event);
}
this.enableDrop = this.proxy = this.now = this.drag = this.dropObject = this.dragObject = this.dragData = this.event = this.xOffset = this.yOffset = null;
drag = new Edo.util.Drag({
delay: this.delay,
capture: this.capture,
onStart: this.onStart.bind(this),
onMove: this.onMove.bind(this),
onStop: this.onStop.bind(this)
});
this.drag = drag;
Edo.apply(this, cfg, {
delay: 80,
capture: false,
ondragstart: Edo.emptyFn,
ondragmove: Edo.emptyFn,
ondragcomplete: Edo.emptyFn,
ondropenter: Edo.emptyFn,
ondropover: Edo.emptyFn,
ondropout: Edo.emptyFn,
ondropmove: Edo.emptyFn,
ondragdrop: Edo.emptyFn
});
this.initEvent = this.event;
drag.start(this.event);
},
/**
@name Edo.managers.DragManager#acceptDragDrop
@function
@description 当一个拖拽器移动到一个组件上时, 是否进行允许投放操作
*/
acceptDragDrop: function(){
this.canDrop = true;
},
/**
@name Edo.managers.DragManager#regDrop
@function
@description 注册投放区Drop对象
*/
regDrop: function(cmp){
this.drops[cmp.id] = cmp;
},
/**
@name Edo.managers.DragManager#unregDrop
@function
@description 注销投放区Drop对象
*/
unregDrop: function(cmp){
delete this.drops[cmp.id];
},
//private
fire: function(e, o){
var dm = Edo.managers.DragManager;
//计算出elxy
dm.xy = [dm.now[0]+dm.xOffset, dm.now[1]+dm.yOffset];
Edo.apply(e, dm);
o = o || dm.dragObject;
if(o.el){
o.fireEvent(e.type, e);
}else{
Edo.util.Dom.fireEvent(o, e.type, e);
}
e['on'+e.type].c(dm, e);
//status = e.xy;
//dm.now = e.now;//修改坐标的关键
dm.now = [e.xy[0] - dm.xOffset, e.xy[1] - dm.yOffset];
//status = dm.xy;
},
findDrop: function(e, t){
t = t || e.target;
while(t && t !== document){
//这里可以优化:将所有drop保存一个idHash,就不需要for,而直接判断是否有了.
for(var id in this.drops){
var drop = this.drops[id];
var el = drop.el || drop;
if(el === t) {
return drop;
}
}
t = t.parentNode;
}
},
onStart: function(drag){
this.event = drag.event;
this.now = drag.now;
this.el = this.dragObject.el || this.dragObject;
var xy = Edo.util.Dom.getXY(this.el);
this.initXY = xy;
if(!this.xOffset && this.xOffset !== 0) this.xOffset = xy[0] - drag.now[0];
if(!this.yOffset && this.yOffset !== 0) this.yOffset = xy[1] - drag.now[1];
this.isDragging = true;
this.fire({
type: 'dragstart',
source: this
});
if(this.proxy === true){
this.proxy = this.el.cloneNode(false);
//this.proxy.className = 'e-dragdrop-proxy';
Edo.util.Dom.setStyle(this.proxy, this.proxyStyle);
Edo.util.Dom.addClass(this.proxy, this.proxyCls);
document.body.appendChild(this.proxy);
var size = Edo.util.Dom.getSize(this.el);
Edo.util.Dom.setSize(this.proxy, size.width, size.height);
this.removeProxy = true;
}else if(!this.proxy){
this.proxy = this.el;
}
this._zIndex = Edo.util.Dom.getStyle(this.proxy, 'z-index');
this._opacity = 1;//Edo.util.Dom.getOpacity(this.proxy);
Edo.util.Dom.setStyle(this.proxy, 'z-index', 9999999);
Edo.util.Dom.setOpacity(this.proxy, this.alpha);
var position = Edo.util.Dom.getStyle(this.proxy, 'position');
if(position != 'relative' && position != 'absolute'){
this.proxy.style.position = 'relative';
}
Edo.util.Dom.setStyle(this.proxy, this.dragStyle);
Edo.util.Dom.setXY(this.proxy, xy);
this.leftTop = [parseInt(Edo.util.Dom.getStyle(this.proxy,'left')) || 0, parseInt(Edo.util.Dom.getStyle(this.proxy,'top')) || 0];
//document.title= new Date();
},
onMove: function(drag){
if(!this.isDragging) return;
this.event = drag.event;
this.now = drag.now;
this.move = true;
//先激发dragmove事件,监听dragmove,修改drag.now,则可以改变拖拽的坐标
this.fire({
type: 'dragmove',
source: this
});
//Edo.util.Dom.setXY(this.proxy, [drag.now[0] + this.xOffset, drag.now[1] + this.yOffset ]);
if(this.move !== false && this.proxy){
var s = this.proxy.style;
s.left = (this.now[0] + this.xOffset - this.initXY[0] + this.leftTop[0]) + 'px';
s.top = (this.now[1] + this.yOffset - this.initXY[1] + this.leftTop[1]) + 'px';
}
if(this.enableDrop){
var el = this.event.target;
//处理!!!
var display = this.proxy.style.display;
this.proxy.style.display = 'none';
el = document.elementFromPoint(this.now[0], this.now[1]);
while(el && el != document){
if(el.tagName) break;
el = el.parentNode;
}
this.proxy.style.display = display;
var now = this.dropObject; //保存当前的drop
this.dropObject = null;
//这个循环是必要的!不要轻易去掉
while(el && el !== document){
var drop = this.findDrop.call(this, this.event, el);
if(!drop) { //没找到新drop,则退出
if(now){
this.dropObject = now;
this.fire({
type: 'dropout',
source: this.dropObject
}, this.dropObject);
}
this.dropObject = null;
break;
}
this.dropObject = drop; //将新drop赋予dropObject,并测试,如果通过,则break
if(drop == now) break; //如果原来的drop和新的drop是同一个,则不需要进行置换
//如果这个等式成立,那么drop原先已经经过dropenter判断过了.
this.canDrop = false;
this.fire({
type: 'dropenter',
source: this.dropObject
}, this.dropObject);
if(this.canDrop){
if(now){
this.dropObject = now;
this.fire({ //激发旧drop的out
type: 'dropout',
source: this.dropObject
}, this.dropObject);
}
this.dropObject = drop;
this.fire({ //激发新drop的over
type: 'dropover',
source: this.dropObject
}, this.dropObject);
break;
}else{
el = (drop.el || drop).parentNode; //没通过,继续循环
}
}
}
//dropmove,当有drop对象时激发
if(this.dropObject){
this.fire({
type: 'dropmove',
source: this.dropObject
}, this.dropObject);
}
},
onStop: function(drag){
if(!this.isDragging) return ;
this.event = drag.event;
this.now = drag.now;
this.onMove(drag);
if(this.dropObject){
this.fire({
type: 'dropout',
source: this.dropObject
}, this.dropObject);
this.fire({
type: 'dragdrop',
source: this.dropObject
}, this.dropObject);
}
var xy = [this.now[0] + this.xOffset, this.now[1] + this.yOffset ];
if(this.autoDragDrop){
if(this.dragObject.set){
this.dragObject.set('XY', xy);
}else{
Edo.util.Dom.setXY(this.dragObject, xy);
}
}
this.fire({
type: 'dragcomplete',
source: this
});
this.isDragging = false;
this.alpha = .5;
//this.now = this.drag = this.dropObject = this.dragObject = this.dragData = this.event = this.xOffset = this.yOffset = null;
this.xy = this.enableDrop = this.now = this.drag = this.dropObject = this.dragObject = this.dragData = this.event = this.xOffset = this.yOffset = null;
//this.proxy.style.position = this._position;
Edo.util.Dom.setStyle(this.proxy, 'z-index', this._zIndex);
Edo.util.Dom.setOpacity(this.proxy, this._opacity);
if(this.el !== this.proxy && this.removeProxy) {
Edo.util.Dom.remove(this.proxy);
this.removeProxy = false;
}
this.proxy = null;
}
};
Edo.managers.DragProxy = function(cfg){
Edo.apply(this, cfg,{
feedback: 'no', //copy,move,no,yes,add,none,between,preend,append
html: ' '
});
};
Edo.managers.DragProxy.prototype = {
setFeedback: function(feedback){
if(this.feedback != feedback){
Edo.util.Dom.removeClass(this.el, this.getFeedbackCls(this.feedback));
this.feedback = feedback;
Edo.util.Dom.addClass(this.el, this.getFeedbackCls(this.feedback));
}
},
setHtml: function(html){
this.innerEl.innerHTML = html;
},
getFeedbackCls: function(value){
return 'e-dragproxy-'+value;
},
render: function(p){
this.el = Edo.util.Dom.append(p || document.body,
'