mirror of https://github.com/artf/grapesjs.git
7 changed files with 58 additions and 351 deletions
@ -1,330 +0,0 @@ |
|||
define(['backbone'], |
|||
function(Backbone) { |
|||
/** |
|||
* @class ItemSort |
|||
* */ |
|||
return Backbone.View.extend({ |
|||
|
|||
initialize: function(o) { |
|||
_.bindAll(this,'startMove','onMove','endMove','rollback', 'itemLeft'); |
|||
this.config = o.config || {}; |
|||
this.pfx = o.config.stylePrefix; |
|||
this.itemClass = '.' + this.pfx + this.config.itemClass; |
|||
this.itemsClass = '.' + this.pfx + this.config.itemsClass; |
|||
this.setElement('.'+this.pfx+this.config.containerId); |
|||
}, |
|||
|
|||
/** |
|||
* Picking component to move |
|||
* @param {Object} Element view |
|||
* @param {Object} Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
startMove: function(eV, e){ |
|||
this.moved = false; |
|||
this.eV = eV; |
|||
this.$sel = this.eV.$el; |
|||
this.$selParent = this.$sel.closest(this.itemsClass); |
|||
|
|||
// In case the component selected is not draggable
|
|||
if( !eV.model.get('draggable') ) |
|||
return; |
|||
|
|||
// Create placeholder if not exists
|
|||
if(!this.$plh){ |
|||
var pfx = this.pfx; |
|||
this.$plh = $('<div>', {id: pfx + 'placeholder'}).css({'pointer-events':'none'}).hide(); |
|||
this.$plh.append( $('<div>', {id: pfx + "plh-int", class: pfx + 'insert'} ) ); |
|||
|
|||
if(!this.$el.length) |
|||
this.$el = $('.'+this.pfx+this.config.containerId); |
|||
|
|||
this.$plh.appendTo(this.$el); |
|||
} |
|||
this.$plh.data('hide',1); |
|||
eV.freeze(); |
|||
this.$el.on('mousemove',this.onMove); |
|||
$(document).on('mouseup',this.endMove); |
|||
$(document).on('keypress',this.rollback); |
|||
}, |
|||
|
|||
/** |
|||
* Get children dimensions |
|||
* @param {Object} Parent element |
|||
* |
|||
* @retun {Array} |
|||
* */ |
|||
getChildrenDim: function(el){ |
|||
var dim = [], |
|||
p = el || this.$targetEl.parent(), |
|||
oT = this.elT, |
|||
oL = this.elL, |
|||
ch = p.children('.' + this.pfx + this.config.itemClass); |
|||
ch.each(function(){ |
|||
var $el = $(this), |
|||
$elO = $el.offset(); |
|||
dim.push( [ $elO.top - oT, $elO.left - oL, $el.outerHeight(), $el.outerWidth(), true, this]); |
|||
}); |
|||
return dim; |
|||
}, |
|||
|
|||
/** |
|||
* During move |
|||
* @param {Object} Event |
|||
* |
|||
* @return void |
|||
* */ |
|||
onMove: function(e){ |
|||
this.moved = true; |
|||
|
|||
if(this.$plh.data('hide')){ |
|||
this.$plh.show(); |
|||
this.$plh.data('hide',0); |
|||
} |
|||
var eO = this.$el.offset(); |
|||
this.elT = eO.top; |
|||
this.elL = eO.left; |
|||
this.rY = (e.pageY - this.elT) + this.$el.scrollTop(); |
|||
this.rX = (e.pageX - this.elL) + this.$el.scrollLeft(); |
|||
this.inspect(e); |
|||
this.updatePosition(this.rX, this.rY); |
|||
var actualPos = this.posIndex+':'+this.posMethod; |
|||
|
|||
//If there is a significant changes with the pointer
|
|||
if(!this.lastPos || (this.lastPos != actualPos)){ |
|||
this.updatePlaceholderPos(this.posIndex, this.posMethod); |
|||
this.lastPos = this.posIndex+':'+this.posMethod; |
|||
} |
|||
//Working alternative for find taget element
|
|||
//var $targetEl = this.$selParent.children('.'+this.pfx+this.config.itemClass).eq(this.aIndex);
|
|||
}, |
|||
|
|||
/** |
|||
* Search where to put placeholder |
|||
* @param int X position of the mouse |
|||
* @param int Y position of the mouse |
|||
* @retun void |
|||
* */ |
|||
updatePosition: function( posX, posY ){ |
|||
this.posMethod = "before"; |
|||
this.posIndex = 0; |
|||
var leftLimit = 0, xLimit = 0, dimRight = 0, yLimit = 0, xCenter = 0, yCenter = 0, dimDown = 0, dim = 0; |
|||
for(var i = 0; i < this.cDim.length; i++){ //Dim => t,l,h,w
|
|||
dim = this.cDim[i]; |
|||
dimDown = dim[0] + dim[2]; |
|||
yCenter = dim[0] + (dim[2] / 2); //Horizontal center
|
|||
xCenter = dim[1] + (dim[3] / 2); //Vertical center
|
|||
dimRight = dim[1] + dim[3]; |
|||
if( (xLimit && dim[1] > xLimit) || (yLimit && yCenter > yLimit) || |
|||
(leftLimit && dimRight < leftLimit)) //No need with this one if over the limit
|
|||
continue; |
|||
if(!dim[4]){ //If it's not inFlow (like float element)
|
|||
if( posY < dimDown) |
|||
yLimit = dimDown; |
|||
if( posX < xCenter){ //If mouse lefter than center
|
|||
xLimit = xCenter; |
|||
this.posMethod = "before"; |
|||
}else{ |
|||
leftLimit = xCenter; |
|||
this.posMethod = "after"; |
|||
} |
|||
this.posIndex = i; |
|||
}else{ |
|||
this.posIndex = this.aIndex = i; |
|||
if( posY < yCenter ){ //If mouse upper than center
|
|||
this.posMethod = "before"; //Should place helper before
|
|||
if(posY < dim[0]) |
|||
this.aIndex = i - 1; |
|||
break; //No need to continue under inFlow element
|
|||
}else |
|||
this.posMethod = "after"; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Updates the position of the placeholder |
|||
* @param int Index of the nearest child |
|||
* @param str Before or after position |
|||
* @return void |
|||
* */ |
|||
updatePlaceholderPos: function(index, method){ |
|||
var marg = 0, t = 0, l = 0, w = 0, h = 0, |
|||
un = 'px', |
|||
margI = 5, |
|||
plh = this.$plh[0]; |
|||
if( this.cDim[index] ){ |
|||
var elDim = this.cDim[index]; |
|||
//If it's like with 'float' style
|
|||
if(!elDim[4]){ |
|||
w = 'auto'; |
|||
h = elDim[2] - (marg * 2) + un; |
|||
t = elDim[0] + marg; |
|||
l = (method == 'before') ? (elDim[1] - marg) : (elDim[1] + elDim[3] - marg); |
|||
}else{ |
|||
//w = '100%';
|
|||
w = elDim[3] + un; |
|||
//h = elDim[3] + un;
|
|||
t = (method == 'before') ? (elDim[0] - marg) : (elDim[0] + elDim[2] - marg); |
|||
l = elDim[1]; |
|||
} |
|||
}else{ |
|||
if(this.$targetEl){ |
|||
var trg = this.$targetEl[0], |
|||
$elO = this.$targetEl.offset(); |
|||
t = $elO.top - this.elT + margI + 17; |
|||
l = $elO.left - this.elL + margI * 7; |
|||
w = (parseInt(trg.offsetWidth) - margI * 14) + un; |
|||
} |
|||
} |
|||
plh.style.top = t + un; |
|||
plh.style.left = l + un; |
|||
if(w) |
|||
plh.style.width = w; |
|||
if(h) |
|||
plh.style.height = h; |
|||
}, |
|||
|
|||
/** |
|||
* Leave item |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
endMove: function(e){ |
|||
this.$el.off('mousemove',this.onMove); |
|||
$(document).off('mouseup', this.endMove); |
|||
$(document).off('keypress', this.rollback); |
|||
this.eV.unfreeze(); |
|||
this.$plh.hide(); |
|||
if(this.moved) |
|||
this.move(this.$targetEl, this.$sel, this.posIndex, this.posMethod); |
|||
this.itemLeft(); |
|||
}, |
|||
|
|||
/** |
|||
* Move component to new position |
|||
* @param {Object} Component to move |
|||
* @param {Object} Target component |
|||
* @param {Integer} Indicates the position inside the collection |
|||
* @param {String} Before of after component |
|||
* |
|||
* @return void |
|||
* */ |
|||
move: function(target, el, posIndex, method){ |
|||
var trg = target|| this.$targetEl; |
|||
trg = trg || this.$backupEl; |
|||
if(!trg) |
|||
return; |
|||
var index = posIndex || 0; |
|||
var model = el.data("model"); |
|||
var collection = model.collection; |
|||
var targetModel = trg.data('model'); |
|||
var targetCollection = targetModel.collection; |
|||
|
|||
if(!this.cDim.length) |
|||
targetCollection = targetModel.get('components'); |
|||
|
|||
if(targetCollection && targetModel.get('droppable')){ |
|||
index = method == 'after' ? index + 1 : index; |
|||
var modelTemp = targetCollection.add({style:{}}, { at: index}); |
|||
var modelRemoved = collection.remove(model, { silent:false }); |
|||
targetCollection.add(modelRemoved, { at: index, silent:false }); |
|||
targetCollection.remove(modelTemp); |
|||
}else |
|||
console.warn("Invalid target position"); |
|||
}, |
|||
|
|||
/** |
|||
* Track inside which element pointer entered |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
inspect: function(e){ |
|||
var item = $(e.target).closest(this.itemClass); |
|||
if(!this.$targetEl || (item.length && item[0] != this.$targetEl[0]) ){ |
|||
this.status = 1; |
|||
if(item.length){ |
|||
this.$targetEl = this.$backupEl = item; |
|||
this.$targetElP = this.$targetEl.parent(); |
|||
this.$targetsEl = this.$targetEl.find(this.itemsClass + ':first'); |
|||
this.$targetEl.on('mouseleave', this.itemLeft); |
|||
this.targetM = this.$targetEl.data('model'); |
|||
this.dimT = this.getTargetDim(this.$targetEl[0]); |
|||
this.cDim = this.getChildrenDim(); |
|||
} |
|||
}else if( this.nearToBorders(this.$targetEl[0]) || this.$targetEl[0] == this.$sel[0] ){ |
|||
if(this.status == 1){ |
|||
this.status = 2; |
|||
this.lastPos = null; |
|||
this.cDim = this.getChildrenDim(this.$targetElP); |
|||
} |
|||
}else if( !this.nearToBorders(this.$targetEl[0]) ){ |
|||
if(this.status == 2){ |
|||
this.status = 1; |
|||
this.lastPos = null; |
|||
} |
|||
this.cDim = []; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when pointer leaves item |
|||
* @param event |
|||
* |
|||
* @return void |
|||
* */ |
|||
itemLeft: function(e){ |
|||
if(this.$targetEl){ |
|||
this.$targetEl.off('mouseleave',this.itemLeft); |
|||
this.$targetEl = null; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Returns dimension of the target |
|||
* @param Event |
|||
* |
|||
* @return Array |
|||
* */ |
|||
getTargetDim: function(e){ |
|||
var $el = $(e), |
|||
$elO = $el.offset(); |
|||
return [ $elO.top - this.elT, $elO.left - this.elL, $el.outerHeight(), $el.outerWidth() ]; |
|||
}, |
|||
|
|||
/** |
|||
* Check if pointer is near to the borders of the target |
|||
* @param event |
|||
* @return Bool |
|||
* */ |
|||
nearToBorders: function(e){ |
|||
var m = 10; //Limit in pixels for be near
|
|||
if(!this.dimT) |
|||
return; |
|||
var dimT = this.dimT; |
|||
if( ((dimT[0] + m) > this.rY) || (this.rY > (dimT[0] + dimT[2] - m)) || |
|||
((dimT[1] + m) > this.rX) || (this.rX > (dimT[1] + dimT[3] - m)) ) |
|||
return 1; |
|||
else |
|||
return 0; |
|||
}, |
|||
|
|||
/** |
|||
* Rollback to previous situation |
|||
* @param Event |
|||
* @param Bool Indicates if rollback in anycase |
|||
* @return void |
|||
* */ |
|||
rollback: function(e, force){ |
|||
var key = e.which || e.keyCode; |
|||
if(key == 27 || force){ |
|||
this.moved = false; |
|||
this.endMove(); |
|||
} |
|||
return; |
|||
}, |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue