CR Fix: tree selection - use serializable node as parameters

This commit is contained in:
Meir Rotstein 2018-04-02 01:40:10 +03:00
parent 7e90161057
commit 39e8d36f72
4 changed files with 102 additions and 36 deletions

View File

@ -216,7 +216,10 @@ Constructs a new JSONEditor.
callback signature should be: callback signature should be:
```js ```js
/** /**
* @param {Array<Node>} nodes selected nodes * @typedef {{field: String, value: String|Object|Number|Boolean, path: Array.<String|Number>} SerializableNode
*
* @param {SerializableNode=} start
* @param {SerializableNode=} end
*/ */
function onSelectionChange(nodes) { function onSelectionChange(nodes) {
... ...
@ -374,9 +377,9 @@ Get the current selected nodes, Only applicable for mode 'tree'.
*Returns:* *Returns:*
- `{Array<Node>} nodes` - `{{start:SerializableNode, end: SerializableNode}}`
#### `JSONEditor.setSelection(startNode, endNode)` #### `JSONEditor.setSelection(start, end)`
Set selection for a range of nodes, Only applicable for mode 'tree'. Set selection for a range of nodes, Only applicable for mode 'tree'.
@ -386,13 +389,13 @@ Set selection for a range of nodes, Only applicable for mode 'tree'.
*Parameters:* *Parameters:*
- `{Node} startNode` - `{{path: Array.<String>}} start`
Node instance for selection start Path for the start node
- `{Node} endNode` - `{{path: Array.<String>}} end`
Node instance for selection end Path for the end node
### Examples ### Examples

View File

@ -33,15 +33,15 @@
<body> <body>
<p> <p>
Selection indication was done using the <code>on{Text/Node}SelectionChange</code> listeners.<br/> Selection indication was done using the <code>on[Text]SelectionChange</code> listeners.<br/>
you can try the following calls in the console of your browser:<br/> you can try the following calls in the console of your browser:<br/>
<code class="multiline"> <code class="multiline">
// text and code modes: // text and code modes:
editor.getTextSelection() editor.getTextSelection()
editor.setTextSelection(startPos,endPos) editor.setTextSelection(startPos, endPos)
// tree mode: // tree mode:
editor.getSelection() editor.getSelection()
editor.setSelection(Node1,Node2) editor.setSelection(startNode, endNode)
</code> </code>
</p> </p>
@ -52,7 +52,7 @@
<b>Text:</b><div id="selectedText"></div> <b>Text:</b><div id="selectedText"></div>
</div> </div>
<div id="treeModeSelection"> <div id="treeModeSelection">
<b>Selection: </b><span id="selectedCount"></span> <b>Selection:</b>
<div id="selectedNodes"></div> <div id="selectedNodes"></div>
</div> </div>
</form> </form>
@ -91,15 +91,15 @@
var textEl = document.getElementById('selectedText'); var textEl = document.getElementById('selectedText');
textEl.innerHTML = text; textEl.innerHTML = text;
}, },
onSelectionChange: function(nodes) { onSelectionChange: function(start, end) {
var nodesEl = document.getElementById('selectedNodes'); var nodesEl = document.getElementById('selectedNodes');
var nodesCountEl = document.getElementById('selectedCount'); nodesEl.innerHTML = '';
nodesCountEl.innerHTML = nodes.length + ' nodes selected'; if (start) {
nodesEl.innerHTML = nodes.map(function(node) { nodesEl.innerHTML = ('start: ' + JSON.stringify(start));
return node.field !== undefined if (end) {
? node._escapeHTML(node.field) nodesEl.innerHTML += ('<br/>end: ' + JSON.stringify(end));
: (isNaN(node.index) ? node.type : node.index); }
}).join(", "); }
} }
}; };

View File

