Merge branch 'develop' of https://github.com/josdejong/jsoneditor into get_caret_position

# Conflicts:
#	docs/api.md
#	src/js/Node.js
#	src/js/treemode.js
This commit is contained in:
Meir Rotstein 2018-04-02 02:07:53 +03:00
commit 3b186633e7
28 changed files with 6148 additions and 492 deletions

View File

@ -3,13 +3,36 @@
https://github.com/josdejong/jsoneditor
## not yet released, version 5.13.2
## 2018-03-21, version 5.14.1
- Fixed absolute path of css image `jsoneditor-icons.svg`, which could.
give issues with webpack plugin "file-loader". Thanks @landru29.
## 2018-02-25, version 5.14.0
- Implemented support for translations. Thanks @mariohmol.
- Fixed a bug sometimes occurring when dragging items from array to
object, see #509. Thanks @43081j.
- Fixed autocomplete not accepting returned `null` values, see #512.
Thanks @43081j.
- Fixed memory inefficiency when working with large JSON Schema's
generating many errors. Thanks @43081j.
## 2018-02-07, version 5.13.3
- Fixed a positioning issue with JSON Schema errors in text/code mode.
## 2018-01-18, version 5.13.2
- Fixed view mode opening links in a new tab instead of current tab
when Ctrl key is not down. Thanks @LEW21.
- Fixed #502: code editor not showing a monospaced font some cases.
## 2018-12-28, version 5.13.1
## 2017-12-28, version 5.13.1
- Fixed another occurrence of #494: properties not escaped in the
navigation bar.

View File

