Dragging multiple nodes mainly working (few bugs left)
This commit is contained in:
parent
f88e3d6f0c
commit
d01fe7caab
|
@ -104,15 +104,14 @@ function History (editor) {
|
|||
},
|
||||
'moveNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node, index) {
|
||||
params.startParent.moveTo(node, params.startIndex + index);
|
||||
params.nodes.forEach(function (node) {
|
||||
params.oldBeforeNode.parent.moveBefore(node, params.oldBeforeNode);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node, index) {
|
||||
params.endParent.moveTo(node, params.endIndex + index);
|
||||
params.nodes.forEach(function (node) {
|
||||
params.newBeforeNode.parent.moveBefore(node, params.newBeforeNode);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
|
148
src/js/Node.js
148
src/js/Node.js
|
@ -1208,30 +1208,42 @@ Node.prototype.getDom = function() {
|
|||
|
||||
/**
|
||||
* DragStart event, fired on mousedown on the dragarea at the left side of a Node
|
||||
* @param {Node[] | Node} nodes
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._onDragStart = function (event) {
|
||||
var node = this;
|
||||
if (!this.mousemove) {
|
||||
this.mousemove = util.addEventListener(window, 'mousemove', function (event) {
|
||||
node._onDrag(event);
|
||||
Node.onDragStart = function (nodes, event) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
return Node.onDragStart([nodes], event);
|
||||
}
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var firstNode = nodes[0];
|
||||
var parent = firstNode.parent;
|
||||
var firstIndex = parent.childs.indexOf(firstNode);
|
||||
var beforeNode = parent.childs[firstIndex + nodes.length] || parent.append;
|
||||
var editor = firstNode.editor;
|
||||
|
||||
if (!editor.mousemove) {
|
||||
editor.mousemove = util.addEventListener(window, 'mousemove', function (event) {
|
||||
Node.onDrag(nodes, event);
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.mouseup) {
|
||||
this.mouseup = util.addEventListener(window, 'mouseup',function (event ) {
|
||||
node._onDragEnd(event);
|
||||
if (!editor.mouseup) {
|
||||
editor.mouseup = util.addEventListener(window, 'mouseup',function (event ) {
|
||||
Node.onDragEnd(nodes, event);
|
||||
});
|
||||
}
|
||||
|
||||
this.editor.highlighter.lock();
|
||||
this.drag = {
|
||||
'oldCursor': document.body.style.cursor,
|
||||
'startParent': this.parent,
|
||||
'startIndex': this.parent.childs.indexOf(this),
|
||||
'mouseX': event.pageX,
|
||||
'level': this.getLevel()
|
||||
editor.highlighter.lock();
|
||||
editor.drag = {
|
||||
oldCursor: document.body.style.cursor,
|
||||
oldSelection: editor.getSelection(),
|
||||
oldBeforeNode: beforeNode,
|
||||
mouseX: event.pageX,
|
||||
level: firstNode.getLevel()
|
||||
};
|
||||
document.body.style.cursor = 'move';
|
||||
|
||||
|
@ -1240,14 +1252,22 @@ Node.prototype._onDragStart = function (event) {
|
|||
|
||||
/**
|
||||
* Drag event, fired when moving the mouse while dragging a Node
|
||||
* @param {Node[] | Node} nodes
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._onDrag = function (event) {
|
||||
Node.onDrag = function (nodes, event) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
return Node.onDrag([nodes], event);
|
||||
}
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: this method has grown too large. Split it in a number of methods
|
||||
var mouseY = event.pageY;
|
||||
var mouseX = event.pageX;
|
||||
|
||||
var editor = nodes[0].editor;
|
||||
var trThis, trPrev, trNext, trFirst, trLast, trRoot;
|
||||
var nodePrev, nodeNext;
|
||||
var topThis, topPrev, topFirst, heightThis, bottomNext, heightNext;
|
||||
|
@ -1256,7 +1276,8 @@ Node.prototype._onDrag = function (event) {
|
|||
// TODO: add an ESC option, which resets to the original position
|
||||
|
||||
// move up/down
|
||||
trThis = this.dom.tr;
|
||||
var firstNode = nodes[0];
|
||||
trThis = firstNode.dom.tr;
|
||||
topThis = util.getAbsoluteTop(trThis);
|
||||
heightThis = trThis.offsetHeight;
|
||||
if (mouseY < topThis) {
|
||||
|
@ -1278,7 +1299,7 @@ Node.prototype._onDrag = function (event) {
|
|||
trRoot = trThis.parentNode.firstChild;
|
||||
trPrev = trRoot ? trRoot.nextSibling : undefined;
|
||||
nodePrev = Node.getNodeFromTarget(trPrev);
|
||||
if (nodePrev == this) {
|
||||
if (nodePrev == firstNode) {
|
||||
nodePrev = undefined;
|
||||
}
|
||||
}
|
||||
|
@ -1293,13 +1314,16 @@ Node.prototype._onDrag = function (event) {
|
|||
}
|
||||
|
||||
if (nodePrev) {
|
||||
nodePrev.parent.moveBefore(this, nodePrev);
|
||||
nodes.forEach(function (node) {
|
||||
nodePrev.parent.moveBefore(node, nodePrev);
|
||||
});
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// move down
|
||||
trLast = (this.expanded && this.append) ? this.append.getDom() : this.dom.tr;
|
||||
var lastNode = nodes[nodes.length - 1];
|
||||
trLast = (lastNode.expanded && lastNode.append) ? lastNode.append.getDom() : lastNode.dom.tr;
|
||||
trFirst = trLast ? trLast.nextSibling : undefined;
|
||||
if (trFirst) {
|
||||
topFirst = util.getAbsoluteTop(trFirst);
|
||||
|
@ -1311,7 +1335,7 @@ Node.prototype._onDrag = function (event) {
|
|||
util.getAbsoluteTop(trNext.nextSibling) : 0;
|
||||
heightNext = trNext ? (bottomNext - topFirst) : 0;
|
||||
|
||||
if (nodeNext.parent.childs.length == 1 && nodeNext.parent.childs[0] == this) {
|
||||
if (nodeNext.parent.childs.length == 1 && nodeNext.parent.childs[0] == lastNode) {
|
||||
// We are about to remove the last child of this parent,
|
||||
// which will make the parents appendNode visible.
|
||||
topThis += 24 - 1;
|
||||
|
@ -1325,22 +1349,22 @@ Node.prototype._onDrag = function (event) {
|
|||
|
||||
if (nodeNext && nodeNext.parent) {
|
||||
// calculate the desired level
|
||||
var diffX = (mouseX - this.drag.mouseX);
|
||||
var diffX = (mouseX - editor.drag.mouseX);
|
||||
var diffLevel = Math.round(diffX / 24 / 2);
|
||||
var level = this.drag.level + diffLevel; // desired level
|
||||
var level = editor.drag.level + diffLevel; // desired level
|
||||
var levelNext = nodeNext.getLevel(); // level to be
|
||||
|
||||
// find the best fitting level (move upwards over the append nodes)
|
||||
trPrev = nodeNext.dom.tr.previousSibling;
|
||||
while (levelNext < level && trPrev) {
|
||||
nodePrev = Node.getNodeFromTarget(trPrev);
|
||||
if (nodePrev == this || nodePrev._isChildOf(this)) {
|
||||
if (nodePrev == lastNode || nodePrev._isChildOf(lastNode)) {
|
||||
// neglect itself and its childs
|
||||
}
|
||||
else if (nodePrev instanceof AppendNode) {
|
||||
var childs = nodePrev.parent.childs;
|
||||
if (childs.length > 1 ||
|
||||
(childs.length == 1 && childs[0] != this)) {
|
||||
(childs.length == 1 && childs[0] != lastNode)) {
|
||||
// non-visible append node of a list of childs
|
||||
// consisting of not only this node (else the
|
||||
// append node will change into a visible "empty"
|
||||
|
@ -1361,7 +1385,9 @@ Node.prototype._onDrag = function (event) {
|
|||
|
||||
// move the node when its position is changed
|
||||
if (trLast.nextSibling != nodeNext.dom.tr) {
|
||||
nodeNext.parent.moveBefore(this, nodeNext);
|
||||
nodes.forEach(function (node) {
|
||||
nodeNext.parent.moveBefore(node, nodeNext);
|
||||
});
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
|
@ -1370,54 +1396,68 @@ Node.prototype._onDrag = function (event) {
|
|||
|
||||
if (moved) {
|
||||
// update the dragging parameters when moved
|
||||
this.drag.mouseX = mouseX;
|
||||
this.drag.level = this.getLevel();
|
||||
editor.drag.mouseX = mouseX;
|
||||
editor.drag.level = firstNode.getLevel();
|
||||
}
|
||||
|
||||
// auto scroll when hovering around the top of the editor
|
||||
this.editor.startAutoScroll(mouseY);
|
||||
editor.startAutoScroll(mouseY);
|
||||
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* Drag event, fired on mouseup after having dragged a node
|
||||
* @param {Node[] | Node} nodes
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._onDragEnd = function (event) {
|
||||
Node.onDragEnd = function (nodes, event) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
return Node.onDrag([nodes], event);
|
||||
}
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var firstNode = nodes[0];
|
||||
var editor = firstNode.editor;
|
||||
var parent = firstNode.parent;
|
||||
var firstIndex = parent.childs.indexOf(firstNode);
|
||||
var beforeNode = parent.childs[firstIndex + nodes.length] || parent.append;
|
||||
|
||||
var params = {
|
||||
'nodes': [this],
|
||||
'startParent': this.drag.startParent,
|
||||
'startIndex': this.drag.startIndex,
|
||||
'endParent': this.parent,
|
||||
'endIndex': this.parent.childs.indexOf(this)
|
||||
nodes: nodes,
|
||||
oldSelection: editor.drag.oldSelection,
|
||||
newSelection: editor.getSelection(),
|
||||
oldBeforeNode: editor.drag.oldBeforeNode,
|
||||
newBeforeNode: beforeNode
|
||||
};
|
||||
|
||||
if ((params.startParent != params.endParent) ||
|
||||
(params.startIndex != params.endIndex)) {
|
||||
if (params.oldBeforeNode != params.newBeforeNode) {
|
||||
// only register this action if the node is actually moved to another place
|
||||
this.editor._onAction('moveNodes', params);
|
||||
editor._onAction('moveNodes', params);
|
||||
}
|
||||
|
||||
document.body.style.cursor = this.drag.oldCursor;
|
||||
this.editor.highlighter.unlock();
|
||||
if (event.target !== this.dom.drag && event.target !== this.dom.menu) {
|
||||
this.editor.highlighter.unhighlight();
|
||||
}
|
||||
delete this.drag;
|
||||
document.body.style.cursor = editor.drag.oldCursor;
|
||||
editor.highlighter.unlock();
|
||||
nodes.forEach(function (node) {
|
||||
if (event.target !== node.dom.drag && event.target !== node.dom.menu) {
|
||||
editor.highlighter.unhighlight();
|
||||
}
|
||||
});
|
||||
delete editor.drag;
|
||||
|
||||
if (this.mousemove) {
|
||||
util.removeEventListener(window, 'mousemove', this.mousemove);
|
||||
delete this.mousemove;
|
||||
if (editor.mousemove) {
|
||||
util.removeEventListener(window, 'mousemove', editor.mousemove);
|
||||
delete editor.mousemove;
|
||||
}
|
||||
if (this.mouseup) {
|
||||
util.removeEventListener(window, 'mouseup', this.mouseup);
|
||||
delete this.mouseup;
|
||||
if (editor.mouseup) {
|
||||
util.removeEventListener(window, 'mouseup', editor.mouseup);
|
||||
delete editor.mouseup;
|
||||
}
|
||||
|
||||
// Stop any running auto scroll
|
||||
this.editor.stopAutoScroll();
|
||||
editor.stopAutoScroll();
|
||||
|
||||
event.preventDefault();
|
||||
};
|
||||
|
|
|
@ -414,9 +414,14 @@ treemode.setSelection = function (selection) {
|
|||
* {Number} scrollTop Scroll position
|
||||
*/
|
||||
treemode.getSelection = function () {
|
||||
var range = util.getSelectionOffset();
|
||||
if (range && range.container.nodeName !== 'DIV') { // filter on (editable) divs)
|
||||
range = null;
|
||||
}
|
||||
|
||||
return {
|
||||
dom: domFocus,
|
||||
range: util.getSelectionOffset(),
|
||||
range: range,
|
||||
nodes: this.multiselect.nodes.slice(0),
|
||||
scrollTop: this.content ? this.content.scrollTop : 0
|
||||
};
|
||||
|
@ -643,17 +648,27 @@ treemode._onEvent = function (event) {
|
|||
// stop propagation
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type == 'click') {
|
||||
// deselect a multi selection
|
||||
this.deselect();
|
||||
}
|
||||
|
||||
if (event.type == 'mousedown') {
|
||||
// drag multiple nodes
|
||||
Node.onDragStart(this.multiselect.nodes, event);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event.type == 'mousedown') {
|
||||
this.deselect();
|
||||
|
||||
if (node && event.target == node.dom.drag) {
|
||||
node._onDragStart(event);
|
||||
// drag a singe node
|
||||
Node.onDragStart(node, event);
|
||||
}
|
||||
else if (!node || (event.target != node.dom.field && event.target != node.dom.value)) {
|
||||
// select multiple nodes
|
||||
// TODO: if there is already a multiselect and this event is inside one of the selected nodes, start a node drag action
|
||||
this._onMultiSelectStart(event);
|
||||
}
|
||||
}
|
||||
|
@ -732,6 +747,7 @@ treemode.deselect = function () {
|
|||
this.multiselect.nodes.forEach(function (node) {
|
||||
node.setSelected(false);
|
||||
});
|
||||
this.multiselect.nodes = [];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -777,8 +793,8 @@ treemode._findTopLevelNodes = function (start, end) {
|
|||
var endChild = endPath[i];
|
||||
|
||||
if (!startChild || !endChild) {
|
||||
// startChild or endChild are each others parents
|
||||
if (root.parent) {
|
||||
// startChild is a parent of endChild or vice versa
|
||||
startChild = root;
|
||||
endChild = root;
|
||||
root = root.parent
|
||||
|
|
Loading…
Reference in New Issue