Sorting object keys or array items via the context menu is now also naturally sorted (see #288)
This commit is contained in:
parent
a97be17ed3
commit
e7b7362fc2
|
@ -6,11 +6,14 @@ https://github.com/josdejong/jsoneditor
|
||||||
## not yet released, version 5.3.0
|
## not yet released, version 5.3.0
|
||||||
|
|
||||||
- Implemented support for sorting object keys naturally. Thanks @edufelipe.
|
- Implemented support for sorting object keys naturally. Thanks @edufelipe.
|
||||||
|
- Sorting object keys or array items via the context menu is now also naturally
|
||||||
|
sorted.
|
||||||
- Fixed #283: improved JSON schema error message in case of no
|
- Fixed #283: improved JSON schema error message in case of no
|
||||||
additionalProperties.
|
additionalProperties.
|
||||||
- Fixed #286: Calling `get()` or `getText()` caused the editor to lose focus.
|
- Fixed #286: Calling `get()` or `getText()` caused the editor to lose focus.
|
||||||
A regression introduced in v5.2.0.
|
A regression introduced in v5.2.0.
|
||||||
|
|
||||||
|
|
||||||
## 2016-03-20, version 5.2.0
|
## 2016-03-20, version 5.2.0
|
||||||
|
|
||||||
- Implemented method `editor.destroy()` to properly cleanup the editor (#278).
|
- Implemented method `editor.destroy()` to properly cleanup the editor (#278).
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "3.4.0",
|
"ajv": "3.4.0",
|
||||||
"brace": "0.7.0"
|
"brace": "0.7.0",
|
||||||
|
"javascript-natural-sort": "0.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"gulp": "3.9.0",
|
"gulp": "3.9.0",
|
||||||
|
|
164
src/js/Node.js
164
src/js/Node.js
|
@ -1,3 +1,4 @@
|
||||||
|
var naturalSort = require('javascript-natural-sort');
|
||||||
var ContextMenu = require('./ContextMenu');
|
var ContextMenu = require('./ContextMenu');
|
||||||
var appendNodeFactory = require('./appendNodeFactory');
|
var appendNodeFactory = require('./appendNodeFactory');
|
||||||
var util = require('./util');
|
var util = require('./util');
|
||||||
|
@ -299,46 +300,30 @@ Node.prototype.setValue = function(value, type) {
|
||||||
else if (this.type == 'object') {
|
else if (this.type == 'object') {
|
||||||
// object
|
// object
|
||||||
this.childs = [];
|
this.childs = [];
|
||||||
var props = [];
|
|
||||||
for (var childField in value) {
|
for (var childField in value) {
|
||||||
if (value.hasOwnProperty(childField)) {
|
if (value.hasOwnProperty(childField)) {
|
||||||
props.push(childField);
|
childValue = value[childField];
|
||||||
|
if (childValue !== undefined && !(childValue instanceof Function)) {
|
||||||
|
// ignore undefined and functions
|
||||||
|
child = new Node(this.editor, {
|
||||||
|
field: childField,
|
||||||
|
value: childValue
|
||||||
|
});
|
||||||
|
this.appendChild(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.editor.options.sortObjectKeys === true) {
|
|
||||||
props = this._naturalSort(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < props.length; i++) {
|
|
||||||
var childField = props[i];
|
|
||||||
childValue = value[childField];
|
|
||||||
if (childValue !== undefined && !(childValue instanceof Function)) {
|
|
||||||
// ignore undefined and functions
|
|
||||||
child = new Node(this.editor, {
|
|
||||||
field: childField,
|
|
||||||
value: childValue
|
|
||||||
});
|
|
||||||
this.appendChild(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = '';
|
this.value = '';
|
||||||
|
|
||||||
|
// sort object keys
|
||||||
|
if (this.editor.options.sortObjectKeys === true) {
|
||||||
|
this.sort('asc');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// value
|
// value
|
||||||
this.childs = undefined;
|
this.childs = undefined;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
/* TODO
|
|
||||||
if (typeof(value) == 'string') {
|
|
||||||
var escValue = JSON.stringify(value);
|
|
||||||
this.value = escValue.substring(1, escValue.length - 1);
|
|
||||||
console.log('check', value, this.value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previousValue = this.value;
|
this.previousValue = this.value;
|
||||||
|
@ -2761,41 +2746,41 @@ Node.prototype._onChangeType = function (newType) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the childs of the node. Only applicable when the node has type 'object'
|
* Sort the child's of the node. Only applicable when the node has type 'object'
|
||||||
* or 'array'.
|
* or 'array'.
|
||||||
* @param {String} direction Sorting direction. Available values: "asc", "desc"
|
* @param {String} direction Sorting direction. Available values: "asc", "desc"
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Node.prototype._onSort = function (direction) {
|
Node.prototype.sort = function (direction) {
|
||||||
if (this._hasChilds()) {
|
if (!this._hasChilds()) {
|
||||||
var order = (direction == 'desc') ? -1 : 1;
|
return;
|
||||||
var prop = (this.type == 'array') ? 'value': 'field';
|
|
||||||
this.hideChilds();
|
|
||||||
|
|
||||||
var oldChilds = this.childs;
|
|
||||||
var oldSort = this.sort;
|
|
||||||
|
|
||||||
// copy the array (the old one will be kept for an undo action
|
|
||||||
this.childs = this.childs.concat();
|
|
||||||
|
|
||||||
// sort the arrays
|
|
||||||
this.childs.sort(function (a, b) {
|
|
||||||
if (a[prop] > b[prop]) return order;
|
|
||||||
if (a[prop] < b[prop]) return -order;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
this.sort = (order == 1) ? 'asc' : 'desc';
|
|
||||||
|
|
||||||
this.editor._onAction('sort', {
|
|
||||||
node: this,
|
|
||||||
oldChilds: oldChilds,
|
|
||||||
oldSort: oldSort,
|
|
||||||
newChilds: this.childs,
|
|
||||||
newSort: this.sort
|
|
||||||
});
|
|
||||||
|
|
||||||
this.showChilds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var order = (direction == 'desc') ? -1 : 1;
|
||||||
|
var prop = (this.type == 'array') ? 'value': 'field';
|
||||||
|
this.hideChilds();
|
||||||
|
|
||||||
|
var oldChilds = this.childs;
|
||||||
|
var oldSortOrder = this.sortOrder;
|
||||||
|
|
||||||
|
// copy the array (the old one will be kept for an undo action
|
||||||
|
this.childs = this.childs.concat();
|
||||||
|
|
||||||
|
// sort the arrays
|
||||||
|
this.childs.sort(function (a, b) {
|
||||||
|
return order * naturalSort(a[prop], b[prop]);
|
||||||
|
});
|
||||||
|
this.sortOrder = (order == 1) ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
this.editor._onAction('sort', {
|
||||||
|
node: this,
|
||||||
|
oldChilds: oldChilds,
|
||||||
|
oldSort: oldSortOrder,
|
||||||
|
newChilds: this.childs,
|
||||||
|
newSort: this.sortOrder
|
||||||
|
});
|
||||||
|
|
||||||
|
this.showChilds();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3105,13 +3090,13 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._hasChilds()) {
|
if (this._hasChilds()) {
|
||||||
var direction = ((this.sort == 'asc') ? 'desc': 'asc');
|
var direction = ((this.sortOrder == 'asc') ? 'desc': 'asc');
|
||||||
items.push({
|
items.push({
|
||||||
text: 'Sort',
|
text: 'Sort',
|
||||||
title: 'Sort the childs of this ' + this.type,
|
title: 'Sort the childs of this ' + this.type,
|
||||||
className: 'jsoneditor-sort-' + direction,
|
className: 'jsoneditor-sort-' + direction,
|
||||||
click: function () {
|
click: function () {
|
||||||
node._onSort(direction);
|
node.sort(direction);
|
||||||
},
|
},
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
|
@ -3119,7 +3104,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
|
||||||
className: 'jsoneditor-sort-asc',
|
className: 'jsoneditor-sort-asc',
|
||||||
title: 'Sort the childs of this ' + this.type + ' in ascending order',
|
title: 'Sort the childs of this ' + this.type + ' in ascending order',
|
||||||
click: function () {
|
click: function () {
|
||||||
node._onSort('asc');
|
node.sort('asc');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3127,7 +3112,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
|
||||||
className: 'jsoneditor-sort-desc',
|
className: 'jsoneditor-sort-desc',
|
||||||
title: 'Sort the childs of this ' + this.type +' in descending order',
|
title: 'Sort the childs of this ' + this.type +' in descending order',
|
||||||
click: function () {
|
click: function () {
|
||||||
node._onSort('desc');
|
node.sort('desc');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -3399,57 +3384,6 @@ Node.prototype._escapeJSON = function (text) {
|
||||||
return escaped;
|
return escaped;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* sorts an array of strings using natural sort.
|
|
||||||
* Natural sort resuls in the array `['100', '2', '1']` being sorted as
|
|
||||||
* `['1', '2', '100']` instead of `['1', '100', '2']`, making it more readable.
|
|
||||||
* This implementation is an adaptation of Brian Huisman implementation of the
|
|
||||||
* Alphanum Algorithm by David Koelle.
|
|
||||||
* @param {Array[String]} array
|
|
||||||
* @return {String} sortedArray
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Node.prototype._naturalSort = function(array) {
|
|
||||||
var sortedArray = array.slice();
|
|
||||||
|
|
||||||
for (var z = 0, t; t = sortedArray[z]; z++) {
|
|
||||||
sortedArray[z] = [];
|
|
||||||
var x = 0, y = -1, n = 0, i, j;
|
|
||||||
|
|
||||||
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
|
|
||||||
var m = (i == 46 || (i >=48 && i <= 57));
|
|
||||||
if (m !== n) {
|
|
||||||
sortedArray[z][++y] = '';
|
|
||||||
n = m;
|
|
||||||
}
|
|
||||||
sortedArray[z][y] += j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sortedArray.sort(function(a, b) {
|
|
||||||
for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
|
|
||||||
aa = aa.toLowerCase();
|
|
||||||
bb = bb.toLowerCase();
|
|
||||||
if (aa !== bb) {
|
|
||||||
var c = Number(aa), d = Number(bb);
|
|
||||||
if (c == aa && d == bb) {
|
|
||||||
return c - d;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (aa > bb) ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a.length - b.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var z = 0; z < sortedArray.length; z++) {
|
|
||||||
sortedArray[z] = sortedArray[z].join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortedArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: find a nicer solution to resolve this circular dependency between Node and AppendNode
|
// TODO: find a nicer solution to resolve this circular dependency between Node and AppendNode
|
||||||
var AppendNode = appendNodeFactory(Node);
|
var AppendNode = appendNodeFactory(Node);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue