grapesjs_codeapps
Version:
Free and Open Source Web Builder Framework/SC Modification
1,043 lines (918 loc) • 28.8 kB
JavaScript
import Backbone from 'backbone';
import { isString, isFunction, isArray } from 'underscore';
import { on, off, matches, getElement } from 'utils/mixins';
const $ = Backbone.$;
module.exports = Backbone.View.extend({
initialize(opt) {
this.opt = opt || {};
_.bindAll(
this,
'startSort',
'onMove',
'endMove',
'rollback',
'udpateOffset',
'moveDragHelper'
);
var o = opt || {};
this.elT = 0;
this.elL = 0;
this.borderOffset = o.borderOffset || 10;
var el = o.container;
this.el = typeof el === 'string' ? document.querySelector(el) : el;
this.$el = $(this.el);
this.containerSel = o.containerSel || 'div';
this.itemSel = o.itemSel || 'div';
this.draggable = o.draggable || true;
this.nested = o.nested || 0;
this.pfx = o.pfx || '';
this.ppfx = o.ppfx || '';
this.freezeClass = o.freezeClass || this.pfx + 'freezed';
this.onStart = o.onStart || '';
this.onEndMove = o.onEndMove || '';
this.direction = o.direction || 'v'; // v (vertical), h (horizontal), a (auto)
this.onMoveClb = o.onMove || '';
this.relative = o.relative || 0;
this.ignoreViewChildren = o.ignoreViewChildren || 0;
this.ignoreModels = o.ignoreModels || 0;
this.plh = o.placer || '';
// Frame offset
this.wmargin = o.wmargin || 0;
this.offTop = o.offsetTop || 0;
this.offLeft = o.offsetLeft || 0;
this.document = o.document || document;
this.$document = $(this.document);
this.dropContent = null;
this.em = o.em || '';
this.dragHelper = null;
this.canvasRelative = o.canvasRelative || 0;
this.selectOnEnd = !o.avoidSelectOnEnd;
if (this.em && this.em.on) {
this.em.on('change:canvasOffset', this.udpateOffset);
this.udpateOffset();
}
},
getContainerEl() {
if (!this.el) {
var el = this.opt.container;
this.el = typeof el === 'string' ? document.querySelector(el) : el;
this.$el = $(this.el);
}
return this.el;
},
getDocuments() {
const em = this.em;
const canvasDoc = em && em.get('Canvas').getBody().ownerDocument;
const docs = [document];
canvasDoc && docs.push(canvasDoc);
return docs;
},
/**
* Triggered when the offset of the editro is changed
*/
udpateOffset() {
var offset = this.em.get('canvasOffset');
this.offTop = offset.top;
this.offLeft = offset.left;
},
/**
* Set content to drop
* @param {String|Object} content
*/
setDropContent(content) {
this.dropContent = content;
},
/**
* Toggle cursor while sorting
* @param {Boolean} active
*/
toggleSortCursor(active) {
var em = this.em;
var body = document.body;
var pfx = this.ppfx || this.pfx;
var sortCls = pfx + 'grabbing';
var emBody = em ? em.get('Canvas').getBody() : '';
// Avoid updating body className as it causes a huge repaint
// Noticeable with "fast" drag of blocks
if (active) {
em && em.get('Canvas').startAutoscroll();
//body.className += ' ' + sortCls;
//if (em) emBody.className += ' ' + sortCls;
} else {
em && em.get('Canvas').stopAutoscroll();
//body.className = body.className.replace(sortCls, '').trim();
//if(em) emBody.className = emBody.className.replace(sortCls, '').trim();
}
},
/**
* Set drag helper
* @param {HTMLElement} el
* @param {Event} event
*/
setDragHelper(el, event) {
const ev = event || '';
const clonedEl = el.cloneNode(1);
const rect = el.getBoundingClientRect();
const computed = getComputedStyle(el);
let style = '';
for (var i = 0; i < computed.length; i++) {
const prop = computed[i];
style += `${prop}:${computed.getPropertyValue(prop)};`;
}
document.body.appendChild(clonedEl);
clonedEl.className += ` ${this.pfx}bdrag`;
clonedEl.setAttribute('style', style);
this.dragHelper = clonedEl;
clonedEl.style.width = `${rect.width}px`;
clonedEl.style.height = `${rect.height}px`;
ev && this.moveDragHelper(ev);
// Listen mouse move events
if (this.em) {
$(this.em.get('Canvas').getBody().ownerDocument)
.off('mousemove', this.moveDragHelper)
.on('mousemove', this.moveDragHelper);
}
$(document)
.off('mousemove', this.moveDragHelper)
.on('mousemove', this.moveDragHelper);
},
/**
* Update the position of the helper
* @param {Event} e
*/
moveDragHelper(e) {
const doc = e.target.ownerDocument;
if (!this.dragHelper || !doc) {
return;
}
let posY = e.pageY;
let posX = e.pageX;
let addTop = 0;
let addLeft = 0;
const window = doc.defaultView || doc.parentWindow;
const frame = window.frameElement;
const dragHelperStyle = this.dragHelper.style;
// If frame is present that means mouse has moved over the editor's canvas,
// which is rendered inside the iframe and the mouse move event comes from
// the iframe, not the parent window. Mouse position relative to the frame's
// parent window needs to account for the frame's position relative to the
// parent window.
if (frame) {
const frameRect = frame.getBoundingClientRect();
addTop = frameRect.top + document.documentElement.scrollTop;
addLeft = frameRect.left + document.documentElement.scrollLeft;
posY = e.clientY;
posX = e.clientX;
}
dragHelperStyle.top = posY + addTop + 'px';
dragHelperStyle.left = posX + addLeft + 'px';
},
/**
* Returns true if the element matches with selector
* @param {Element} el
* @param {String} selector
* @return {Boolean}
*/
matches(el, selector, useBody) {
return matches.call(el, selector);
},
/**
* Closest parent
* @param {Element} el
* @param {String} selector
* @return {Element|null}
*/
closest(el, selector) {
if (!el) return;
var elem = el.parentNode;
while (elem && elem.nodeType === 1) {
if (this.matches(elem, selector)) return elem;
elem = elem.parentNode;
}
return null;
},
/**
* Get the offset of the element
* @param {HTMLElement} el
* @return {Object}
*/
offset(el) {
var rect = el.getBoundingClientRect();
return {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
};
},
/**
* Create placeholder
* @return {HTMLElement}
*/
createPlaceholder() {
var pfx = this.pfx;
var el = document.createElement('div');
var ins = document.createElement('div');
el.className = pfx + 'placeholder';
el.style.display = 'none';
el.style['pointer-events'] = 'none';
ins.className = pfx + 'placeholder-int';
el.appendChild(ins);
return el;
},
/**
* Picking component to move
* @param {HTMLElement} src
* */
startSort(src) {
const em = this.em;
const itemSel = this.itemSel;
const contSel = this.containerSel;
const container = this.getContainerEl();
const docs = this.getDocuments();
const onStart = this.onStart;
let srcModel;
let plh = this.plh;
this.dropModel = null;
this.moved = 0;
// Check if the start element is a valid one, if not get the
// closest valid one
if (src && !this.matches(src, `${itemSel}, ${contSel}`)) {
src = this.closest(src, itemSel);
}
this.eV = src;
// Create placeholder if not yet exists
if (!plh) {
plh = this.createPlaceholder();
container.appendChild(plh);
this.plh = plh;
}
if (src) {
srcModel = this.getSourceModel(src);
srcModel && srcModel.set && srcModel.set('status', 'freezed');
}
on(container, 'mousemove dragover', this.onMove);
on(docs, 'mouseup dragend touchend', this.endMove);
on(docs, 'keydown', this.rollback);
onStart && onStart();
// Avoid strange effects on dragging
em && em.clearSelection();
this.toggleSortCursor(1);
em && em.trigger('sorter:drag:start', src, srcModel);
},
/**
* Get the model from HTMLElement target
* @return {Model|null}
*/
getTargetModel(el) {
let elem = el || this.target;
return $(elem).data('model');
},
/**
* Get the model of the current source element (element to drag)
* @return {Model}
*/
getSourceModel(source) {
var src = source || this.eV;
let dropContent = this.dropContent;
let dropModel = this.dropModel;
const em = this.em;
if (dropContent && em) {
if (!dropModel) {
let comps = em.get('DomComponents').getComponents();
const opts = {
avoidStore: 1,
avoidChildren: 1,
avoidUpdateStyle: 1,
temporary: 1
};
let tempModel = comps.add(dropContent, opts);
dropModel = comps.remove(tempModel, opts);
this.dropModel = dropModel instanceof Array ? dropModel[0] : dropModel;
}
return dropModel;
}
if (src) {
return $(src).data('model');
}
},
/**
* Highlight target
* @param {Model|null} model
*/
selectTargetModel(model) {
if (model instanceof Backbone.Collection) {
return;
}
var prevModel = this.targetModel;
if (prevModel) {
prevModel.set('status', '');
}
if (model && model.set) {
model.set('status', 'selected-parent');
this.targetModel = model;
}
},
/**
* During move
* @param {Event} e
* */
onMove(e) {
const em = this.em;
this.moved = 1;
// Turn placeholder visibile
var plh = this.plh;
var dsp = plh.style.display;
//if (!dsp || dsp === 'none') plh.style.display = 'block';
// Cache all necessary positions
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;
var rY = e.pageY - this.elT + this.el.scrollTop;
var rX = e.pageX - this.elL + this.el.scrollLeft;
if (this.canvasRelative && em) {
var mousePos = em.get('Canvas').getMouseRelativeCanvas(e);
rX = mousePos.x;
rY = mousePos.y;
}
this.rX = rX;
this.rY = rY;
this.eventMove = e;
//var targetNew = this.getTargetFromEl(e.target);
const dims = this.dimsFromTarget(e.target, rX, rY);
const target = this.target;
const targetModel = this.getTargetModel(target);
this.selectTargetModel(targetModel);
if (!targetModel) plh.style.display = 'none';
this.lastDims = dims;
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);
// 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 = 1;
}
if (typeof this.onMoveClb === 'function') this.onMoveClb(e);
em &&
em.trigger('sorter:drag', {
target,
targetModel,
dims,
pos,
x: rX,
y: rY
});
},
/**
* Returns true if the elements is in flow, so is not in flow where
* for example the component is with float:left
* @param {HTMLElement} el
* @param {HTMLElement} parent
* @return {Boolean}
* @private
* */
isInFlow(el, parent) {
if (!el) return false;
parent = parent || document.body;
var ch = -1,
h;
var elem = el;
h = elem.offsetHeight;
if (/*h < ch || */ !this.styleInFlow(elem, parent)) return false;
else return true;
},
/**
* Check if el has style to be in flow
* @param {HTMLElement} el
* @param {HTMLElement} parent
* @return {Boolean}
* @private
*/
styleInFlow(el, parent) {
var style = el.style;
var $el = $(el);
if (style.overflow && style.overflow !== 'visible') return;
if ($el.css('float') !== 'none') return;
if (parent && $(parent).css('display') == 'flex') return;
switch (style.position) {
case 'static':
case 'relative':
case '':
break;
default:
return;
}
switch (el.tagName) {
case 'TR':
case 'TBODY':
case 'THEAD':
case 'TFOOT':
return true;
}
switch ($el.css('display')) {
case 'block':
case 'list-item':
case 'table':
case 'flex':
return true;
}
return;
},
/**
* Check if the target is valid with the actual source
* @param {HTMLElement} trg
* @return {Boolean}
*/
validTarget(trg, src) {
let srcModel = this.getSourceModel(src);
src = srcModel && srcModel.view && srcModel.view.el;
let trgModel = this.getTargetModel(trg);
trg = trgModel && trgModel.view && trgModel.view.el;
let result = {
valid: true,
src,
srcModel,
trg,
trgModel
};
if (!src || !trg) {
result.valid = false;
return result;
}
// Check if the target could accept the source
let droppable = trgModel.get('droppable');
droppable = droppable instanceof Backbone.Collection ? 1 : droppable;
droppable = droppable instanceof Array ? droppable.join(', ') : droppable;
result.dropInfo = droppable;
droppable = isString(droppable) ? this.matches(src, droppable) : droppable;
result.droppable = droppable;
// check if the source is draggable in target
let draggable = srcModel.get('draggable');
draggable = draggable instanceof Array ? draggable.join(', ') : draggable;
result.dragInfo = draggable;
draggable = isString(draggable) ? this.matches(trg, draggable) : draggable;
result.draggable = draggable;
if (!droppable || !draggable) {
result.valid = false;
}
return result;
},
/**
* Get dimensions of nodes relative to the coordinates
* @param {HTMLElement} target
* @param {number} rX Relative X position
* @param {number} rY Relative Y position
* @return {Array<Array>}
*/
dimsFromTarget(target, rX, rY) {
const em = this.em;
var dims = [];
if (!target) {
return dims;
}
// Select the first valuable target
if (!this.matches(target, `${this.itemSel}, ${this.containerSel}`)) {
target = this.closest(target, this.itemSel);
}
// If draggable is an array the target will be one of those
if (this.draggable instanceof Array) {
target = this.closest(target, this.draggable.join(','));
}
if (!target) {
return dims;
}
// Check if the target is different from the previous one
if (this.prevTarget && this.prevTarget != target) {
this.prevTarget = null;
}
// New target found
if (!this.prevTarget) {
this.targetP = this.closest(target, this.containerSel);
// Check if the source is valid with the target
let validResult = this.validTarget(target);
em && em.trigger('sorter:drag:validation', validResult);
if (!validResult.valid && this.targetP) {
return this.dimsFromTarget(this.targetP, rX, rY);
}
this.prevTarget = target;
this.prevTargetDim = this.getDim(target);
this.cacheDimsP = this.getChildrenDim(this.targetP);
this.cacheDims = this.getChildrenDim(target);
}
// If the target is the previous one will return the cached dims
if (this.prevTarget == target) dims = this.cacheDims;
// Target when I will drop element to sort
this.target = this.prevTarget;
// Generally, on any new target the poiner enters inside its area and
// triggers nearBorders(), so have to take care of this
if (
this.nearBorders(this.prevTargetDim, rX, rY) ||
(!this.nested && !this.cacheDims.length)
) {
const targetParent = this.targetP;
if (targetParent && this.validTarget(targetParent).valid) {
dims = this.cacheDimsP;
this.target = targetParent;
}
}
this.lastPos = null;
return dims;
},
/**
* Get valid target from element
* This method should replace dimsFromTarget()
* @param {HTMLElement} el
* @return {HTMLElement}
*/
getTargetFromEl(el) {
let target = el;
let targetParent;
let targetPrev = this.targetPrev;
const em = this.em;
const containerSel = this.containerSel;
const itemSel = this.itemSel;
// Select the first valuable target
if (!this.matches(target, `${itemSel}, ${containerSel}`)) {
target = this.closest(target, itemSel);
}
// If draggable is an array the target will be one of those
// TODO check if this options is used somewhere
if (this.draggable instanceof Array) {
target = this.closest(target, this.draggable.join(','));
}
// Check if the target is different from the previous one
if (targetPrev && targetPrev != target) {
this.targetPrev = '';
}
// New target found
if (!this.targetPrev) {
targetParent = this.closest(target, containerSel);
// If the current target is not valid (src/trg reasons) try with
// the parent one (if exists)
const validResult = this.validTarget(target);
em && em.trigger('sorter:drag:validation', validResult);
if (!validResult.valid && targetParent) {
return this.getTargetFromEl(targetParent);
}
this.targetPrev = target;
}
// Generally, on any new target the poiner enters inside its area and
// triggers nearBorders(), so have to take care of this
if (this.nearElBorders(target)) {
targetParent = this.closest(target, containerSel);
if (targetParent && this.validTarget(targetParent).valid) {
target = targetParent;
}
}
return target;
},
/**
* Check if the current pointer is neare to element borders
* @return {Boolen}
*/
nearElBorders(el) {
const off = 10;
const rect = el.getBoundingClientRect();
const body = el.ownerDocument.body;
const { x, y } = this.getCurrentPos();
const top = rect.top + body.scrollTop;
const left = rect.left + body.scrollLeft;
const width = rect.width;
const height = rect.height;
if (
y < top + off || // near top edge
y > top + height - off || // near bottom edge
x < left + off || // near left edge
x > left + width - off // near right edge
) {
return 1;
}
},
getCurrentPos() {
const ev = this.eventMove;
const x = ev.pageX || 0;
const y = ev.pageY || 0;
return { x, y };
},
/**
* Returns dimensions and positions about the element
* @param {HTMLElement} el
* @return {Array<number>}
*/
getDim(el) {
var top, left, height, width;
if (this.canvasRelative && this.em) {
var pos = this.em.get('Canvas').getElementPos(el);
var styles = window.getComputedStyle(el);
var marginTop = parseFloat(styles['marginTop']);
var marginBottom = parseFloat(styles['marginBottom']);
var marginRight = parseFloat(styles['marginRight']);
var marginLeft = parseFloat(styles['marginLeft']);
top = pos.top - marginTop;
left = pos.left - marginLeft;
height = pos.height + marginTop + marginBottom;
width = pos.width + marginLeft + marginRight;
} 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;
}
return [top, left, height, width];
},
/**
* Get children dimensions
* @param {HTMLELement} el Element root
* @retun {Array}
* */
getChildrenDim(trg) {
var dims = [];
if (!trg) return dims;
// Get children based on getChildrenContainer
var trgModel = this.getTargetModel(trg);
if (trgModel && trgModel.view && !this.ignoreViewChildren) {
trg = trgModel.view.getChildrenContainer();
}
var ch = trg.children;
for (var i = 0, len = ch.length; i < len; i++) {
var el = ch[i];
if (!this.matches(el, this.itemSel)) {
continue;
}
var dim = this.getDim(el);
var dir = this.direction;
if (dir == 'v') dir = true;
else if (dir == 'h') dir = false;
else dir = this.isInFlow(el, trg);
dim.push(dir);
dim.push(el);
dims.push(dim);
}
return dims;
},
/**
* Check if the coordinates are near to the borders
* @param {Array<number>} dim
* @param {number} rX Relative X position
* @param {number} rY Relative Y position
* @return {Boolean}
* */
nearBorders(dim, rX, rY) {
var result = 0;
var off = this.borderOffset;
var x = rX || 0;
var y = rY || 0;
var t = dim[0];
var l = dim[1];
var h = dim[2];
var w = dim[3];
if (t + off > y || y > t + h - off || l + off > x || x > l + w - off)
result = 1;
return !!result;
},
/**
* Find the position based on passed dimensions and coordinates
* @param {Array<Array>} dims Dimensions of nodes to parse
* @param {number} posX X coordindate
* @param {number} posY Y coordindate
* @retun {Object}
* */
findPosition(dims, posX, posY) {
var result = { index: 0, method: 'before' };
var leftLimit = 0,
xLimit = 0,
dimRight = 0,
yLimit = 0,
xCenter = 0,
yCenter = 0,
dimDown = 0,
dim = 0;
// Each dim is: Top, Left, Height, Width
for (var i = 0, len = dims.length; i < len; i++) {
dim = dims[i];
// Right position of the element. Left + Width
dimRight = dim[1] + dim[3];
// Bottom position of the element. Top + Height
dimDown = dim[0] + dim[2];
// X center position of the element. Left + (Width / 2)
xCenter = dim[1] + dim[3] / 2;
// Y center position of the element. Top + (Height / 2)
yCenter = dim[0] + dim[2] / 2;
// Skip if over the limits
if (
(xLimit && dim[1] > xLimit) ||
(yLimit && yCenter >= yLimit) || // >= avoid issue with clearfixes
(leftLimit && dimRight < leftLimit)
)
continue;
result.index = i;
// If it's not in flow (like 'float' element)
if (!dim[4]) {
if (posY < dimDown) yLimit = dimDown;
//If x lefter than center
if (posX < xCenter) {
xLimit = xCenter;
result.method = 'before';
} else {
leftLimit = xCenter;
result.method = 'after';
}
} else {
// If y upper than center
if (posY < yCenter) {
result.method = 'before';
break;
} else result.method = 'after'; // After last element
}
}
return result;
},
/**
* Updates the position of the placeholder
* @param {HTMLElement} phl
* @param {Array<Array>} dims
* @param {Object} pos Position object
* @param {Array<number>} trgDim target dimensions
* */
movePlaceholder(plh, dims, pos, trgDim) {
var marg = 0,
t = 0,
l = 0,
w = 0,
h = 0,
un = 'px',
margI = 5,
brdCol = '#62c462',
brd = 3,
method = pos.method;
var elDim = dims[pos.index];
plh.style.borderColor = 'transparent ' + brdCol;
plh.style.borderWidth = brd + un + ' ' + (brd + 2) + un;
plh.style.margin = '-' + brd + 'px 0 0';
if (elDim) {
// If it's not in flow (like 'float' element)
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;
plh.style.borderColor = brdCol + ' transparent';
plh.style.borderWidth = brd + 2 + un + ' ' + brd + un;
plh.style.margin = '0 0 0 -' + brd + 'px';
} else {
w = elDim[3] + un;
h = 'auto';
t = method == 'before' ? elDim[0] - marg : elDim[0] + elDim[2] - marg;
l = elDim[1];
}
} else {
if (!this.nested) {
plh.style.display = 'none';
return;
}
if (trgDim) {
t = trgDim[0] + margI;
l = trgDim[1] + margI;
w = parseInt(trgDim[3]) - margI * 2 + un;
h = 'auto';
}
}
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(e) {
var created;
const moved = [null];
const docs = this.getDocuments();
const container = this.getContainerEl();
const onEndMove = this.onEndMove;
const { target, lastPos } = this;
off(container, 'mousemove dragover', this.onMove);
off(docs, 'mouseup dragend touchend', this.endMove);
off(docs, 'keydown', this.rollback);
//this.$document.off('mouseup', this.endMove);
//this.$document.off('keydown', this.rollback);
this.plh.style.display = 'none';
var clsReg = new RegExp('(?:^|\\s)' + this.freezeClass + '(?!\\S)', 'gi');
let src = this.eV;
if (src && this.selectOnEnd) {
var srcModel = this.getSourceModel();
if (srcModel && srcModel.set) {
srcModel.set('status', '');
srcModel.set('status', 'selected');
}
}
if (this.moved) {
const toMove = this.toMove;
const toMoveArr = isArray(toMove) ? toMove : toMove ? [toMove] : [src];
toMoveArr.forEach(model => {
moved.push(this.move(target, model, lastPos));
});
}
if (this.plh) this.plh.style.display = 'none';
var dragHelper = this.dragHelper;
if (dragHelper) {
dragHelper.parentNode.removeChild(dragHelper);
this.dragHelper = null;
}
this.selectTargetModel();
this.toggleSortCursor();
this.toMove = null;
isFunction(onEndMove) && moved.forEach(m => onEndMove(m, this));
},
/**
* Move component to new position
* @param {HTMLElement} dst Destination target
* @param {HTMLElement} src Element to move
* @param {Object} pos Object with position coordinates
* */
move(dst, src, pos) {
var em = this.em;
const srcEl = getElement(src);
em && em.trigger('component:dragEnd:before', dst, srcEl, pos); // @depricated
var warns = [];
var index = pos.index;
var modelToDrop, modelTemp, created;
var validResult = this.validTarget(dst, srcEl);
var targetCollection = $(dst).data('collection');
var model = validResult.srcModel;
var droppable = validResult.droppable;
var draggable = validResult.draggable;
var dropInfo = validResult.dropInfo;
var dragInfo = validResult.dragInfo;
var dropContent = this.dropContent;
droppable =
validResult.trgModel instanceof Backbone.Collection ? 1 : droppable;
if (targetCollection && droppable && draggable) {
index = pos.method === 'after' ? index + 1 : index;
var opts = { at: index, noIncrement: 1 };
if (!dropContent) {
// Putting `avoidStore` here will make the UndoManager behave wrong
opts.temporary = 1;
modelTemp = targetCollection.add({}, { ...opts });
if (model) {
modelToDrop = model.collection.remove(model);
}
} else {
modelToDrop = dropContent;
opts.silent = false;
opts.avoidUpdateStyle = 1;
}
created = targetCollection.add(modelToDrop, opts);
if (!dropContent) {
targetCollection.remove(modelTemp);
} else {
this.dropContent = null;
}
// This will cause to recalculate children dimensions
this.prevTarget = null;
} else {
if (!targetCollection) {
warns.push('Target collection not found');
}
if (!droppable) {
warns.push(`Target is not droppable, accepts [${dropInfo}]`);
}
if (!draggable) {
warns.push(`Component not draggable, acceptable by [${dragInfo}]`);
}
console.warn('Invalid target position: ' + warns.join(', '));
}
em && em.trigger('component:dragEnd', targetCollection, modelToDrop, warns); // @depricated
em && em.trigger('sorter:drag:end', targetCollection, modelToDrop, warns);
return created;
},
/**
* Rollback to previous situation
* @param {Event}
* @param {Bool} Indicates if rollback in anycase
* */
rollback(e) {
off(this.getDocuments(), 'keydown', this.rollback);
const key = e.which || e.keyCode;
if (key == 27) {
this.moved = 0;
this.endMove();
}
}
});