|
|
@ -1,6 +1,6 @@ |
|
|
import Backbone from 'backbone'; |
|
|
import Backbone from 'backbone'; |
|
|
import { isString, isFunction, isArray, result } from 'underscore'; |
|
|
import { isString, isFunction, isArray, result } from 'underscore'; |
|
|
import { on, off, matches, getElement } from 'utils/mixins'; |
|
|
import { on, off, matches, getElement, getPointerEvent } from 'utils/mixins'; |
|
|
const $ = Backbone.$; |
|
|
const $ = Backbone.$; |
|
|
|
|
|
|
|
|
module.exports = Backbone.View.extend({ |
|
|
module.exports = Backbone.View.extend({ |
|
|
@ -51,6 +51,7 @@ module.exports = Backbone.View.extend({ |
|
|
this.canvasRelative = o.canvasRelative || 0; |
|
|
this.canvasRelative = o.canvasRelative || 0; |
|
|
this.selectOnEnd = !o.avoidSelectOnEnd; |
|
|
this.selectOnEnd = !o.avoidSelectOnEnd; |
|
|
this.scale = o.scale; |
|
|
this.scale = o.scale; |
|
|
|
|
|
this.activeTextModel = null; |
|
|
|
|
|
|
|
|
if (this.em && this.em.on) { |
|
|
if (this.em && this.em.on) { |
|
|
this.em.on('change:canvasOffset', this.udpateOffset); |
|
|
this.em.on('change:canvasOffset', this.udpateOffset); |
|
|
@ -96,6 +97,34 @@ module.exports = Backbone.View.extend({ |
|
|
this.dropContent = content; |
|
|
this.dropContent = content; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
updateTextViewCursorPosition(e) { |
|
|
|
|
|
const Canvas = this.em.get('Canvas'); |
|
|
|
|
|
const targetDoc = Canvas.getDocument(); |
|
|
|
|
|
let range = null; |
|
|
|
|
|
|
|
|
|
|
|
if (targetDoc.caretRangeFromPoint) { |
|
|
|
|
|
// Chrome
|
|
|
|
|
|
const poiner = getPointerEvent(e); |
|
|
|
|
|
range = targetDoc.caretRangeFromPoint(poiner.clientX, poiner.clientY); |
|
|
|
|
|
} else if (e.rangeParent) { |
|
|
|
|
|
// Firefox
|
|
|
|
|
|
range = targetDoc.createRange(); |
|
|
|
|
|
range.setStart(e.rangeParent, e.rangeOffset); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const sel = Canvas.getWindow().getSelection(); |
|
|
|
|
|
Canvas.getFrameEl().focus(); |
|
|
|
|
|
sel.removeAllRanges(); |
|
|
|
|
|
range && sel.addRange(range); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
setContentEditable(model, mode) { |
|
|
|
|
|
if (model) { |
|
|
|
|
|
const el = model.getEl(); |
|
|
|
|
|
if (el.contentEditable != mode) el.contentEditable = mode; |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Toggle cursor while sorting |
|
|
* Toggle cursor while sorting |
|
|
* @param {Boolean} active |
|
|
* @param {Boolean} active |
|
|
@ -308,30 +337,40 @@ module.exports = Backbone.View.extend({ |
|
|
* Get the model of the current source element (element to drag) |
|
|
* Get the model of the current source element (element to drag) |
|
|
* @return {Model} |
|
|
* @return {Model} |
|
|
*/ |
|
|
*/ |
|
|
getSourceModel(source) { |
|
|
getSourceModel(source, { target, avoidChildren = 1 } = {}) { |
|
|
var src = source || this.eV; |
|
|
const { em, eV } = this; |
|
|
let dropContent = this.dropContent; |
|
|
const src = source || eV; |
|
|
let dropModel = this.dropModel; |
|
|
let { dropModel, dropContent } = this; |
|
|
const em = this.em; |
|
|
const isTextable = src => |
|
|
|
|
|
src && |
|
|
|
|
|
target && |
|
|
|
|
|
src.opt.avoidChildren && |
|
|
|
|
|
this.isTextableActive(src, target); |
|
|
|
|
|
|
|
|
if (dropContent && em) { |
|
|
if (dropContent && em) { |
|
|
|
|
|
if (isTextable(dropModel)) { |
|
|
|
|
|
dropModel = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (!dropModel) { |
|
|
if (!dropModel) { |
|
|
let comps = em.get('DomComponents').getComponents(); |
|
|
const comps = em.get('DomComponents').getComponents(); |
|
|
const opts = { |
|
|
const opts = { |
|
|
|
|
|
avoidChildren, |
|
|
avoidStore: 1, |
|
|
avoidStore: 1, |
|
|
avoidChildren: 1, |
|
|
|
|
|
avoidUpdateStyle: 1 |
|
|
avoidUpdateStyle: 1 |
|
|
}; |
|
|
}; |
|
|
let tempModel = comps.add(dropContent, { ...opts, temporary: 1 }); |
|
|
const tempModel = comps.add(dropContent, { ...opts, temporary: 1 }); |
|
|
dropModel = comps.remove(tempModel, opts); |
|
|
dropModel = comps.remove(tempModel, opts); |
|
|
this.dropModel = dropModel instanceof Array ? dropModel[0] : dropModel; |
|
|
this.dropModel = dropModel instanceof Array ? dropModel[0] : dropModel; |
|
|
|
|
|
|
|
|
|
|
|
if (isTextable(dropModel)) { |
|
|
|
|
|
return this.getSourceModel(src, { target, avoidChildren: 0 }); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
return dropModel; |
|
|
return dropModel; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (src) { |
|
|
return src && $(src).data('model'); |
|
|
return $(src).data('model'); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -359,11 +398,11 @@ module.exports = Backbone.View.extend({ |
|
|
* @param {Event} e |
|
|
* @param {Event} e |
|
|
* */ |
|
|
* */ |
|
|
onMove(e) { |
|
|
onMove(e) { |
|
|
const em = this.em; |
|
|
const ev = e; |
|
|
|
|
|
const { em, onMoveClb, plh } = this; |
|
|
this.moved = 1; |
|
|
this.moved = 1; |
|
|
|
|
|
|
|
|
// Turn placeholder visibile
|
|
|
// Turn placeholder visibile
|
|
|
var plh = this.plh; |
|
|
|
|
|
var dsp = plh.style.display; |
|
|
var dsp = plh.style.display; |
|
|
if (!dsp || dsp === 'none') plh.style.display = 'block'; |
|
|
if (!dsp || dsp === 'none') plh.style.display = 'block'; |
|
|
|
|
|
|
|
|
@ -385,6 +424,7 @@ module.exports = Backbone.View.extend({ |
|
|
this.eventMove = e; |
|
|
this.eventMove = e; |
|
|
|
|
|
|
|
|
//var targetNew = this.getTargetFromEl(e.target);
|
|
|
//var targetNew = this.getTargetFromEl(e.target);
|
|
|
|
|
|
const sourceModel = this.getSourceModel(); |
|
|
const dims = this.dimsFromTarget(e.target, rX, rY); |
|
|
const dims = this.dimsFromTarget(e.target, rX, rY); |
|
|
const target = this.target; |
|
|
const target = this.target; |
|
|
const targetModel = this.getTargetModel(target); |
|
|
const targetModel = this.getTargetModel(target); |
|
|
@ -392,26 +432,39 @@ module.exports = Backbone.View.extend({ |
|
|
if (!targetModel) plh.style.display = 'none'; |
|
|
if (!targetModel) plh.style.display = 'none'; |
|
|
|
|
|
|
|
|
this.lastDims = dims; |
|
|
this.lastDims = dims; |
|
|
var pos = this.findPosition(dims, rX, rY); |
|
|
const 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'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.isTextableActive(sourceModel, targetModel)) { |
|
|
|
|
|
this.activeTextModel = targetModel; |
|
|
|
|
|
this.setContentEditable(targetModel, true); |
|
|
|
|
|
|
|
|
|
|
|
plh.style.display = 'none'; |
|
|
this.lastPos = pos; |
|
|
this.lastPos = pos; |
|
|
|
|
|
this.updateTextViewCursorPosition(ev); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.disableTextable(); |
|
|
|
|
|
this.activeTextModel = null; |
|
|
|
|
|
|
|
|
|
|
|
// 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 = pos; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof this.onMoveClb === 'function') this.onMoveClb(e); |
|
|
isFunction(onMoveClb) && onMoveClb(e); |
|
|
|
|
|
|
|
|
em && |
|
|
em && |
|
|
em.trigger('sorter:drag', { |
|
|
em.trigger('sorter:drag', { |
|
|
@ -424,6 +477,15 @@ module.exports = Backbone.View.extend({ |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
isTextableActive(src, trg) { |
|
|
|
|
|
return src && src.get('textable') && trg && trg.is('text'); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
disableTextable() { |
|
|
|
|
|
const { activeTextModel } = this; |
|
|
|
|
|
activeTextModel && activeTextModel.getView().disableEditing(); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Returns true if the elements is in flow, so is not in flow where |
|
|
* Returns true if the elements is in flow, so is not in flow where |
|
|
* for example the component is with float:left |
|
|
* for example the component is with float:left |
|
|
@ -495,9 +557,9 @@ module.exports = Backbone.View.extend({ |
|
|
* @return {Boolean} |
|
|
* @return {Boolean} |
|
|
*/ |
|
|
*/ |
|
|
validTarget(trg, src) { |
|
|
validTarget(trg, src) { |
|
|
let srcModel = this.getSourceModel(src); |
|
|
const trgModel = this.getTargetModel(trg); |
|
|
|
|
|
const srcModel = this.getSourceModel(src, { target: trgModel }); |
|
|
src = srcModel && srcModel.view && srcModel.view.el; |
|
|
src = srcModel && srcModel.view && srcModel.view.el; |
|
|
let trgModel = this.getTargetModel(trg); |
|
|
|
|
|
trg = trgModel && trgModel.view && trgModel.view.el; |
|
|
trg = trgModel && trgModel.view && trgModel.view.el; |
|
|
let result = { |
|
|
let result = { |
|
|
valid: true, |
|
|
valid: true, |
|
|
@ -512,21 +574,23 @@ module.exports = Backbone.View.extend({ |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
|
|
// Check if the target could accept the source
|
|
|
// Check if the target could accept the source
|
|
|
let droppable = trgModel.get('droppable'); |
|
|
let droppable = trgModel.get('droppable'); |
|
|
droppable = droppable instanceof Backbone.Collection ? 1 : droppable; |
|
|
droppable = droppable instanceof Backbone.Collection ? 1 : droppable; |
|
|
droppable = droppable instanceof Array ? droppable.join(', ') : droppable; |
|
|
droppable = droppable instanceof Array ? droppable.join(', ') : droppable; |
|
|
result.dropInfo = droppable; |
|
|
result.dropInfo = droppable; |
|
|
droppable = isString(droppable) ? this.matches(src, droppable) : droppable; |
|
|
droppable = isString(droppable) ? this.matches(src, droppable) : droppable; |
|
|
|
|
|
droppable = |
|
|
|
|
|
draggable && this.isTextableActive(srcModel, trgModel) ? 1 : droppable; |
|
|
result.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) { |
|
|
if (!droppable || !draggable) { |
|
|
result.valid = false; |
|
|
result.valid = false; |
|
|
} |
|
|
} |
|
|
@ -914,7 +978,6 @@ module.exports = Backbone.View.extend({ |
|
|
* @return void |
|
|
* @return void |
|
|
* */ |
|
|
* */ |
|
|
endMove(e) { |
|
|
endMove(e) { |
|
|
var created; |
|
|
|
|
|
const moved = [null]; |
|
|
const moved = [null]; |
|
|
const docs = this.getDocuments(); |
|
|
const docs = this.getDocuments(); |
|
|
const container = this.getContainerEl(); |
|
|
const container = this.getContainerEl(); |
|
|
@ -923,10 +986,7 @@ module.exports = Backbone.View.extend({ |
|
|
off(container, 'mousemove dragover', this.onMove); |
|
|
off(container, 'mousemove dragover', this.onMove); |
|
|
off(docs, 'mouseup dragend touchend', this.endMove); |
|
|
off(docs, 'mouseup dragend touchend', this.endMove); |
|
|
off(docs, 'keydown', this.rollback); |
|
|
off(docs, 'keydown', this.rollback); |
|
|
//this.$document.off('mouseup', this.endMove);
|
|
|
|
|
|
//this.$document.off('keydown', this.rollback);
|
|
|
|
|
|
this.plh.style.display = 'none'; |
|
|
this.plh.style.display = 'none'; |
|
|
var clsReg = new RegExp('(?:^|\\s)' + this.freezeClass + '(?!\\S)', 'gi'); |
|
|
|
|
|
let src = this.eV; |
|
|
let src = this.eV; |
|
|
|
|
|
|
|
|
if (src && this.selectOnEnd) { |
|
|
if (src && this.selectOnEnd) { |
|
|
@ -953,6 +1013,7 @@ module.exports = Backbone.View.extend({ |
|
|
this.dragHelper = null; |
|
|
this.dragHelper = null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.disableTextable(); |
|
|
this.selectTargetModel(); |
|
|
this.selectTargetModel(); |
|
|
this.toggleSortCursor(); |
|
|
this.toggleSortCursor(); |
|
|
|
|
|
|
|
|
@ -967,7 +1028,7 @@ module.exports = Backbone.View.extend({ |
|
|
* @param {Object} pos Object with position coordinates |
|
|
* @param {Object} pos Object with position coordinates |
|
|
* */ |
|
|
* */ |
|
|
move(dst, src, pos) { |
|
|
move(dst, src, pos) { |
|
|
var em = this.em; |
|
|
const { em, activeTextModel } = this; |
|
|
const srcEl = getElement(src); |
|
|
const srcEl = getElement(src); |
|
|
em && em.trigger('component:dragEnd:before', dst, srcEl, pos); // @depricated
|
|
|
em && em.trigger('component:dragEnd:before', dst, srcEl, pos); // @depricated
|
|
|
var warns = []; |
|
|
var warns = []; |
|
|
@ -981,8 +1042,9 @@ module.exports = Backbone.View.extend({ |
|
|
var dropInfo = validResult.dropInfo; |
|
|
var dropInfo = validResult.dropInfo; |
|
|
var dragInfo = validResult.dragInfo; |
|
|
var dragInfo = validResult.dragInfo; |
|
|
var dropContent = this.dropContent; |
|
|
var dropContent = this.dropContent; |
|
|
droppable = |
|
|
const { trgModel } = validResult; |
|
|
validResult.trgModel instanceof Backbone.Collection ? 1 : droppable; |
|
|
droppable = trgModel instanceof Backbone.Collection ? 1 : droppable; |
|
|
|
|
|
const isTextableActive = this.isTextableActive(model, trgModel); |
|
|
|
|
|
|
|
|
if (targetCollection && droppable && draggable) { |
|
|
if (targetCollection && droppable && draggable) { |
|
|
index = pos.method === 'after' ? index + 1 : index; |
|
|
index = pos.method === 'after' ? index + 1 : index; |
|
|
@ -993,7 +1055,7 @@ module.exports = Backbone.View.extend({ |
|
|
opts.temporary = 1; |
|
|
opts.temporary = 1; |
|
|
modelTemp = targetCollection.add({}, { ...opts }); |
|
|
modelTemp = targetCollection.add({}, { ...opts }); |
|
|
|
|
|
|
|
|
if (model) { |
|
|
if (model.collection) { |
|
|
modelToDrop = model.collection.remove(model, { temporary: 1 }); |
|
|
modelToDrop = model.collection.remove(model, { temporary: 1 }); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
@ -1002,7 +1064,18 @@ module.exports = Backbone.View.extend({ |
|
|
opts.avoidUpdateStyle = 1; |
|
|
opts.avoidUpdateStyle = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
created = targetCollection.add(modelToDrop, opts); |
|
|
if (isTextableActive) { |
|
|
|
|
|
const viewActive = activeTextModel.getView(); |
|
|
|
|
|
activeTextModel.trigger('active'); |
|
|
|
|
|
const { activeRte } = viewActive; |
|
|
|
|
|
const modelEl = model.getEl(); |
|
|
|
|
|
model.getView().render(); |
|
|
|
|
|
modelEl.setAttribute('data-gjs-textable', 'true'); |
|
|
|
|
|
const { outerHTML } = modelEl; |
|
|
|
|
|
activeRte.insertHTML && activeRte.insertHTML(outerHTML); |
|
|
|
|
|
} else { |
|
|
|
|
|
created = targetCollection.add(modelToDrop, opts); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (!dropContent) { |
|
|
if (!dropContent) { |
|
|
targetCollection.remove(modelTemp); |
|
|
targetCollection.remove(modelTemp); |
|
|
|