Implemented keyboard shortcuts to select multiple fields

This commit is contained in:
jos 2015-12-30 20:29:45 +01:00
parent fe5a413f23
commit 96c4204b1c
4 changed files with 76 additions and 28 deletions

View File

@ -5,7 +5,8 @@
Key | Description
----------------------- | ------------------------------------------------
Alt+Arrows | Move the caret up/down/left/right between fields
Shift+Alt+Arrows | Move field up/down/left/right
Shift+Alt+Arrows | Move current field or selected fields up/down/left/right
Shift+Arrow Up/Down | Select multiple fields
Ctrl+D | Duplicate field
Ctrl+Del | Remove field
Ctrl+Enter | Open link when on a field containing an url

View File

@ -233,7 +233,8 @@ tr.jsoneditor-selected button.jsoneditor-contextmenu {
visibility: hidden;
}
tr.jsoneditor-selected.jsoneditor-first button {
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea,
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
visibility: visible;
}

View File

@ -2004,6 +2004,8 @@ Node.prototype.onKeyDown = function (event) {
var editable = this.editor.options.mode === 'tree';
var oldSelection;
var oldBeforeNode;
var nodes;
var multiselection;
// util.log(ctrlKey, keynum, event.charCode); // TODO: cleanup
if (keynum == 13) { // Enter
@ -2027,7 +2029,10 @@ Node.prototype.onKeyDown = function (event) {
}
else if (keynum == 68) { // D
if (ctrlKey && editable) { // Ctrl+D
Node.onDuplicate(this);
nodes = this.editor.multiselection.nodes.length > 0
? this.editor.multiselection.nodes
: this;
Node.onDuplicate(nodes);
handled = true;
}
}
@ -2046,7 +2051,10 @@ Node.prototype.onKeyDown = function (event) {
}
else if (keynum == 46 && editable) { // Del
if (ctrlKey) { // Ctrl+Del
Node.onRemove(this);
nodes = this.editor.multiselection.nodes.length > 0
? this.editor.multiselection.nodes
: this;
Node.onRemove(nodes);
handled = true;
}
}
@ -2127,10 +2135,25 @@ Node.prototype.onKeyDown = function (event) {
// find the previous node
prevNode = this._previousNode();
if (prevNode) {
this.editor.deselect(true);
prevNode.focus(Node.focusElement || this._getElementName(target));
}
handled = true;
}
else if (!altKey && shiftKey) { // Shift + Arrow Up
// select multiple nodes
prevNode = this._previousNode();
if (prevNode) {
multiselection = this.editor.multiselection;
multiselection.start = multiselection.start || this;
multiselection.end = prevNode;
nodes = this.editor._findTopLevelNodes(multiselection.start, multiselection.end);
this.editor.select(nodes);
prevNode.focus('field'); // select field as we know this always exists
}
handled = true;
}
else if (altKey && shiftKey) { // Alt + Shift + Arrow Up
// find the previous node
prevNode = this._previousNode();
@ -2191,10 +2214,25 @@ Node.prototype.onKeyDown = function (event) {
// find the next node
nextNode = this._nextNode();
if (nextNode) {
this.editor.deselect(true);
nextNode.focus(Node.focusElement || this._getElementName(target));
}
handled = true;
}
else if (!altKey && shiftKey) { // Shift + Arrow Down
// select multiple nodes
nextNode = this._nextNode();
if (nextNode) {
multiselection = this.editor.multiselection;
multiselection.start = multiselection.start || this;
multiselection.end = nextNode;
nodes = this.editor._findTopLevelNodes(multiselection.start, multiselection.end);
this.editor.select(nodes);
nextNode.focus('field'); // select field as we know this always exists
}
handled = true;
}
else if (altKey && shiftKey && editable) { // Alt + Shift + Arrow Down
// find the 2nd next node and move before that one
if (this.expanded) {
@ -2310,7 +2348,7 @@ Node.onDuplicate = function(nodes) {
var parent = lastNode.parent;
var editor = lastNode.editor;
editor.deselect(editor.multiselect.nodes);
editor.deselect(editor.multiselection.nodes);
// duplicate the nodes
var oldSelection = editor.getSelection();

View File

@ -36,7 +36,9 @@ treemode.create = function (container, options) {
this.dom = {};
this.highlighter = new Highlighter();
this.selection = undefined; // will hold the last input selection
this.multiselection = [];
this.multiselection = {
nodes: []
};
this._setOptions(options);
@ -422,7 +424,7 @@ treemode.getSelection = function () {
return {
dom: domFocus,
range: range,
nodes: this.multiselection.slice(0),
nodes: this.multiselection.nodes.slice(0),
scrollTop: this.content ? this.content.scrollTop : 0
};
};
@ -656,7 +658,7 @@ treemode._onEvent = function (event) {
if (event.type == 'mousedown') {
// drag multiple nodes
Node.onDragStart(this.multiselection, event);
Node.onDragStart(this.multiselection.nodes, event);
}
}
else {
@ -682,10 +684,10 @@ treemode._onEvent = function (event) {
treemode._onMultiSelectStart = function (event) {
var node = Node.getNodeFromTarget(event.target);
this.multiselection = [];
this.drag = {
this.multiselection = {
start: node || null,
end: null
end: null,
nodes: []
};
var editor = this;
@ -708,27 +710,28 @@ treemode._onMultiSelect = function (event) {
var node = Node.getNodeFromTarget(event.target);
if (node) {
if (this.drag.start == null) {
this.drag.start = node;
if (this.multiselection.start == null) {
this.multiselection.start = node;
}
this.drag.end = node;
this.multiselection.end = node;
}
// deselect previous selection
this.deselect();
// find the selected nodes in the range from first to last
var start = this.drag.start;
var end = this.drag.end || this.drag.start;
var start = this.multiselection.start;
var end = this.multiselection.end || this.multiselection.start;
if (start && end) {
// find the top level childs, all having the same parent
this.multiselection = this._findTopLevelNodes(start, end);
this.select(this.multiselection);
this.multiselection.nodes = this._findTopLevelNodes(start, end);
this.select(this.multiselection.nodes);
}
};
treemode._onMultiSelectEnd = function (event) {
delete this.drag;
this.multiselection.start = null;
this.multiselection.end = null;
// cleanup global event listeners
if (this.mousemove) {
@ -743,13 +746,18 @@ treemode._onMultiSelectEnd = function (event) {
/**
* deselect currently selected nodes
* @param {boolean} [clearStartAndEnd=false] If true, the `start` and `end`
* state is cleared too.
*/
treemode.deselect = function () {
if (this.multiselection) {
this.multiselection.forEach(function (node) {
node.setSelected(false);
});
this.multiselection = [];
treemode.deselect = function (clearStartAndEnd) {
this.multiselection.nodes.forEach(function (node) {
node.setSelected(false);
});
this.multiselection.nodes = [];
if (clearStartAndEnd) {
this.multiselection.start = null;
this.multiselection.end = null;
}
};
@ -765,7 +773,7 @@ treemode.select = function (nodes) {
if (nodes) {
this.deselect();
this.multiselection = nodes.slice(0);
this.multiselection.nodes = nodes.slice(0);
var first = nodes[0];
nodes.forEach(function (node) {
@ -935,7 +943,7 @@ treemode.showContextMenu = function (anchor, onClose) {
title: 'Duplicate selected fields (Ctrl+D)',
className: 'jsoneditor-duplicate',
click: function () {
Node.onDuplicate(editor.multiselection);
Node.onDuplicate(editor.multiselection.nodes);
}
});
@ -945,7 +953,7 @@ treemode.showContextMenu = function (anchor, onClose) {
title: 'Remove selected fields (Ctrl+Del)',
className: 'jsoneditor-remove',
click: function () {
Node.onRemove(editor.multiselection);
Node.onRemove(editor.multiselection.nodes);
}
});