CR Fix: tree selection - use serializable node as parameters
This commit is contained in:
parent
7e90161057
commit
39e8d36f72
17
docs/api.md
17
docs/api.md
|
@ -216,7 +216,10 @@ Constructs a new JSONEditor.
|
|||
callback signature should be:
|
||||
```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) {
|
||||
...
|
||||
|
@ -374,9 +377,9 @@ Get the current selected nodes, Only applicable for mode 'tree'.
|
|||
|
||||
*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'.
|
||||
|
||||
|
@ -386,13 +389,13 @@ Set selection for a range of nodes, Only applicable for mode 'tree'.
|
|||
|
||||
*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
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<body>
|
||||
|
||||
<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/>
|
||||
<code class="multiline">
|
||||
// text and code modes:
|
||||
|
@ -41,7 +41,7 @@
|
|||
editor.setTextSelection(startPos, endPos)
|
||||
// tree mode:
|
||||
editor.getSelection()
|
||||
editor.setSelection(Node1,Node2)
|
||||
editor.setSelection(startNode, endNode)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
|||
<b>Text:</b><div id="selectedText"></div>
|
||||
</div>
|
||||
<div id="treeModeSelection">
|
||||
<b>Selection: </b><span id="selectedCount"></span>
|
||||
<b>Selection:</b>
|
||||
<div id="selectedNodes"></div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -91,15 +91,15 @@
|
|||
var textEl = document.getElementById('selectedText');
|
||||
textEl.innerHTML = text;
|
||||
},
|
||||
onSelectionChange: function(nodes) {
|
||||
onSelectionChange: function(start, end) {
|
||||
var nodesEl = document.getElementById('selectedNodes');
|
||||
var nodesCountEl = document.getElementById('selectedCount');
|
||||
nodesCountEl.innerHTML = nodes.length + ' nodes selected';
|
||||
nodesEl.innerHTML = nodes.map(function(node) {
|
||||
return node.field !== undefined
|
||||
? node._escapeHTML(node.field)
|
||||
: (isNaN(node.index) ? node.type : node.index);
|
||||
}).join(", ");
|
||||
nodesEl.innerHTML = '';
|
||||
if (start) {
|
||||
nodesEl.innerHTML = ('start: ' + JSON.stringify(start));
|
||||
if (end) {
|
||||
nodesEl.innerHTML += ('<br/>end: ' + JSON.stringify(end));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -80,12 +80,7 @@ Node.prototype.getPath = function () {
|
|||
var node = this;
|
||||
var path = [];
|
||||
while (node) {
|
||||
var field = !node.parent
|
||||
? undefined // do not add an (optional) field name of the root node
|
||||
: (node.parent.type != 'array')
|
||||
? node.field
|
||||
: node.index;
|
||||
|
||||
var field = node.getName();
|
||||
if (field !== undefined) {
|
||||
path.unshift(field);
|
||||
}
|
||||
|
@ -94,6 +89,54 @@ Node.prototype.getPath = function () {
|
|||
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'
|
||||
* @param {string} jsonPath
|
||||
|
|
|
@ -1088,7 +1088,7 @@ treemode.deselect = function (clearStartAndEnd) {
|
|||
|
||||
if (selectionChanged) {
|
||||
if (this._selectionChangedHandler) {
|
||||
this._selectionChangedHandler([]);
|
||||
this._selectionChangedHandler();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1113,7 +1113,8 @@ treemode.select = function (nodes) {
|
|||
});
|
||||
|
||||
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
|
||||
* @return {Array<Node>}
|
||||
* @return {{start:SerializableNode, end: SerializableNode}} if no selection an empty object will be retured
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @callback selectionCallback
|
||||
* @param {Array<Node>} nodes selected nodes
|
||||
* @param {SerializableNode=} start
|
||||
* @param {SerializableNode=} end
|
||||
*/
|
||||
treemode.onSelectionChange = function (callback) {
|
||||
if (typeof callback === 'function') {
|
||||
|
@ -1361,18 +1371,28 @@ treemode.onSelectionChange = function (callback) {
|
|||
|
||||
/**
|
||||
* Select range of nodes.
|
||||
* For selecting single node send only the first node parameter
|
||||
* For clear selection do not send any parameter
|
||||
* For selecting single node send only the start 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
|
||||
* @param {Node} [startNode] node for selection start
|
||||
* @param {Node} [endNode] node for selection end
|
||||
* @param {{path: Array.<String>}} start object contains the path for selection start
|
||||
* @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
|
||||
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');
|
||||
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 = [];
|
||||
if (startNode instanceof Node) {
|
||||
if (endNode instanceof Node && endNode !== startNode) {
|
||||
|
|
Loading…
Reference in New Issue