Browse Source

Setup relative positioning while sorting components

pull/79/merge
Artur Arseniev 9 years ago
parent
commit
492a8805db
  1. 3
      src/block_manager/view/BlocksView.js
  2. 24
      src/canvas/main.js
  3. 294
      src/commands/view/MoveComponent.js
  4. 185
      src/commands/view/SelectPosition.js
  5. 55
      src/utils/Sorter.js

3
src/block_manager/view/BlocksView.js

@ -40,7 +40,8 @@ function(Backbone, BlockView) {
direction: 'a',
wmargin: 1,
nested: 1,
em: this.em
em: this.em,
canvasRelative: 1,
});
}
return this.sorter;

24
src/canvas/main.js

@ -283,8 +283,8 @@ define(function(require) {
var yOffset = subWinOffset ? win.pageYOffset : 0;
var xOffset = subWinOffset ? win.pageXOffset : 0;
if(frame) {
var frameRect = frame.getBoundingClientRect(); // maybe to cache ?!?
if (frame) {
var frameRect = frame.getBoundingClientRect();
addTop = frameRect.top || 0;
addLeft = frameRect.left || 0;
}
@ -295,6 +295,26 @@ define(function(require) {
};
},
/**
* X and Y mouse position relative to the canvas
* @param {Event} e
* @return {Object}
*/
getMouseRelativeCanvas: function (e, options) {
var opts = options || {};
var frame = this.getFrameEl();
var body = this.getBody();
var addTop = frame.offsetTop || 0;
var addLeft = frame.offsetLeft || 0;
var yOffset = body.scrollTop || 0;
var xOffset = body.scrollLeft || 0;
return {
y: e.clientY + addTop + yOffset,
x: e.clientX + addLeft + xOffset,
};
},
/**
* Returns wrapper element
* @return {HTMLElement}

294
src/commands/view/MoveComponent.js

@ -1,148 +1,148 @@
define(['backbone', './SelectComponent','./SelectPosition'],
function(Backbone, SelectComponent, SelectPosition) {
return _.extend({}, SelectPosition, SelectComponent, {
init: function(o){
SelectComponent.init.apply(this, arguments);
_.bindAll(this, 'initSorter','rollback', 'onEndMove');
this.opt = o;
this.hoverClass = this.ppfx + 'highlighter-warning';
this.badgeClass = this.ppfx + 'badge-warning';
this.noSelClass = this.ppfx + 'no-select';
},
enable: function() {
SelectComponent.enable.apply(this, arguments);
this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass);
var wp = this.$wrapper;
wp.css('cursor','move');
wp.on('mousedown', this.initSorter);
// Avoid strange moving behavior
wp.addClass(this.noSelClass);
},
/**
* Overwrite for doing nothing
* @private
*/
toggleClipboard: function(){},
/**
* Delegate sorting
* @param {Event} e
* @private
* */
initSorter: function(e){
var el = $(e.target).data('model');
var drag = el.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
this.startSelectPosition(e.target, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMove.bind(this);
this.stopSelectComponent();
this.$wrapper.off('mousedown', this.initSorter);
this.getContentWindow().on('keydown', this.rollback);
},
/**
* Init sorter from model
* @param {Object} model
* @private
*/
initSorterFromModel: function(model) {
var drag = model.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
var el = model.view.el;
this.startSelectPosition(el, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this);
/*
this.sorter.setDragHelper(el);
var dragHelper = this.sorter.dragHelper;
dragHelper.className = this.ppfx + 'drag-helper';
dragHelper.innerHTML = '';
dragHelper.backgroundColor = 'white';
*/
this.stopSelectComponent();
this.getContentWindow().on('keydown', this.rollback);
},
onEndMoveFromModel: function() {
this.getContentWindow().off('keydown', this.rollback);
},
/**
* Callback after sorting
* @private
*/
onEndMove: function(){
this.enable();
this.getContentWindow().off('keydown', this.rollback);
},
/**
* Say what to do after the component was selected (selectComponent)
* @param {Event} e
* @param {Object} Selected element
* @private
* */
onSelect: function(e,el){},
/**
* Used to bring the previous situation before start moving the component
* @param {Event} e
* @param {Boolean} Indicates if rollback in anycase
* @private
* */
rollback: function(e, force){
var key = e.which || e.keyCode;
if(key == this.opt.ESCAPE_KEY || force){
this.sorter.moved = false;
this.sorter.endMove();
}
return;
},
/**
* Returns badge element
* @return {HTMLElement}
* @private
*/
getBadgeEl: function(){
if(!this.$badge)
this.$badge = $(this.getBadge());
return this.$badge;
},
/**
* Returns highlighter element
* @return {HTMLElement}
* @private
*/
getHighlighterEl: function(){
if(!this.$hl)
this.$hl = $(this.canvas.getHighlighter());
return this.$hl;
},
stop: function(){
SelectComponent.stop.apply(this, arguments);
this.getBadgeEl().removeClass(this.badgeClass);
this.getHighlighterEl().removeClass(this.hoverClass);
var wp = this.$wrapper;
wp.css('cursor', '').unbind().removeClass(this.noSelClass);
}
});
});
function(Backbone, SelectComponent, SelectPosition) {
return _.extend({}, SelectPosition, SelectComponent, {
init: function(o){
SelectComponent.init.apply(this, arguments);
_.bindAll(this, 'initSorter','rollback', 'onEndMove');
this.opt = o;
this.hoverClass = this.ppfx + 'highlighter-warning';
this.badgeClass = this.ppfx + 'badge-warning';
this.noSelClass = this.ppfx + 'no-select';
},
enable: function() {
SelectComponent.enable.apply(this, arguments);
this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass);
var wp = this.$wrapper;
wp.css('cursor','move');
wp.on('mousedown', this.initSorter);
// Avoid strange moving behavior
wp.addClass(this.noSelClass);
},
/**
* Overwrite for doing nothing
* @private
*/
toggleClipboard: function(){},
/**
* Delegate sorting
* @param {Event} e
* @private
* */
initSorter: function(e){
var el = $(e.target).data('model');
var drag = el.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
this.startSelectPosition(e.target, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMove.bind(this);
this.stopSelectComponent();
this.$wrapper.off('mousedown', this.initSorter);
this.getContentWindow().on('keydown', this.rollback);
},
/**
* Init sorter from model
* @param {Object} model
* @private
*/
initSorterFromModel: function(model) {
var drag = model.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
var el = model.view.el;
this.startSelectPosition(el, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this);
/*
this.sorter.setDragHelper(el);
var dragHelper = this.sorter.dragHelper;
dragHelper.className = this.ppfx + 'drag-helper';
dragHelper.innerHTML = '';
dragHelper.backgroundColor = 'white';
*/
this.stopSelectComponent();
this.getContentWindow().on('keydown', this.rollback);
},
onEndMoveFromModel: function() {
this.getContentWindow().off('keydown', this.rollback);
},
/**
* Callback after sorting
* @private
*/
onEndMove: function(){
this.enable();
this.getContentWindow().off('keydown', this.rollback);
},
/**
* Say what to do after the component was selected (selectComponent)
* @param {Event} e
* @param {Object} Selected element
* @private
* */
onSelect: function(e,el){},
/**
* Used to bring the previous situation before start moving the component
* @param {Event} e
* @param {Boolean} Indicates if rollback in anycase
* @private
* */
rollback: function(e, force){
var key = e.which || e.keyCode;
if(key == this.opt.ESCAPE_KEY || force){
this.sorter.moved = false;
this.sorter.endMove();
}
return;
},
/**
* Returns badge element
* @return {HTMLElement}
* @private
*/
getBadgeEl: function(){
if(!this.$badge)
this.$badge = $(this.getBadge());
return this.$badge;
},
/**
* Returns highlighter element
* @return {HTMLElement}
* @private
*/
getHighlighterEl: function(){
if(!this.$hl)
this.$hl = $(this.canvas.getHighlighter());
return this.$hl;
},
stop: function(){
SelectComponent.stop.apply(this, arguments);
this.getBadgeEl().removeClass(this.badgeClass);
this.getHighlighterEl().removeClass(this.hoverClass);
var wp = this.$wrapper;
wp.css('cursor', '').unbind().removeClass(this.noSelClass);
}
});
});

