Merge branch 'develop' into feature/enumAsDropDownMenus

This commit is contained in:
tdakanalis 2016-04-07 09:08:52 +03:00
commit d1d9ce6135
14 changed files with 622 additions and 480 deletions

View File

@ -3,10 +3,15 @@
https://github.com/josdejong/jsoneditor https://github.com/josdejong/jsoneditor
## not yet released, version 5.2.1 ## 2016-04-06, version 5.3.0
- 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.
A regression introduced in v5.2.0.
## 2016-03-20, version 5.2.0 ## 2016-03-20, version 5.2.0

View File

@ -24,8 +24,8 @@
* Copyright (c) 2011-2016 Jos de Jong, http://jsoneditoronline.org * Copyright (c) 2011-2016 Jos de Jong, http://jsoneditoronline.org
* *
* @author Jos de Jong, <wjosdejong@gmail.com> * @author Jos de Jong, <wjosdejong@gmail.com>
* @version 5.2.0 * @version 5.3.0
* @date 2016-03-20 * @date 2016-04-06
*/ */
(function webpackUniversalModuleDefinition(root, factory) { (function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object') if(typeof exports === 'object' && typeof module === 'object')
@ -124,6 +124,9 @@ return /******/ (function(modules) { // webpackBootstrap
* {boolean} escapeUnicode If true, unicode * {boolean} escapeUnicode If true, unicode
* characters are escaped. * characters are escaped.
* false by default. * false by default.
* {boolean} sortObjectKeys If true, object keys are
* sorted before display.
* false by default.
* @param {Object | undefined} json JSON object * @param {Object | undefined} json JSON object
*/ */
function JSONEditor (container, options, json) { function JSONEditor (container, options, json) {
@ -162,7 +165,7 @@ return /******/ (function(modules) { // webpackBootstrap
'ace', 'theme', 'ace', 'theme',
'ajv', 'schema', 'ajv', 'schema',
'onChange', 'onEditable', 'onError', 'onModeChange', 'onChange', 'onEditable', 'onError', 'onModeChange',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation' 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys'
]; ];
Object.keys(options).forEach(function (option) { Object.keys(options).forEach(function (option) {
@ -641,7 +644,10 @@ return /******/ (function(modules) { // webpackBootstrap
treemode.get = function () { treemode.get = function () {
// remove focus from currently edited node // remove focus from currently edited node
if (this.focusTarget) { if (this.focusTarget) {
this.focusTarget.blur(); var node = Node.getNodeFromTarget(this.focusTarget);
if (node) {
node.blur();
}
} }
if (this.node) { if (this.node) {
@ -1449,8 +1455,8 @@ return /******/ (function(modules) { // webpackBootstrap
* @private * @private
*/ */
treemode._findTopLevelNodes = function (start, end) { treemode._findTopLevelNodes = function (start, end) {
var startPath = start.getPath(); var startPath = start.getNodePath();
var endPath = end.getPath(); var endPath = end.getNodePath();
var i = 0; var i = 0;
while (i < startPath.length && startPath[i] === endPath[i]) { while (i < startPath.length && startPath[i] === endPath[i]) {
i++; i++;
@ -1646,7 +1652,7 @@ return /******/ (function(modules) { // webpackBootstrap
var ace; var ace;
try { try {
ace = __webpack_require__(11); ace = __webpack_require__(10);
} }
catch (err) { catch (err) {
// failed to load ace, no problem, we will fall back to plain text // failed to load ace, no problem, we will fall back to plain text
@ -2137,7 +2143,7 @@ return /******/ (function(modules) { // webpackBootstrap
/* 3 */ /* 3 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
var jsonlint = __webpack_require__(10); var jsonlint = __webpack_require__(11);
/** /**
* Parse JSON using the parser built-in in the browser. * Parse JSON using the parser built-in in the browser.
@ -2797,7 +2803,8 @@ return /******/ (function(modules) { // webpackBootstrap
throw new SyntaxError('Index expected after ['); throw new SyntaxError('Index expected after [');
} }
prop = JSON.parse(jsonPath.substring(1, end)); var value = jsonPath.substring(1, end);
prop = value === '*' ? value : JSON.parse(value); // parse string and number
remainder = jsonPath.substr(end + 1); remainder = jsonPath.substr(end + 1);
} }
else { else {
@ -2829,6 +2836,10 @@ return /******/ (function(modules) { // webpackBootstrap
} }
} }
if (error.keyword === 'additionalProperties') {
error.message = 'should NOT have additional property: ' + error.params.additionalProperty;
}
return error; return error;
}; };
@ -4046,6 +4057,7 @@ return /******/ (function(modules) { // webpackBootstrap
/* 8 */ /* 8 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
var naturalSort = __webpack_require__(14);
var ContextMenu = __webpack_require__(7); var ContextMenu = __webpack_require__(7);
var appendNodeFactory = __webpack_require__(12); var appendNodeFactory = __webpack_require__(12);
var util = __webpack_require__(3); var util = __webpack_require__(3);
@ -4102,7 +4114,7 @@ return /******/ (function(modules) { // webpackBootstrap
var editable = this.editor.options.onEditable({ var editable = this.editor.options.onEditable({
field: this.field, field: this.field,
value: this.value, value: this.value,
path: this.getFieldsPath() path: this.getPath()
}); });
if (typeof editable === 'boolean') { if (typeof editable === 'boolean') {
@ -4121,11 +4133,14 @@ return /******/ (function(modules) { // webpackBootstrap
* Get the path of this node * Get the path of this node
* @return {String[]} Array containing the path to this node * @return {String[]} Array containing the path to this node
*/ */
Node.prototype.getFieldsPath = function () { Node.prototype.getPath = function () {
var node = this; var node = this;
var path = []; var path = [];
while (node) { while (node) {
var field = node.field != undefined ? node.field : node.index; var field = (!node.parent || node.parent.type != 'array')
? node.field
: node.index;
if (field !== undefined) { if (field !== undefined) {
path.unshift(field); path.unshift(field);
} }
@ -4358,21 +4373,16 @@ return /******/ (function(modules) { // webpackBootstrap
} }
} }
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;
@ -4420,8 +4430,8 @@ return /******/ (function(modules) { // webpackBootstrap
* Get path of the root node till the current node * Get path of the root node till the current node
* @return {Node[]} Returns an array with nodes * @return {Node[]} Returns an array with nodes
*/ */
Node.prototype.getPath = function() { Node.prototype.getNodePath = function() {
var path = this.parent ? this.parent.getPath() : []; var path = this.parent ? this.parent.getNodePath() : [];
path.push(this); path.push(this);
return path; return path;
}; };
@ -6795,41 +6805,41 @@ return /******/ (function(modules) { // webpackBootstrap
}; };
/** /**
* 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()) {
return;
}
var order = (direction == 'desc') ? -1 : 1; var order = (direction == 'desc') ? -1 : 1;
var prop = (this.type == 'array') ? 'value': 'field'; var prop = (this.type == 'array') ? 'value': 'field';
this.hideChilds(); this.hideChilds();
var oldChilds = this.childs; var oldChilds = this.childs;
var oldSort = this.sort; var oldSortOrder = this.sortOrder;
// copy the array (the old one will be kept for an undo action // copy the array (the old one will be kept for an undo action
this.childs = this.childs.concat(); this.childs = this.childs.concat();
// sort the arrays // sort the arrays
this.childs.sort(function (a, b) { this.childs.sort(function (a, b) {
if (a[prop] > b[prop]) return order; return order * naturalSort(a[prop], b[prop]);
if (a[prop] < b[prop]) return -order;
return 0;
}); });
this.sort = (order == 1) ? 'asc' : 'desc'; this.sortOrder = (order == 1) ? 'asc' : 'desc';
this.editor._onAction('sort', { this.editor._onAction('sort', {
node: this, node: this,
oldChilds: oldChilds, oldChilds: oldChilds,
oldSort: oldSort, oldSort: oldSortOrder,
newChilds: this.childs, newChilds: this.childs,
newSort: this.sort newSort: this.sortOrder
}); });
this.showChilds(); this.showChilds();
}
}; };
/** /**
@ -7139,13 +7149,13 @@ return /******/ (function(modules) { // webpackBootstrap
} }
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: [
{ {
@ -7153,7 +7163,7 @@ return /******/ (function(modules) { // webpackBootstrap
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');
} }
}, },
{ {
@ -7161,7 +7171,7 @@ return /******/ (function(modules) { // webpackBootstrap
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');
} }
} }
] ]
@ -7559,6 +7569,21 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ }, /***/ },
/* 10 */ /* 10 */
/***/ function(module, exports, __webpack_require__) {
// load brace
var ace = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module \"brace\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
// load required ace modules
__webpack_require__(15);
__webpack_require__(16);
__webpack_require__(13);
module.exports = ace;
/***/ },
/* 11 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* Jison generated parser */ /* Jison generated parser */
@ -7980,21 +8005,6 @@ return /******/ (function(modules) { // webpackBootstrap
exports.parse = jsonlint.parse.bind(jsonlint); exports.parse = jsonlint.parse.bind(jsonlint);
} }
/***/ },
/* 11 */
/***/ function(module, exports, __webpack_require__) {
// load brace
var ace = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module \"brace\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
// load required ace modules
__webpack_require__(14);
__webpack_require__(15);
__webpack_require__(13);
module.exports = ace;
/***/ }, /***/ },
/* 12 */ /* 12 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
@ -8379,6 +8389,57 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ }, /***/ },
/* 14 */ /* 14 */
/***/ function(module, exports, __webpack_require__) {
/*
* Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
* Author: Jim Palmer (based on chunking idea from Dave Koelle)
*/
/*jshint unused:false */
module.exports = function naturalSort (a, b) {
"use strict";
var re = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
sre = /(^[ ]*|[ ]*$)/g,
dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
hre = /^0x[0-9a-f]+$/i,
ore = /^0/,
i = function(s) { return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s; },
// convert all to strings strip whitespace
x = i(a).replace(sre, '') || '',
y = i(b).replace(sre, '') || '',
// chunk/tokenize
xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
// numeric, hex or date detection
xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && x.match(dre) && Date.parse(x)),
yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
oFxNcL, oFyNcL;
// first try and sort Hex codes or Dates
if (yD) {
if ( xD < yD ) { return -1; }
else if ( xD > yD ) { return 1; }
}
// natural sorting through split numeric strings and default strings
for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
else if (typeof oFxNcL !== typeof oFyNcL) {
oFxNcL += '';
oFyNcL += '';
}
if (oFxNcL < oFyNcL) { return -1; }
if (oFxNcL > oFyNcL) { return 1; }
}
return 0;
};
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(acequire, exports, module) { ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(acequire, exports, module) {
@ -9029,7 +9090,7 @@ return /******/ (function(modules) { // webpackBootstrap
}; };
this.createWorker = function(session) { this.createWorker = function(session) {
var worker = new WorkerClient(["ace"], __webpack_require__(16), "JsonWorker"); var worker = new WorkerClient(["ace"], __webpack_require__(17), "JsonWorker");
worker.attachToDocument(session.getDocument()); worker.attachToDocument(session.getDocument());
worker.on("annotate", function(e) { worker.on("annotate", function(e) {
@ -9052,7 +9113,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ }, /***/ },
/* 15 */ /* 16 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"], function(acequire, exports, module) { ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"], function(acequire, exports, module) {
@ -9473,7 +9534,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ }, /***/ },
/* 16 */ /* 17 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
module.exports.id = 'ace/mode/json_worker'; module.exports.id = 'ace/mode/json_worker';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

673
dist/jsoneditor.js vendored

File diff suppressed because one or more lines are too long

2
dist/jsoneditor.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -68,6 +68,10 @@ Constructs a new JSONEditor.
If true, unicode characters are escaped and displayed as their hexadecimal code (like `\u260E`) instead of of the character itself (like `☎`). False by default. If true, unicode characters are escaped and displayed as their hexadecimal code (like `\u260E`) instead of of the character itself (like `☎`). False by default.
- `{boolean} sortObjectKeys`
If true, object keys in 'tree', 'view' or 'form' mode list be listed alphabetically instead by their insertion order. Sorting is performed using a natural sort algorithm, which makes it easier to see objects that have string numbers as keys. False by default.
- `{boolean} history` - `{boolean} history`
Enables history, adds a button Undo and Redo to the menu of the JSONEditor. True by default. Only applicable when `mode` is 'tree' or 'form'. Enables history, adds a button Undo and Redo to the menu of the JSONEditor. True by default. Only applicable when `mode` is 'tree' or 'form'.

View File

@ -1,6 +1,6 @@
{ {
"name": "jsoneditor", "name": "jsoneditor",
"version": "5.2.0", "version": "5.3.0",
"main": "./index", "main": "./index",
"description": "A web-based tool to view, edit, format, and validate JSON", "description": "A web-based tool to view, edit, format, and validate JSON",
"tags": [ "tags": [
@ -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",

View File

@ -39,6 +39,9 @@ var util = require('./util');
* {boolean} escapeUnicode If true, unicode * {boolean} escapeUnicode If true, unicode
* characters are escaped. * characters are escaped.
* false by default. * false by default.
* {boolean} sortObjectKeys If true, object keys are
* sorted before display.
* false by default.
* @param {Object | undefined} json JSON object * @param {Object | undefined} json JSON object
*/ */
function JSONEditor (container, options, json) { function JSONEditor (container, options, json) {
@ -77,7 +80,7 @@ function JSONEditor (container, options, json) {
'ace', 'theme', 'ace', 'theme',
'ajv', 'schema', 'ajv', 'schema',
'onChange', 'onEditable', 'onError', 'onModeChange', 'onChange', 'onEditable', 'onError', 'onModeChange',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation' 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys'
]; ];
Object.keys(options).forEach(function (option) { Object.keys(options).forEach(function (option) {

View File

@ -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');
@ -54,7 +55,7 @@ Node.prototype._updateEditability = function () {
var editable = this.editor.options.onEditable({ var editable = this.editor.options.onEditable({
field: this.field, field: this.field,
value: this.value, value: this.value,
path: this.getFieldsPath() path: this.getPath()
}); });
if (typeof editable === 'boolean') { if (typeof editable === 'boolean') {
@ -73,11 +74,14 @@ Node.prototype._updateEditability = function () {
* Get the path of this node * Get the path of this node
* @return {String[]} Array containing the path to this node * @return {String[]} Array containing the path to this node
*/ */
Node.prototype.getFieldsPath = function () { Node.prototype.getPath = function () {
var node = this; var node = this;
var path = []; var path = [];
while (node) { while (node) {
var field = node.field != undefined ? node.field : node.index; var field = (!node.parent || node.parent.type != 'array')
? node.field
: node.index;
if (field !== undefined) { if (field !== undefined) {
path.unshift(field); path.unshift(field);
} }
@ -310,21 +314,16 @@ Node.prototype.setValue = function(value, type) {
} }
} }
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;
@ -372,8 +371,8 @@ Node.prototype.getLevel = function() {
* Get path of the root node till the current node * Get path of the root node till the current node
* @return {Node[]} Returns an array with nodes * @return {Node[]} Returns an array with nodes
*/ */
Node.prototype.getPath = function() { Node.prototype.getNodePath = function() {
var path = this.parent ? this.parent.getPath() : []; var path = this.parent ? this.parent.getNodePath() : [];
path.push(this); path.push(this);
return path; return path;
}; };
@ -2862,41 +2861,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()) {
return;
}
var order = (direction == 'desc') ? -1 : 1; var order = (direction == 'desc') ? -1 : 1;
var prop = (this.type == 'array') ? 'value': 'field'; var prop = (this.type == 'array') ? 'value': 'field';
this.hideChilds(); this.hideChilds();
var oldChilds = this.childs; var oldChilds = this.childs;
var oldSort = this.sort; var oldSortOrder = this.sortOrder;
// copy the array (the old one will be kept for an undo action // copy the array (the old one will be kept for an undo action
this.childs = this.childs.concat(); this.childs = this.childs.concat();
// sort the arrays // sort the arrays
this.childs.sort(function (a, b) { this.childs.sort(function (a, b) {
if (a[prop] > b[prop]) return order; return order * naturalSort(a[prop], b[prop]);
if (a[prop] < b[prop]) return -order;
return 0;
}); });
this.sort = (order == 1) ? 'asc' : 'desc'; this.sortOrder = (order == 1) ? 'asc' : 'desc';
this.editor._onAction('sort', { this.editor._onAction('sort', {
node: this, node: this,
oldChilds: oldChilds, oldChilds: oldChilds,
oldSort: oldSort, oldSort: oldSortOrder,
newChilds: this.childs, newChilds: this.childs,
newSort: this.sort newSort: this.sortOrder
}); });
this.showChilds(); this.showChilds();
}
}; };
/** /**
@ -3206,13 +3205,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: [
{ {
@ -3220,7 +3219,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');
} }
}, },
{ {
@ -3228,7 +3227,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');
} }
} }
] ]

View File

@ -180,7 +180,10 @@ treemode.set = function (json, name) {
treemode.get = function () { treemode.get = function () {
// remove focus from currently edited node // remove focus from currently edited node
if (this.focusTarget) { if (this.focusTarget) {
this.focusTarget.blur(); var node = Node.getNodeFromTarget(this.focusTarget);
if (node) {
node.blur();
}
} }
if (this.node) { if (this.node) {
@ -988,8 +991,8 @@ treemode.select = function (nodes) {
* @private * @private
*/ */
treemode._findTopLevelNodes = function (start, end) { treemode._findTopLevelNodes = function (start, end) {
var startPath = start.getPath(); var startPath = start.getNodePath();
var endPath = end.getPath(); var endPath = end.getNodePath();
var i = 0; var i = 0;
while (i < startPath.length && startPath[i] === endPath[i]) { while (i < startPath.length && startPath[i] === endPath[i]) {
i++; i++;

View File

@ -658,7 +658,8 @@ exports.parsePath = function parsePath(jsonPath) {
throw new SyntaxError('Index expected after ['); throw new SyntaxError('Index expected after [');
} }
prop = JSON.parse(jsonPath.substring(1, end)); var value = jsonPath.substring(1, end);
prop = value === '*' ? value : JSON.parse(value); // parse string and number
remainder = jsonPath.substr(end + 1); remainder = jsonPath.substr(end + 1);
} }
else { else {

View File

@ -1,6 +1,9 @@
var assert = require('assert'); var assert = require('assert');
var util = require('../src/js/util'); var util = require('../src/js/util');
// console.log('TEST', util.parsePath('.items[3].name'));
// console.log('TEST', util.parsePath('.items[*].name'));
describe('util', function () { describe('util', function () {
describe('sanitize', function () { describe('sanitize', function () {
@ -70,6 +73,7 @@ describe('util', function () {
assert.deepEqual(util.parsePath('.foo[2]'), ['foo', 2]); assert.deepEqual(util.parsePath('.foo[2]'), ['foo', 2]);
assert.deepEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar']); assert.deepEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar']);
assert.deepEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces']); assert.deepEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces']);
assert.deepEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar']);
}); });
it ('should throw an exception in case of an invalid path', function () { it ('should throw an exception in case of an invalid path', function () {