Implemented `transform` modal for modes `code` and `text`
This commit is contained in:
parent
74b816a554
commit
7311e78b53
|
@ -3,6 +3,11 @@
|
|||
https://github.com/josdejong/jsoneditor
|
||||
|
||||
|
||||
## not yet published, version 6.1.0
|
||||
|
||||
- Implemented menu options `sort` and `transform` for modes `code` and `text`.
|
||||
|
||||
|
||||
## 2019-06-12, version 6.0.0
|
||||
|
||||
- Breaking change: upgraded dependency `ajv@6.10.0`, supporting JSON schema
|
||||
|
|
|
@ -1459,7 +1459,7 @@ Node.prototype.changeType = function (newType) {
|
|||
this.value = String(this.value);
|
||||
}
|
||||
else {
|
||||
this.value = this._stringCast(String(this.value));
|
||||
this.value = util.parseString(String(this.value));
|
||||
}
|
||||
|
||||
this.focus();
|
||||
|
@ -1550,7 +1550,7 @@ Node.prototype._getDomValue = function() {
|
|||
}
|
||||
else {
|
||||
var str = this._unescapeHTML(this.valueInnerText);
|
||||
value = this._stringCast(str);
|
||||
value = util.parseString(str);
|
||||
}
|
||||
if (value !== this.value) {
|
||||
this.value = value;
|
||||
|
@ -4303,8 +4303,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
|
|||
title: translate('transformTitle', {type: this.type}),
|
||||
className: 'jsoneditor-transform',
|
||||
click: function () {
|
||||
var anchor = node.editor.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
||||
showTransformModal(node, anchor)
|
||||
node.showTransformModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4456,7 +4455,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
|
|||
|
||||
|
||||
/**
|
||||
* Show advanced sorting modal
|
||||
* Show sorting modal
|
||||
*/
|
||||
Node.prototype.showSortModal = function () {
|
||||
var node = this;
|
||||
|
@ -4479,6 +4478,19 @@ Node.prototype.showSortModal = function () {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Show transform modal
|
||||
*/
|
||||
Node.prototype.showTransformModal = function () {
|
||||
var node = this;
|
||||
|
||||
var anchor = this.editor.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
||||
var json = node.getValue();
|
||||
showTransformModal(anchor, json, function (query) {
|
||||
node.transform(query);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get the type of a value
|
||||
* @param {*} value
|
||||
|
@ -4492,45 +4504,13 @@ Node.prototype._getType = function(value) {
|
|||
if (value instanceof Object) {
|
||||
return 'object';
|
||||
}
|
||||
if (typeof(value) == 'string' && typeof(this._stringCast(value)) != 'string') {
|
||||
if (typeof(value) == 'string' && typeof(util.parseString(value)) != 'string') {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
return 'auto';
|
||||
};
|
||||
|
||||
/**
|
||||
* cast contents of a string to the correct type. This can be a string,
|
||||
* a number, a boolean, etc
|
||||
* @param {String} str
|
||||
* @return {*} castedStr
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._stringCast = function(str) {
|
||||
var lower = str.toLowerCase(),
|
||||
num = Number(str), // will nicely fail with '123ab'
|
||||
numFloat = parseFloat(str); // will nicely fail with ' '
|
||||
|
||||
if (str == '') {
|
||||
return '';
|
||||
}
|
||||
else if (lower == 'null') {
|
||||
return null;
|
||||
}
|
||||
else if (lower == 'true') {
|
||||
return true;
|
||||
}
|
||||
else if (lower == 'false') {
|
||||
return false;
|
||||
}
|
||||
else if (!isNaN(num) && !isNaN(numFloat)) {
|
||||
return num;
|
||||
}
|
||||
else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* escape a text, such that it can be displayed safely in an HTML element
|
||||
* @param {String} text
|
||||
|
|
|
@ -9,12 +9,14 @@ var MAX_PREVIEW_LINES = 100;
|
|||
|
||||
/**
|
||||
* Show advanced filter and transform modal using JMESPath
|
||||
* @param {Node} node the node to be transformed
|
||||
* @param {HTMLElement} container The container where to center
|
||||
* the modal and create an overlay
|
||||
* @param {JSON} json The json data to be transformed
|
||||
* @param {function} onTransform Callback invoked with the created
|
||||
* query as callback
|
||||
*/
|
||||
function showTransformModal (node, container) {
|
||||
var value = node.getValue();
|
||||
function showTransformModal (container, json, onTransform) {
|
||||
var value = json;
|
||||
|
||||
var content = '<label class="pico-modal-contents">' +
|
||||
'<div class="pico-modal-header">' + translate('transform') + '</div>' +
|
||||
|
@ -119,8 +121,9 @@ function showTransformModal (node, container) {
|
|||
wizard.innerHTML = '(wizard not available for objects, only for arrays)'
|
||||
}
|
||||
|
||||
var paths = node.getChildPaths();
|
||||
paths.forEach(function (path) {
|
||||
var sortablePaths = util.getChildPaths(json);
|
||||
|
||||
sortablePaths.forEach(function (path) {
|
||||
var formattedPath = preprocessPath(path);
|
||||
var filterOption = document.createElement('option');
|
||||
filterOption.text = formattedPath;
|
||||
|
@ -133,12 +136,11 @@ function showTransformModal (node, container) {
|
|||
sortField.appendChild(sortOption);
|
||||
});
|
||||
|
||||
var allPaths = node.getChildPaths(true).filter(function(path) {
|
||||
var selectablePaths = util.getChildPaths(json, true).filter(function(path) {
|
||||
return path !== '.';
|
||||
});
|
||||
|
||||
if (allPaths.length > 0) {
|
||||
allPaths.forEach(function (path) {
|
||||
if (selectablePaths.length > 0) {
|
||||
selectablePaths.forEach(function (path) {
|
||||
var formattedPath = preprocessPath(path);
|
||||
var option = document.createElement('option');
|
||||
option.text = formattedPath;
|
||||
|
@ -194,10 +196,9 @@ function showTransformModal (node, container) {
|
|||
? ['0'].concat(util.parsePath('.' + field1))
|
||||
: ['0']
|
||||
var exampleValue = util.get(value, examplePath)
|
||||
// TODO: move _stringCast into a static util function
|
||||
var value1 = typeof exampleValue === 'string'
|
||||
? filterValue.value
|
||||
: node._stringCast(filterValue.value);
|
||||
: parseString(filterValue.value);
|
||||
|
||||
query.value = '[? ' +
|
||||
field1 + ' ' +
|
||||
|
@ -284,7 +285,7 @@ function showTransformModal (node, container) {
|
|||
|
||||
modal.close();
|
||||
|
||||
node.transform(query.value)
|
||||
onTransform(query.value)
|
||||
};
|
||||
|
||||
setTimeout(function () {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var ace = require('./ace');
|
||||
var jmespath = require('jmespath');
|
||||
var translate = require('./i18n').translate;
|
||||
var ModeSwitcher = require('./ModeSwitcher');
|
||||
var showSortModal = require('./showSortModal');
|
||||
|
@ -173,24 +174,23 @@ textmode.create = function (container, options) {
|
|||
sort.className = 'jsoneditor-sort';
|
||||
sort.title = translate('sortTitleShort');
|
||||
sort.onclick = function () {
|
||||
me._showSortModal()
|
||||
me._showSortModal();
|
||||
};
|
||||
this.menu.appendChild(sort);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// // create transform button
|
||||
// if (this.options.enableTransform) {
|
||||
// var transform = document.createElement('button');
|
||||
// transform.type = 'button';
|
||||
// transform.title = translate('transformTitleShort');
|
||||
// transform.className = 'jsoneditor-transform';
|
||||
// transform.onclick = function () {
|
||||
// var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
||||
// showTransformModal(me.node, anchor)
|
||||
// };
|
||||
// this.menu.appendChild(transform);
|
||||
// }
|
||||
// create transform button
|
||||
if (this.options.enableTransform) {
|
||||
var transform = document.createElement('button');
|
||||
transform.type = 'button';
|
||||
transform.title = translate('transformTitleShort');
|
||||
transform.className = 'jsoneditor-transform';
|
||||
transform.onclick = function () {
|
||||
me._showTransformModal();
|
||||
};
|
||||
this.menu.appendChild(transform);
|
||||
}
|
||||
|
||||
// create repair button
|
||||
var buttonRepair = document.createElement('button');
|
||||
|
@ -468,6 +468,20 @@ textmode._showSortModal = function () {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a transform modal
|
||||
* @private
|
||||
*/
|
||||
textmode._showTransformModal = function () {
|
||||
var me = this;
|
||||
var anchor = this.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
||||
var json = this.get();
|
||||
showTransformModal(anchor, json, function (query) {
|
||||
var updatedJson = jmespath.search(json, query);
|
||||
me.set(updatedJson);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text selection
|
||||
* Calculates the cursor position and selection range and updates menu
|
||||
|
|
|
@ -10,13 +10,10 @@ var Node = require('./Node');
|
|||
var ModeSwitcher = require('./ModeSwitcher');
|
||||
var util = require('./util');
|
||||
var autocomplete = require('./autocomplete');
|
||||
var showTransformModal = require('./showTransformModal');
|
||||
var translate = require('./i18n').translate;
|
||||
var setLanguages = require('./i18n').setLanguages;
|
||||
var setLanguage = require('./i18n').setLanguage;
|
||||
|
||||
var DEFAULT_MODAL_ANCHOR = document.body; // TODO: this constant is defined twice
|
||||
|
||||
// create a mixin with the functions for tree mode
|
||||
var treemode = {};
|
||||
|
||||
|
@ -1033,8 +1030,7 @@ treemode._createFrame = function () {
|
|||
transform.title = translate('transformTitleShort');
|
||||
transform.className = 'jsoneditor-transform';
|
||||
transform.onclick = function () {
|
||||
var anchor = editor.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
||||
showTransformModal(editor.node, anchor)
|
||||
editor.node.showTransformModal();
|
||||
};
|
||||
this.menu.appendChild(transform);
|
||||
}
|
||||
|
|
|
@ -1264,6 +1264,38 @@ exports.sortObjectKeys = function (object, direction) {
|
|||
return sortedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast contents of a string to the correct type.
|
||||
* This can be a string, a number, a boolean, etc
|
||||
* @param {String} str
|
||||
* @return {*} castedStr
|
||||
* @private
|
||||
*/
|
||||
exports.parseString = function(str) {
|
||||
var lower = str.toLowerCase();
|
||||
var num = Number(str); // will nicely fail with '123ab'
|
||||
var numFloat = parseFloat(str); // will nicely fail with ' '
|
||||
|
||||
if (str === '') {
|
||||
return '';
|
||||
}
|
||||
else if (lower === 'null') {
|
||||
return null;
|
||||
}
|
||||
else if (lower === 'true') {
|
||||
return true;
|
||||
}
|
||||
else if (lower === 'false') {
|
||||
return false;
|
||||
}
|
||||
else if (!isNaN(num) && !isNaN(numFloat)) {
|
||||
return num;
|
||||
}
|
||||
else {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether a value is an Object
|
||||
* @param {*} value
|
||||
|
|
|
@ -353,6 +353,15 @@ describe('util', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should parse a string', function () {
|
||||
assert.strictEqual(util.parseString('foo'), 'foo');
|
||||
assert.strictEqual(util.parseString('234foo'), '234foo');
|
||||
assert.strictEqual(util.parseString('2.3'), 2.3);
|
||||
assert.strictEqual(util.parseString('null'), null);
|
||||
assert.strictEqual(util.parseString('true'), true);
|
||||
assert.strictEqual(util.parseString('false'), false);
|
||||
})
|
||||
|
||||
it('should find a unique name', function () {
|
||||
assert.strictEqual(util.findUniqueName('other', [
|
||||
'a',
|
||||
|
|
Loading…
Reference in New Issue