185
src/commands/view/SelectPosition.js

@ -1,102 +1,103 @@
define(function() {
return {
return {
/**
* Start select position event
* @param {HTMLElement} trg
* @private
* */
startSelectPosition: function(trg, doc) {
this.isPointed = false;
var utils = this.editorModel.get('Utils');
if(utils && !this.sorter)
this.sorter = new utils.Sorter({
container: this.getCanvasBody(),
placer: this.canvas.getPlacerEl(),
containerSel: '*',
itemSel: '*',
pfx: this.ppfx,
direction: 'a',
document: doc,
wmargin: 1,
nested: 1,
em: this.editorModel,
});
this.sorter.startSort(trg);
},
/**
* Start select position event
* @param {HTMLElement} trg
* @private
* */
startSelectPosition: function(trg, doc) {
this.isPointed = false;
var utils = this.editorModel.get('Utils');
if(utils && !this.sorter)
this.sorter = new utils.Sorter({
container: this.getCanvasBody(),
placer: this.canvas.getPlacerEl(),
containerSel: '*',
itemSel: '*',
pfx: this.ppfx,
direction: 'a',
document: doc,
wmargin: 1,
nested: 1,
em: this.editorModel,
canvasRelative: 1,
});
this.sorter.startSort(trg);
},
/**
* Get frame position
* @return {Object}
* @private
*/
getOffsetDim: function() {
var frameOff = this.offset(this.canvas.getFrameEl());
var canvasOff = this.offset(this.canvas.getElement());
var top = frameOff.top - canvasOff.top;
var left = frameOff.left - canvasOff.left;
return { top: top, left: left };
},
/**
* Get frame position
* @return {Object}
* @private
*/
getOffsetDim: function() {
var frameOff = this.offset(this.canvas.getFrameEl());
var canvasOff = this.offset(this.canvas.getElement());
var top = frameOff.top - canvasOff.top;
var left = frameOff.left - canvasOff.left;
return { top: top, left: left };
},
/**
* Stop select position event
* @private
* */
stopSelectPosition: function() {
this.posTargetCollection = null;
this.posIndex = this.posMethod=='after' && this.cDim.length!==0 ? this.posIndex + 1 : this.posIndex; //Normalize
if(this.sorter){
this.sorter.moved = 0;
this.sorter.endMove();
}
if(this.cDim){
this.posIsLastEl = this.cDim.length!==0 && this.posMethod=='after' && this.posIndex==this.cDim.length;
this.posTargetEl = (this.cDim.length===0 ? $(this.outsideElem) :
(!this.posIsLastEl && this.cDim[this.posIndex] ? $(this.cDim[this.posIndex][5]).parent() : $(this.outsideElem) ));
this.posTargetModel = this.posTargetEl.data("model");
this.posTargetCollection = this.posTargetEl.data("model-comp");
}
},
/**
* Stop select position event
* @private
* */
stopSelectPosition: function() {
this.posTargetCollection = null;
this.posIndex = this.posMethod=='after' && this.cDim.length!==0 ? this.posIndex + 1 : this.posIndex; //Normalize
if(this.sorter){
this.sorter.moved = 0;
this.sorter.endMove();
}
if(this.cDim){
this.posIsLastEl = this.cDim.length!==0 && this.posMethod=='after' && this.posIndex==this.cDim.length;
this.posTargetEl = (this.cDim.length===0 ? $(this.outsideElem) :
(!this.posIsLastEl && this.cDim[this.posIndex] ? $(this.cDim[this.posIndex][5]).parent() : $(this.outsideElem) ));
this.posTargetModel = this.posTargetEl.data("model");
this.posTargetCollection = this.posTargetEl.data("model-comp");
}
},
/**
* Enabel select position
* @private
*/
enable: function() {
this.startSelectPosition();
},
/**
* Enabel select position
* @private
*/
enable: function() {
this.startSelectPosition();
},
/**
* Check if the pointer is near to the float component
* @param {number} index
* @param {string} method
* @param {Array<Array>} dims
* @return {Boolean}
* @private
* */
nearFloat: function(index, method, dims) {
var i = index || 0;
var m = method || 'before';
var len = dims.length;
var isLast = len !== 0 && m == 'after' && i == len;
if(len !== 0 && (
(!isLast && !dims[i][4]) ||
(dims[i-1] && !dims[i-1][4]) ||
(isLast && !dims[i-1][4]) ) )
return 1;
return 0;
},
/**
* Check if the pointer is near to the float component
* @param {number} index
* @param {string} method
* @param {Array<Array>} dims
* @return {Boolean}
* @private
* */
nearFloat: function(index, method, dims) {
var i = index || 0;
var m = method || 'before';
var len = dims.length;
var isLast = len !== 0 && m == 'after' && i == len;
if(len !== 0 && (
(!isLast && !dims[i][4]) ||
(dims[i-1] && !dims[i-1][4]) ||
(isLast && !dims[i-1][4]) ) )
return 1;
return 0;
},
run: function() {
this.enable();
},
run: function() {
this.enable();
},
stop: function() {
this.stopSelectPosition();
this.$wrapper.css('cursor','');
this.$wrapper.unbind();
}
};
});
stop: function() {
this.stopSelectPosition();
this.$wrapper.css('cursor','');
this.$wrapper.unbind();
}
};
});