@ -80,12 +80,7 @@ Node.prototype.getPath = function () {
var node = this; var node = this;
var path = []; var path = [];
while (node) { while (node) {
var field = !node.parent var field = node.getName();
? undefined // do not add an (optional) field name of the root node
: (node.parent.type != 'array')
? node.field
: node.index;
if (field !== undefined) { if (field !== undefined) {
path.unshift(field); path.unshift(field);
} }
@ -94,6 +89,54 @@ Node.prototype.getPath = function () {
return path; return path;
}; };
/**
* Get node serializable name
* @returns {String|Number}
*/
Node.prototype.getName = function () {
return !this.parent
? undefined // do not add an (optional) field name of the root node
: (this.parent.type != 'array')
? this.field
: this.index;
};
/**
* Find child node by serializable path
* @param {Array<String>} path
*/
Node.prototype.findNodeByPath = function (path) {
if (!path) {
return;
}
if (path.length == 0) {
return this;
}
if (path.length && this.childs && this.childs.length) {
for (var i=0; i < this.childs.length; ++i) {
if (path[0] === '' + this.childs[i].getName()) {
return this.childs[i].findNodeByPath(path.slice(1));
}
}
}
};
/**
* @typedef {{field: String, value: String|Object|Number|Boolean, path: Array.<String|Number>} SerializableNode
*
* Returns serializable representation for the node
* @return {SerializedNode}
*/
Node.prototype.serialize = function () {
return {
field: this.getField(),
value: this.getValue(),
path: this.getPath()
};
};
/** /**
* Find a Node from a JSON path like '.items[3].name' * Find a Node from a JSON path like '.items[3].name'
* @param {string} jsonPath * @param {string} jsonPath

View File

@ -1088,7 +1088,7 @@ treemode.deselect = function (clearStartAndEnd) {
if (selectionChanged) { if (selectionChanged) {
if (this._selectionChangedHandler) { if (this._selectionChangedHandler) {
this._selectionChangedHandler([]); this._selectionChangedHandler();
} }
} }
}; };
@ -1113,7 +1113,8 @@ treemode.select = function (nodes) {
}); });
if (this._selectionChangedHandler) { if (this._selectionChangedHandler) {
this._selectionChangedHandler(nodes); var selection = this.getSelection();
this._selectionChangedHandler(selection.start, selection.end);
} }
} }
}; };
@ -1340,10 +1341,18 @@ treemode.showContextMenu = function (anchor, onClose) {
/** /**
* Get current selected nodes * Get current selected nodes
* @return {Array<Node>} * @return {{start:SerializableNode, end: SerializableNode}} if no selection an empty object will be retured
*/ */
treemode.getSelection = function () { treemode.getSelection = function () {
return this.multiselection.nodes || []; var selection = {};
if (this.multiselection.nodes && this.multiselection.nodes.length) {
selection.start = this.multiselection.nodes[0].serialize();
if (this.multiselection.nodes.length > 1) {
selection.end = this.multiselection.nodes[this.multiselection.nodes.length - 1].serialize();
}
}
return selection;
}; };
/** /**
@ -1351,7 +1360,8 @@ treemode.getSelection = function () {
* @param {selectionCallback} callback * @param {selectionCallback} callback
* *
* @callback selectionCallback * @callback selectionCallback
* @param {Array<Node>} nodes selected nodes * @param {SerializableNode=} start
* @param {SerializableNode=} end
*/ */
treemode.onSelectionChange = function (callback) { treemode.onSelectionChange = function (callback) {
if (typeof callback === 'function') { if (typeof callback === 'function') {
@ -1361,18 +1371,28 @@ treemode.onSelectionChange = function (callback) {
/** /**
* Select range of nodes. * Select range of nodes.
* For selecting single node send only the first node parameter * For selecting single node send only the start parameter
* For clear selection do not send any parameter * For clear the selection do not send any parameter
* If the nodes are not from the same level the first common parent will be selected * If the nodes are not from the same level the first common parent will be selected
* @param {Node} [startNode] node for selection start * @param {{path: Array.<String>}} start object contains the path for selection start
* @param {Node} [endNode] node for selection end * @param {{path: Array.<String>}=} end object contains the path for selection end
*/ */
treemode.setSelection = function (startNode, endNode) { treemode.setSelection = function (start, end) {
// check for old usage // check for old usage
if (startNode.dom && startNode.range) { if (start && start.dom && start.range) {
console.warn('setSelection/getSelection usage for text selection is depracated and should not be used, see documantaion for supported selection options'); console.warn('setSelection/getSelection usage for text selection is depracated and should not be used, see documantaion for supported selection options');
this.setDomSelection(startNode); this.setDomSelection(startNode);
} }
var startNode, endNode;
if (start && start.path) {
startNode = this.node.findNodeByPath(start.path);
if (end && end.path) {
endNode = this.node.findNodeByPath(end.path);
}
}
var nodes = []; var nodes = [];
if (startNode instanceof Node) { if (startNode instanceof Node) {
if (endNode instanceof Node && endNode !== startNode) { if (endNode instanceof Node && endNode !== startNode) {