@ -67,10 +67,15 @@ with bower:
#### More
There is a directive available for using JSONEditor in Angular.js:
There is a directive available for using JSONEditor in AngularJS:
[https://github.com/isonet/angular-jsoneditor](https://github.com/isonet/angular-jsoneditor)
Directive for Angular 5.x as well:
[https://github.com/mariohmol/ang-jsoneditor](https://github.com/mariohmol/ang-jsoneditor)
## Use

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
dist/jsoneditor.css vendored
View File

@ -310,7 +310,7 @@ div.jsoneditor td,
div.jsoneditor th,
div.jsoneditor textarea,
.jsoneditor-schema-error {
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
@ -974,7 +974,7 @@ div.jsoneditor div.autocomplete.dropdown {
padding-right: 5pt;
text-align: left;
outline: 0;
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
font-size: 10pt;
}
@ -1021,7 +1021,7 @@ div.jsoneditor-treepath span.jsoneditor-treepath-seperator:hover {
div.jsoneditor-statusbar {
line-height: 26px;
height: 26px;
margin-top: -26px;
margin-top: -1px;
color: #808080;
background-color: #ebebeb;
border-top: 1px solid #d3d3d3;

554
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

File diff suppressed because one or more lines are too long

View File

@ -125,7 +125,7 @@ Constructs a new JSONEditor.
The following example allow you can create a "Person" node and a "Address" node, each one will appear in your context menu, once you selected the whole json object will be created.
```js
```js
var options = {
templates: [
{
@ -226,6 +226,29 @@ Constructs a new JSONEditor.
}
```
Only applicable when `mode` is 'tree'.
- `{string} language`
The default language comes from the browser navigator, but you can force a specific language. So use here string as 'en' or 'pt-BR'. Built-in languages: `en`, `pt-BR`. Other translations can be specified via the option `languages`.
- `{Object} languages`
You can override existing translations or provide a new translation for a specific language. To do it provide an object at languages with language and the keys/values to be inserted. For example:
```
'languages': {
'pt-BR': {
'auto': 'Automático testing'
},
'en': {
'auto': 'Auto testing'
}
}
```
All available fields for translation can be found in the source file `src/js/i18n.js`.
### Methods

View File

@ -0,0 +1,57 @@
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor | Translate</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
JSONEditor has support for multiple languages (i18n), in this case uses <code>pt-BR</code>.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
var container = document.getElementById('jsoneditor');
var options = {
// switch between pt-BR or en for testing forcing a language
// leave blank to get language
'language': 'pt-BR',
'languages': {
'pt-BR': {
'auto': 'Automático testing'
},
'en': {
'auto': 'Auto testing'
},
'newlang': {
'auto': 'Auto new lang'
}
}
};
var editor = new JSONEditor(container, options);
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': { 'a': 'b', 'c': 'd' },
'string': 'Hello World'
};
editor.set(json);
</script>
</body>
</html>

5001
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "jsoneditor",
"version": "5.13.1",
"version": "5.14.1",
"main": "./index",
"description": "A web-based tool to view, edit, format, and validate JSON",
"tags": [

View File

@ -13,7 +13,7 @@ div.jsoneditor div.autocomplete.dropdown {
padding-right: 5pt;
text-align: left;
outline: 0;
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
font-size: 10pt;
}

View File

@ -86,7 +86,7 @@ div.jsoneditor-contextmenu div.jsoneditor-icon {
border: none;
padding: 0;
margin: 0;
background-image: url('img/jsoneditor-icons.svg');
background-image: url('./img/jsoneditor-icons.svg');
}
div.jsoneditor-contextmenu ul li ul div.jsoneditor-icon {
@ -110,7 +110,7 @@ div.jsoneditor-contextmenu ul li button div.jsoneditor-expand {
height: 24px;
padding: 0;
margin: 0 4px 0 0;
background: url('img/jsoneditor-icons.svg') 0 -72px;
background: url('./img/jsoneditor-icons.svg') 0 -72px;
opacity: 0.4;
}

View File

@ -131,7 +131,7 @@ div.jsoneditor-tree button {
margin: 0;
border: none;
cursor: pointer;
background: transparent url('img/jsoneditor-icons.svg');
background: transparent url('./img/jsoneditor-icons.svg');
}
div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree,
@ -263,7 +263,7 @@ tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
}
div.jsoneditor-tree button.jsoneditor-dragarea {
background: url('img/jsoneditor-icons.svg') -72px -72px;
background: url('./img/jsoneditor-icons.svg') -72px -72px;
cursor: move;
}
@ -294,7 +294,7 @@ div.jsoneditor td,
div.jsoneditor th,
div.jsoneditor textarea,
.jsoneditor-schema-error {
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
@ -320,7 +320,7 @@ div.jsoneditor-tree .jsoneditor-schema-error {
height: 24px;
padding: 0;
margin: 0 4px 0 0;
background: url('img/jsoneditor-icons.svg') -168px -48px;
background: url('./img/jsoneditor-icons.svg') -168px -48px;
}
.jsoneditor-schema-error .jsoneditor-popover {
@ -454,6 +454,6 @@ div.jsoneditor-tree .jsoneditor-schema-error {
height: 24px;
padding: 0;
margin: 0 4px 0 0;
background: url('img/jsoneditor-icons.svg') -168px -48px;
background: url('./img/jsoneditor-icons.svg') -168px -48px;
}

View File

@ -21,7 +21,7 @@ div.jsoneditor-menu > div.jsoneditor-modes > button {
padding: 0;
border-radius: 2px;
border: 1px solid transparent;
background: transparent url('img/jsoneditor-icons.svg');
background: transparent url('./img/jsoneditor-icons.svg');
color: white;
opacity: 0.8;

View File

@ -46,7 +46,7 @@ table.jsoneditor-search button {
padding: 0;
margin: 0;
border: none;
background: url('img/jsoneditor-icons.svg');
background: url('./img/jsoneditor-icons.svg');
vertical-align: top;
}

View File

@ -1,7 +1,7 @@
div.jsoneditor-statusbar {
line-height: 26px;
height: 26px;
margin-top: -26px;
margin-top: -1px;
color: #808080;
background-color: #ebebeb;
border-top: 1px solid #d3d3d3;
@ -9,7 +9,6 @@ div.jsoneditor-statusbar {
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-size: 10pt;
}
div.jsoneditor-statusbar > .jsoneditor-curserinfo-label {

View File

@ -1,6 +1,7 @@
'use strict';
var util = require('./util');
var translate = require('./i18n').translate;
/**
* Node.getRootNode shim
@ -151,7 +152,7 @@ function ContextMenu (items, options) {
else {
// no submenu, just a button with clickhandler
button.innerHTML = '<div class="jsoneditor-icon"></div>' +
'<div class="jsoneditor-text">' + item.text + '</div>';
'<div class="jsoneditor-text">' + translate(item.text) + '</div>';
}
domItems.push(domItem);

View File

@ -91,7 +91,7 @@ function JSONEditor (container, options, json) {
'ace', 'theme','autocomplete',
'onChange', 'onEditable', 'onError', 'onModeChange', 'onSelectionChange', 'onTextSelectionChange',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
'sortObjectKeys', 'navigationBar', 'statusBar'
'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language'
];
Object.keys(options).forEach(function (option) {

View File

@ -4,6 +4,7 @@ var naturalSort = require('javascript-natural-sort');
var ContextMenu = require('./ContextMenu');
var appendNodeFactory = require('./appendNodeFactory');
var util = require('./util');
var translate = require('./i18n').translate;
/**
* @constructor Node
@ -995,7 +996,7 @@ Node.prototype._move = function(node, beforeNode) {
// check if this node is not a child of the node to be moved here
if (node.containsNode(this)) {
throw new Error('Cannot move a field into a child of itself');
throw new Error(translate('validationCannotMove'));
}
// remove the original node
@ -1239,14 +1240,15 @@ Node.prototype._onChangeField = function () {
// get current selection, then override the range such that we can select
// the added/removed text on undo/redo
var oldSelection = this.editor.getDomSelection();
var previous = this.previousField || '';
if (oldSelection.range) {
var undoDiff = util.textDiff(this.field, this.previousField);
var undoDiff = util.textDiff(this.field, previous);
oldSelection.range.startOffset = undoDiff.start;
oldSelection.range.endOffset = undoDiff.end;
}
var newSelection = this.editor.getDomSelection();
if (newSelection.range) {
var redoDiff = util.textDiff(this.previousField, this.field);
var redoDiff = util.textDiff(previous, this.field);
newSelection.range.startOffset = redoDiff.start;
newSelection.range.endOffset = redoDiff.end;
}
@ -1306,7 +1308,7 @@ Node.prototype._updateDomValue = function () {
domValue.title = this.type + ' containing ' + count + ' items';
}
else if (isUrl && this.editable.value) {
domValue.title = 'Ctrl+Click or Ctrl+Enter to open url in new window';
domValue.title = translate('openUrl');
}
else {
domValue.title = '';
@ -1493,7 +1495,7 @@ Node.prototype.validate = function () {
return {
node: node,
error: {
message: 'duplicate key "' + node.field + '"'
message: translate('duplicateKey') + ' "' + node.field + '"'
}
}
});
@ -1550,7 +1552,7 @@ Node.prototype.getDom = function() {
domDrag.type = 'button';
dom.drag = domDrag;
domDrag.className = 'jsoneditor-dragarea';
domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)';
domDrag.title = translate('drag');
tdDrag.appendChild(domDrag);
}
}
@ -1562,7 +1564,7 @@ Node.prototype.getDom = function() {
menu.type = 'button';
dom.menu = menu;
menu.className = 'jsoneditor-contextmenu';
menu.title = 'Click to open the actions menu (Ctrl+M)';
menu.title = translate('actionsMenu');
tdMenu.appendChild(dom.menu);
dom.tr.appendChild(tdMenu);
}
@ -2219,9 +2221,7 @@ Node.prototype._createDomExpandButton = function () {
expand.type = 'button';
if (this._hasChilds()) {
expand.className = this.expanded ? 'jsoneditor-expanded' : 'jsoneditor-collapsed';
expand.title =
'Click to expand/collapse this field (Ctrl+E). \n' +
'Ctrl+Click to expand/collapse including all childs.';
expand.title = translate('expandTitle');
}
else {
expand.className = 'jsoneditor-invisible';
@ -3249,16 +3249,10 @@ Node.prototype._hasChilds = function () {
// titles with explanation for the different types
Node.TYPE_TITLES = {
'auto': 'Field type "auto". ' +
'The field type is automatically determined from the value ' +
'and can be a string, number, boolean, or null.',
'object': 'Field type "object". ' +
'An object contains an unordered set of key/value pairs.',
'array': 'Field type "array". ' +
'An array contains an ordered collection of values.',
'string': 'Field type "string". ' +
'Field type is not determined from the value, ' +
'but always returned as string.'
'auto': translate('autoType'),
'object': translate('objectType'),
'array': translate('arrayType'),
'string': translate('stringType')
};
Node.prototype.addTemplates = function (menu, append) {
@ -3301,12 +3295,12 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
if (this.editable.value) {
items.push({
text: 'Type',
title: 'Change the type of this field',
text: translate('type'),
title: translate('typeTitle'),
className: 'jsoneditor-type-' + this.type,
submenu: [
{
text: 'Auto',
text: translate('auto'),
className: 'jsoneditor-type-auto' +
(this.type == 'auto' ? ' jsoneditor-selected' : ''),
title: titles.auto,
@ -3315,7 +3309,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Array',
text: translate('array'),
className: 'jsoneditor-type-array' +
(this.type == 'array' ? ' jsoneditor-selected' : ''),
title: titles.array,
@ -3324,7 +3318,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Object',
text: translate('object'),
className: 'jsoneditor-type-object' +
(this.type == 'object' ? ' jsoneditor-selected' : ''),
title: titles.object,
@ -3333,7 +3327,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'String',
text: translate('string'),
className: 'jsoneditor-type-string' +
(this.type == 'string' ? ' jsoneditor-selected' : ''),
title: titles.string,
@ -3348,25 +3342,25 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
if (this._hasChilds()) {
var direction = ((this.sortOrder == 'asc') ? 'desc': 'asc');
items.push({
text: 'Sort',
title: 'Sort the childs of this ' + this.type,
text: translate('sort'),
title: translate('sortTitle') + this.type,
className: 'jsoneditor-sort-' + direction,
click: function () {
node.sort(direction);
},
submenu: [
{
text: 'Ascending',
text: translate('ascending'),
className: 'jsoneditor-sort-asc',
title: 'Sort the childs of this ' + this.type + ' in ascending order',
title: translate('ascendingTitle' , {type: this.type}),
click: function () {
node.sort('asc');
}
},
{
text: 'Descending',
text: translate('descending'),
className: 'jsoneditor-sort-desc',
title: 'Sort the childs of this ' + this.type +' in descending order',
title: translate('descendingTitle' , {type: this.type}),
click: function () {
node.sort('desc');
}
@ -3388,7 +3382,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
if (node == childs[childs.length - 1]) {
var appendSubmenu = [
{
text: 'Auto',
text: translate('auto'),
className: 'jsoneditor-type-auto',
title: titles.auto,
click: function () {
@ -3396,7 +3390,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Array',
text: translate('array'),
className: 'jsoneditor-type-array',
title: titles.array,
click: function () {
@ -3404,7 +3398,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Object',
text: translate('object'),
className: 'jsoneditor-type-object',
title: titles.object,
click: function () {
@ -3412,7 +3406,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'String',
text: translate('string'),
className: 'jsoneditor-type-string',
title: titles.string,
click: function () {
@ -3422,9 +3416,9 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
];
node.addTemplates(appendSubmenu, true);
items.push({
text: 'Append',
title: 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)',
submenuTitle: 'Select the type of the field to be appended',
text: translate('appendText'),
title: translate('appendTitle'),
submenuTitle: translate('appendSubmenuTitle'),
className: 'jsoneditor-append',
click: function () {
node._onAppend('', '', 'auto');
@ -3438,7 +3432,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
// create insert button
var insertSubmenu = [
{
text: 'Auto',
text: translate('auto'),
className: 'jsoneditor-type-auto',
title: titles.auto,
click: function () {
@ -3446,7 +3440,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Array',
text: translate('array'),
className: 'jsoneditor-type-array',
title: titles.array,
click: function () {
@ -3454,7 +3448,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'Object',
text: translate('object'),
className: 'jsoneditor-type-object',
title: titles.object,
click: function () {
@ -3462,7 +3456,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
}
},
{
text: 'String',
text: translate('string'),
className: 'jsoneditor-type-string',
title: titles.string,
click: function () {
@ -3472,9 +3466,9 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
];
node.addTemplates(insertSubmenu, false);
items.push({
text: 'Insert',
title: 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)',
submenuTitle: 'Select the type of the field to be inserted',
text: translate('insert'),
title: translate('insertTitle'),
submenuTitle: translate('insertSub'),
className: 'jsoneditor-insert',
click: function () {
node._onInsertBefore('', '', 'auto');
@ -3485,8 +3479,8 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
if (this.editable.field) {
// create duplicate button
items.push({
text: 'Duplicate',
title: 'Duplicate this field (Ctrl+D)',
text: translate('duplicateText'),
title: translate('duplicateField'),
className: 'jsoneditor-duplicate',
click: function () {
Node.onDuplicate(node);
@ -3495,8 +3489,8 @@ Node.prototype.showContextMenu = function (anchor, onClose) {
// create remove button
items.push({
text: 'Remove',
title: 'Remove this field (Ctrl+Del)',
text: translate('removeText'),
title: translate('removeField'),
className: 'jsoneditor-remove',
click: function () {
Node.onRemove(node);

View File

@ -38,7 +38,7 @@ color: #333\
}\
\
.ace-jsoneditor.ace_editor {\
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;\
font-family: \"dejavu sans mono\", \"droid sans mono\", consolas, monaco, \"lucida console\", \"courier new\", courier, monospace, sans-serif;\
line-height: 1.3;\
background-color: #fff;\
}\

View File

@ -2,6 +2,7 @@
var util = require('./util');
var ContextMenu = require('./ContextMenu');
var translate = require('./i18n').translate;
/**
* A factory function to create an AppendNode, which depends on a Node
@ -62,7 +63,7 @@ function appendNodeFactory(Node) {
// a cell for the contents (showing text 'empty')
var tdAppend = document.createElement('td');
var domText = document.createElement('div');
domText.innerHTML = '(empty)';
domText.innerHTML = '(' + translate('empty') + ')';
domText.className = 'jsoneditor-readonly';
tdAppend.appendChild(domText);
dom.td = tdAppend;
@ -86,7 +87,7 @@ function appendNodeFactory(Node) {
var domText = dom.text;
if (domText) {
domText.innerHTML = '(empty ' + this.parent.type + ')';
domText.innerHTML = '(' + translate('empty') + ' ' + this.parent.type + ')';
}
// attach or detach the contents of the append node:
@ -136,7 +137,7 @@ function appendNodeFactory(Node) {
var titles = Node.TYPE_TITLES;
var appendSubmenu = [
{
text: 'Auto',
text: translate('auto'),
className: 'jsoneditor-type-auto',
title: titles.auto,
click: function () {
@ -144,7 +145,7 @@ function appendNodeFactory(Node) {
}
},
{
text: 'Array',
text: translate('array'),
className: 'jsoneditor-type-array',
title: titles.array,
click: function () {
@ -152,7 +153,7 @@ function appendNodeFactory(Node) {
}
},
{
text: 'Object',
text: translate('object'),
className: 'jsoneditor-type-object',
title: titles.object,
click: function () {
@ -160,7 +161,7 @@ function appendNodeFactory(Node) {
}
},
{
text: 'String',
text: translate('string'),
className: 'jsoneditor-type-string',
title: titles.string,
click: function () {
@ -172,9 +173,9 @@ function appendNodeFactory(Node) {
var items = [
// create append button
{
'text': 'Append',
'title': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)',
'submenuTitle': 'Select the type of the field to be appended',
'text': translate('appendText'),
'title': translate('appendTitleAuto'),
'submenuTitle': translate('appendSubmenuTitle'),
'className': 'jsoneditor-insert',
'click': function () {
node._onAppend('', '', 'auto');

159
src/js/i18n.js Normal file
View File

@ -0,0 +1,159 @@
'use strict';
var _locales = ['en', 'pt-BR'];
var _defs = {
en: {
'array': 'Array',
'auto': 'Auto',
'appendText': 'Append',
'appendTitle': 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)',
'appendSubmenuTitle': 'Select the type of the field to be appended',
'appendTitleAuto': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)',
'ascending': 'Ascending',
'ascendingTitle': 'Sort the childs of this ${type} in ascending order',
'actionsMenu': 'Click to open the actions menu (Ctrl+M)',
'collapseAll': 'Collapse all fields',
'descending': 'Descending',
'descendingTitle': 'Sort the childs of this ${type} in descending order',
'drag': 'Drag to move this field (Alt+Shift+Arrows)',
'duplicateKey': 'duplicate key',
'duplicateText': 'Duplicate',
'duplicateTitle': 'Duplicate selected fields (Ctrl+D)',
'duplicateField': 'Duplicate this field (Ctrl+D)',
'empty': 'empty',
'expandAll': 'Expand all fields',
'expandTitle': 'Click to expand/collapse this field (Ctrl+E). \n' +
'Ctrl+Click to expand/collapse including all childs.',
'insert': 'Insert',
'insertTitle': 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)',
'insertSub': 'Select the type of the field to be inserted',
'object': 'Object',
'redo': 'Redo (Ctrl+Shift+Z)',
'removeText': 'Remove',
'removeTitle': 'Remove selected fields (Ctrl+Del)',
'removeField': 'Remove this field (Ctrl+Del)',
'sort': 'Sort',
'sortTitle': 'Sort the childs of this ',
'string': 'String',
'type': 'Type',
'typeTitle': 'Change the type of this field',
'openUrl': 'Ctrl+Click or Ctrl+Enter to open url in new window',
'undo': 'Undo last action (Ctrl+Z)',
'validationCannotMove': 'Cannot move a field into a child of itself',
'autoType': 'Field type "auto". ' +
'The field type is automatically determined from the value ' +
'and can be a string, number, boolean, or null.',
'objectType': 'Field type "object". ' +
'An object contains an unordered set of key/value pairs.',
'arrayType': 'Field type "array". ' +
'An array contains an ordered collection of values.',
'stringType': 'Field type "string". ' +
'Field type is not determined from the value, ' +
'but always returned as string.'
},
'pt-BR': {
'array': 'Lista',
'auto': 'Automatico',
'appendText': 'Adicionar',
'appendTitle': 'Adicionar novo campo com tipo \'auto\' depois deste campo (Ctrl+Shift+Ins)',
'appendSubmenuTitle': 'Selecione o tipo do campo a ser adicionado',
'appendTitleAuto': 'Adicionar novo campo com tipo \'auto\' (Ctrl+Shift+Ins)',
'ascending': 'Ascendente',
'ascendingTitle': 'Organizar filhor do tipo ${type} em crescente',
'actionsMenu': 'Clique para abrir o menu de ações (Ctrl+M)',
'collapseAll': 'Fechar todos campos',
'descending': 'Descendente',
'descendingTitle': 'Organizar o filhos do tipo ${type} em decrescente',
'duplicateKey': 'chave duplicada',
'drag': 'Arraste para mover este campo (Alt+Shift+Arrows)',
'duplicateText': 'Duplicar',
'duplicateTitle': 'Duplicar campos selecionados (Ctrl+D)',
'duplicateField': 'Duplicar este campo (Ctrl+D)',
'empty': 'vazio',
'expandAll': 'Expandir todos campos',
'expandTitle': 'Clique para expandir/encolher este campo (Ctrl+E). \n' +
'Ctrl+Click para expandir/encolher incluindo todos os filhos.',
'insert': 'Inserir',
'insertTitle': 'Inserir um novo campo do tipo \'auto\' antes deste campo (Ctrl+Ins)',
'insertSub': 'Selecionar o tipo de campo a ser inserido',
'object': 'Objeto',
'redo': 'Refazer (Ctrl+Shift+Z)',
'removeText': 'Remover',
'removeTitle': 'Remover campos selecionados (Ctrl+Del)',
'removeField': 'Remover este campo (Ctrl+Del)',
'sort': 'Organizar',
'sortTitle': 'Organizar os filhos deste ',
'string': 'Texto',
'type': 'Tipo',
'typeTitle': 'Mudar o tipo deste campo',
'openUrl': 'Ctrl+Click ou Ctrl+Enter para abrir link em nova janela',
'undo': 'Desfazer último ação (Ctrl+Z)',
'validationCannotMove': 'Não pode mover um campo como filho dele mesmo',
'autoType': 'Campo do tipo "auto". ' +
'O tipo do campo é determinao automaticamente a partir do seu valor ' +
'e pode ser texto, número, verdade/falso ou nulo.',
'objectType': 'Campo do tipo "objeto". ' +
'Um objeto contém uma lista de pares com chave e valor.',
'arrayType': 'Campo do tipo "lista". ' +
'Uma lista contem uma coleção de valores ordenados.',
'stringType': 'Campo do tipo "string". ' +
'Campo do tipo nao é determinado através do seu valor, ' +
'mas sempre retornara um texto.'
}
};
var _defaultLang = 'en';
var _lang;
var userLang = navigator.language || navigator.userLanguage;
_lang = _locales.find(function (l) {
return l === userLang;
});
if (!_lang) {
_lang = _defaultLang;
}
module.exports = {
// supported locales
_locales: _locales,
_defs: _defs,
_lang: _lang,
setLanguage: function (lang) {
if (!lang) {
return;
}
var langFound = _locales.find(function (l) {
return l === lang;
});
if (langFound) {
_lang = langFound;
} else {
console.error('Language not found');
}
},
setLanguages: function (languages) {
if (!languages) {
return;
}
for (var key in languages) {
var langFound = _locales.find(function (l) {
return l === key;
});
if (!langFound) {
_locales.push(key);
}
_defs[key] = Object.assign({}, _defs[_defaultLang], _defs[key], languages[key]);
}
},
translate: function (key, data, lang) {
if (!lang) {
lang = _lang;
}
var text = _defs[lang][key];
if (data) {
for (key in data) {
text = text.replace('${' + key + '}', data[key]);
}
}
return text || key;
}
};

View File

@ -252,11 +252,17 @@ textmode.create = function (container, options) {
textarea.onblur = this._onBlur.bind(this);
}
var validationErrorsContainer = document.createElement('div');
validationErrorsContainer.className = 'validation-errors-container';
this.dom.validationErrorsContainer = validationErrorsContainer;
this.frame.appendChild(validationErrorsContainer);
if (options.statusBar) {
util.addClassName(this.content, 'has-status-bar');
this.curserInfoElements = {};
var statusBar = document.createElement('div');
this.dom.statusBar = statusBar;
statusBar.className = 'jsoneditor-statusbar';
this.frame.appendChild(statusBar);
@ -651,9 +657,10 @@ textmode.validate = function () {
'</table>';
this.dom.validationErrors = validationErrors;
this.frame.appendChild(validationErrors);
this.dom.validationErrorsContainer.appendChild(validationErrors);
var height = validationErrors.clientHeight;
var height = validationErrors.clientHeight +
(this.dom.statusBar ? this.dom.statusBar.clientHeight : 0);
this.content.style.marginBottom = (-height) + 'px';
this.content.style.paddingBottom = height + 'px';
}

View File

@ -10,6 +10,9 @@ var Node = require('./Node');
var ModeSwitcher = require('./ModeSwitcher');
var util = require('./util');
var autocomplete = require('./autocomplete');
var translate = require('./i18n').translate;
var setLanguages = require('./i18n').setLanguages;
var setLanguage = require('./i18n').setLanguage;
// create a mixin with the functions for tree mode
var treemode = {};
@ -137,6 +140,9 @@ treemode._setOptions = function (options) {
if (options.onSelectionChange) {
this.onSelectionChange(options.onSelectionChange);
}
setLanguages(this.options.languages);
setLanguage(this.options.language)
};
/**
@ -440,28 +446,35 @@ treemode.validate = function () {
}
}
// display the error in the nodes with a problem
this.errorNodes = duplicateErrors
.concat(schemaErrors)
.reduce(function expandParents (all, entry) {
// expand parents, then merge such that parents come first and
// original entries last
return entry.node
.findParents()
.map(function (parent) {
return {
node: parent,
child: entry.node,
error: {
message: parent.type === 'object'
? 'Contains invalid properties' // object
: 'Contains invalid items' // array
}
};
})
.concat(all, [entry]);
}, [])
// TODO: dedupe the parent nodes
var errorNodes = duplicateErrors.concat(schemaErrors);
var parentPairs = errorNodes
.reduce(function (all, entry) {
return entry.node
.findParents()
.filter(function (parent) {
return !all.some(function (pair) {
return pair[0] === parent;
});
})
.map(function (parent) {
return [parent, entry.node];
})
.concat(all);
}, []);
this.errorNodes = parentPairs
.map(function (pair) {
return {
node: pair[0],
child: pair[1],
error: {
message: pair[0].type === 'object'
? 'Contains invalid properties' // object
: 'Contains invalid items' // array
}
};
})
.concat(errorNodes)
.map(function setError (entry) {
entry.node.setError(entry.error, entry.child);
return entry.node;
@ -700,7 +713,7 @@ treemode._createFrame = function () {
var expandAll = document.createElement('button');
expandAll.type = 'button';
expandAll.className = 'jsoneditor-expand-all';
expandAll.title = 'Expand all fields';
expandAll.title = translate('expandAll');
expandAll.onclick = function () {
editor.expandAll();
};
@ -709,7 +722,7 @@ treemode._createFrame = function () {
// create collapse all button
var collapseAll = document.createElement('button');
collapseAll.type = 'button';
collapseAll.title = 'Collapse all fields';
collapseAll.title = translate('collapseAll');
collapseAll.className = 'jsoneditor-collapse-all';
collapseAll.onclick = function () {
editor.collapseAll();
@ -722,7 +735,7 @@ treemode._createFrame = function () {
var undo = document.createElement('button');
undo.type = 'button';
undo.className = 'jsoneditor-undo jsoneditor-separator';
undo.title = 'Undo last action (Ctrl+Z)';
undo.title = translate('undo');
undo.onclick = function () {
editor._onUndo();
};
@ -733,7 +746,7 @@ treemode._createFrame = function () {
var redo = document.createElement('button');
redo.type = 'button';
redo.className = 'jsoneditor-redo';
redo.title = 'Redo (Ctrl+Shift+Z)';
redo.title = translate('redo');
redo.onclick = function () {
editor._onRedo();
};
@ -1233,13 +1246,18 @@ treemode._onKeyDown = function (event) {
setTimeout(function (hnode, element) {
if (element.innerText.length > 0) {
var result = this.options.autocomplete.getOptions(element.innerText, hnode.getPath(), jsonElementType, hnode.editor);
if (typeof result.then === 'function') {
if (result === null) {
this.autocomplete.hideDropDown();
} else if (typeof result.then === 'function') {
// probably a promise
if (result.then(function (obj) {
if (obj.options)
if (obj === null) {
this.autocomplete.hideDropDown();
} else if (obj.options) {
this.autocomplete.show(element, obj.startFrom, obj.options);
else
} else {
this.autocomplete.show(element, 0, obj);
}
}.bind(this)));
} else {
// definitely not a promise
@ -1317,8 +1335,8 @@ treemode.showContextMenu = function (anchor, onClose) {
// create duplicate button
items.push({
text: 'Duplicate',
title: 'Duplicate selected fields (Ctrl+D)',
text: translate('duplicateText'),
title: translate('duplicateTitle'),
className: 'jsoneditor-duplicate',
click: function () {
Node.onDuplicate(editor.multiselection.nodes);
@ -1327,8 +1345,8 @@ treemode.showContextMenu = function (anchor, onClose) {
// create remove button
items.push({
text: 'Remove',
title: 'Remove selected fields (Ctrl+Del)',
text: translate('remove'),
title: translate('removeTitle'),
className: 'jsoneditor-remove',
click: function () {
Node.onRemove(editor.multiselection.nodes);