55
src/utils/Sorter.js

@ -38,6 +38,7 @@ define(function(require) {
this.dropContent = null;
this.em = o.em || '';
this.dragHelper = null;
this.canvasRelative = o.canvasRelative || 0;
if(this.em && this.em.on){
this.em.on('change:canvasOffset', this.udpateOffset);
@ -269,21 +270,34 @@ define(function(require) {
var eO = this.offset(this.el);
this.elT = this.wmargin ? Math.abs(eO.top) : eO.top;
this.elL = this.wmargin ? Math.abs(eO.left): eO.left;
this.rY = (e.pageY - this.elT) + this.el.scrollTop;
this.rX = (e.pageX - this.elL) + this.el.scrollLeft;
var dims = this.dimsFromTarget(e.target, this.rX, this.rY);
var rY = (e.pageY - this.elT) + this.el.scrollTop;
var rX = (e.pageX - this.elL) + this.el.scrollLeft;
if (this.canvasRelative && this.em) {
var mousePos = this.em.get('Canvas').getMouseRelativeCanvas(e);
rX = mousePos.x;
rY = mousePos.y;
}
var dims = this.dimsFromTarget(e.target, rX, rY);
this.lastDims = dims;
var pos = this.findPosition(dims, this.rX, this.rY);
var pos = this.findPosition(dims, rX, rY);
// If there is a significant changes with the pointer
if( !this.lastPos ||
(this.lastPos.index != pos.index || this.lastPos.method != pos.method)){
this.movePlaceholder(this.plh, dims, pos, this.prevTargetDim);
if(!this.$plh)
this.$plh = $(this.plh);
if(this.offTop)
this.$plh.css('top', '+=' + this.offTop + 'px');
if(this.offLeft)
this.$plh.css('left', '+=' + this.offLeft + 'px');
// With canvasRelative the offset is calculated automatically for
// each element
if (!this.canvasRelative) {
if(this.offTop)
this.$plh.css('top', '+=' + this.offTop + 'px');
if(this.offLeft)
this.$plh.css('left', '+=' + this.offLeft + 'px');
}
this.lastPos = pos;
}
@ -411,11 +425,26 @@ define(function(require) {
* @param {HTMLElement} el
* @return {Array<number>}
*/
getDim: function(el){
var o = this.offset(el);
var top = this.relative ? el.offsetTop : o.top - (this.wmargin ? -1 : 1) * this.elT;
var left = this.relative ? el.offsetLeft : o.left - (this.wmargin ? -1 : 1) * this.elL;
return [top, left, el.offsetHeight, el.offsetWidth];
getDim: function(el) {
var top, left, height, width;
if (this.canvasRelative && this.em) {
var pos = this.em.get('Canvas').getElementPos(el);
top = pos.top;
left = pos.left;
height = pos.height;
width = pos.width;
} else {
var o = this.offset(el);
top = this.relative ? el.offsetTop : o.top - (this.wmargin ? -1 : 1) * this.elT;
left = this.relative ? el.offsetLeft : o.left - (this.wmargin ? -1 : 1) * this.elL;
height = el.offsetHeight;
width = el.offsetWidth;
}
//console.log('get dim', top, left, this.canvasRelative);
return [top, left, height, width];
},
/**

Loading…
Cancel
Save