Compare commits

...

64 Commits

Author SHA1 Message Date
ZaneYork ecebf360b3 Add text-plain mode 2020-10-16 15:32:07 +08:00
dependabot-preview[bot] b64e012da8
Bump uglify-js from 3.10.4 to 3.11.1 (#1123)
Bumps [uglify-js](https://github.com/mishoo/UglifyJS) from 3.10.4 to 3.11.1.
- [Release notes](https://github.com/mishoo/UglifyJS/releases)
- [Commits](https://github.com/mishoo/UglifyJS/compare/v3.10.4...v3.11.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-07 09:56:16 +02:00
Jos de Jong 8eb4819d0e Fix lint error 2020-09-23 15:49:44 +02:00
Jos de Jong e35e39ff2f Merge remote-tracking branch 'origin/develop' into develop 2020-09-23 15:44:11 +02:00
Jos de Jong 58f460a383 Log a clear error in the console when the returned value of `onEditable` is invalid. See #1112 2020-09-23 15:44:04 +02:00
dependabot-preview[bot] 1492f22eea
Bump webpack from 4.44.1 to 4.44.2 (#1114)
Bumps [webpack](https://github.com/webpack/webpack) from 4.44.1 to 4.44.2.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.44.1...v4.44.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-23 11:40:05 +02:00
Jos de Jong 223b78542e Publish v9.1.1 2020-09-23 10:33:34 +02:00
Jos de Jong e1a8077dc1 Fix quick-key `Ctrl+D` (duplicate) not working 2020-09-23 10:27:47 +02:00
Jos de Jong 745a1597dd Fix linter issue 2020-09-23 10:25:26 +02:00
Jos de Jong 2a861a2868 Defined charset="utf-8" and lang="en" in all examples 2020-09-23 10:23:38 +02:00
Josh Kelley 69fbe63f0e
Multi-select mouse events now honor the event's window (#1098)
* Multi-select mouse events now honor the event's window

This prevents errors from opening JSONEditor in a child window (such as `window.open` or third-party libraries like react-new-window).

* Add a demo of showing a JSONEditor in a child window

* Minor spelling fixes

* Further improvements to new window support

Use `event.view` instead of the global `window`. Copy VanillaPicker styles in the example so that the color picker is correctly styled.

* Add 'noopener'

This helps security; otherwise, JavaScript running in the context of the new window can access the original window object via the `window.opener` property, even if it's a different origin.

* Update modal handling for new windows

There are two approaches we could take; we could use the existing modalAnchor property and make callers responsible for setting it, or we could modify the default handling to default to the node's container body. For now, I chose to make callers responsible.

Rename showTransformModal's `anchor` parameter to `container`; as far as I can tell, `anchor` didn't work properly.
2020-09-23 10:06:12 +02:00
Jos de Jong f3694c3126 Update history 2020-09-23 09:45:37 +02:00
Žiga Miklič 6cf627a61a
Fix for issue #1111 (#1116)
Fixes enum dropdown not showing when using patternProperties for schema.

The issue happens as `_findSchema` is recursively called one more than than it should. Instead of returning the nested schema object (eg. `{ enum: [1, 2, 3] }`), it returns the parent object, eg.:

```javascript
{
  type: 'object',
  properties: {
    testrigId: {
      enum: [1, 2, 3]
    },
  },
  required: [
    'testrigId'
  ]
}
```

The fix adds an if check to ignore the additional recursive call and return the correct object.

The unit tests pass and I've also tested a complex schema inside `patternProperties` that uses the special types (boolean, color, enum).
2020-09-23 09:43:44 +02:00
Jos de Jong 41fbf6973f Publish v9.1.0 2020-09-15 20:51:01 +02:00
Jos de Jong 07e4221fad Fix quick-keys `Ctrl-\` (format) and `Ctrl-Shift-\` (compact) not working in `code` mode (see #1107) 2020-09-15 20:47:28 +02:00
Jos de Jong 8855944bae Update history and docs with new translation `de` 2020-09-14 20:05:34 +02:00
Stephan Ahlf 09b8ed8af6
Add German language support to i18n.js (#1105)
* Add German language support to i18n.js

* add `de` to `_locales` variable

* fix code format to fit JavaScript Standard Style

* fix variable typo in "de" dictionary

* add new containsInvalidProperties and containsInvalidItems translation keys to german i18n dictionary

Co-authored-by: s-a <stephan.ahlf@gmail.com>
2020-09-14 19:59:29 +02:00
Jos de Jong 2aee4a6008 Add translation for the texts "Contains invalid properties" and "Contains invalid items" (see #1105) 2020-09-12 17:33:37 +02:00
Jos de Jong 2314aa74e5 Publish v9.0.5 2020-09-09 09:36:06 +02:00
Jos de Jong 12fd998cc1 Update `uglify-js` to the latest version 2020-09-09 09:34:03 +02:00
Jos de Jong 60b84bb6bd Fix #1090: autocomplete firing on dragging or clicking a node 2020-09-09 09:29:45 +02:00
Jos de Jong 2cbac6fd5c Default to tree mode in custom styling example 2020-09-09 09:05:04 +02:00
Jos de Jong 70c9b0b454 Update devDependencies 2020-09-06 10:18:06 +02:00
Jos de Jong 59dd16a538 Update dependencies and devDependencies 2020-08-26 21:56:45 +02:00
Jos de Jong b214915b34 Fix #1096: editor crashing when passing an empty string as `name` 2020-08-26 21:35:30 +02:00
Jos de Jong b48ec89953 Publish v9.0.4 2020-08-15 10:27:18 +02:00
Jos de Jong 295e771ec4 Merge remote-tracking branch 'origin/develop' into develop 2020-08-15 10:17:49 +02:00
Jos de Jong df81d1098d Fix #1077: change the `main` field in `package.json` to point to the actual bundled and minified file instead of a node.js index file 2020-08-15 10:17:41 +02:00
dependabot-preview[bot] 475902593e
Bump jsdom from 16.3.0 to 16.4.0 (#1074)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 16.3.0 to 16.4.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/master/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/16.3.0...16.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-10 21:35:25 +02:00
Jos de Jong e92bdf407f Update devDependencies 2020-08-07 15:14:48 +02:00
jos f9649d1155 Update devDependencies 2020-07-25 15:06:29 +02:00
Jos de Jong e89632d9ce Update dependencies 2020-07-11 13:01:26 +02:00
Jos de Jong 09f2a398ca Make React examples maintenance friendly 2020-07-04 15:06:15 +02:00
josdejong 162756ef69 Publish v9.0.3 2020-07-02 20:10:21 +02:00
josdejong 025c0649fa Fix regression introduced in `v9.0.2` in the select boxes in the Transform model not lighlighting the matches correctly 2020-07-02 20:07:27 +02:00
josdejong fb994728fd Publish v9.0.2 2020-07-01 11:05:00 +02:00
josdejong 400b1eea37 Small styling fix 2020-07-01 10:58:29 +02:00
josdejong 87bc7b2561 Fix #1029: XSS vulnerabilities 2020-07-01 10:45:09 +02:00
josdejong 8826c6f2b6 Fix #1017: unable to style the color of a value containing a color. See also #1028 2020-06-27 17:15:58 +02:00
josdejong 394432d3a6 Publish v9.0.1 2020-06-24 08:42:33 +02:00
josdejong 3a5ddb2ae7 Update devDependencies 2020-06-24 08:41:34 +02:00
josdejong b6235a8d23 Fix #1027: create IE11 Array polyfills `find` and `findIndex` in such a way that they are not iterable 2020-06-23 21:22:21 +02:00
josdejong 70a2f94693 Update history 2020-06-21 16:34:01 +02:00
patrikx3 d71c7b4ca0
FIXE: powered by ace link is updated to https://ace.c9.io/ (#1018) 2020-06-21 16:32:20 +02:00
dependabot[bot] 3048e710c9
Bump websocket-extensions in /examples/react_advanced_demo (#1007)
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-06-06 16:49:11 +02:00
dependabot[bot] 2d38d0bbc9
Bump websocket-extensions from 0.1.3 to 0.1.4 in /examples/react_demo (#1006)
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-06-06 14:08:16 +02:00
josdejong ae84c74996 Update devDependencies 2020-06-06 14:04:01 +02:00
josdejong f94589c1e9 Update devDependencies 2020-05-30 13:40:52 +02:00
josdejong 901b8aa8dd Describe `onFocus` and `onBlur` in the docs (see #612) 2020-05-27 09:03:46 +02:00
josdejong 1b259e7e47 Publish v9.0.0 2020-05-24 16:08:09 +02:00
josdejong 62025c490d Implemented option `limitDragging`, see #962 2020-05-24 16:02:04 +02:00
josdejong c2fa821a31 Update example 20 to also show how to customize font color (See #990) 2020-05-23 14:26:29 +02:00
josdejong bd69cf9ebd Remove greenkeeper badge 2020-05-13 12:42:12 +02:00
josdejong 71e209528d Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	package.json
2020-05-13 08:57:22 +02:00
josdejong 27eb02a410 Publish v8.6.8 2020-05-13 08:56:56 +02:00
josdejong 9fbd352c12 Update devDependencies 2020-05-13 08:20:40 +02:00
josdejong ad021ec7af Fix #936: too many return characters inserted when pasting formatted text from OpenOffice 2020-05-13 08:17:54 +02:00
dependabot-preview[bot] 81513d0f4a
Bump uglify-js from 3.9.1 to 3.9.2 (#980)
Bumps [uglify-js](https://github.com/mishoo/UglifyJS2) from 3.9.1 to 3.9.2.
- [Release notes](https://github.com/mishoo/UglifyJS2/releases)
- [Commits](https://github.com/mishoo/UglifyJS2/compare/v3.9.1...v3.9.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-10 19:22:28 +02:00
josdejong 79beb26d66 Publish v8.6.7 2020-05-10 17:22:14 +02:00
josdejong ea7893a2f6 Update history 2020-05-10 12:07:42 +02:00
josdejong d3231570ab Fix #978: in some special cases the caret was jumping to the beginning of the line whilst typing 2020-05-10 12:06:50 +02:00
josdejong 561e582de8 Fix #858: the `dist/jsoneditor.js` bundle containing a link to a non-existing source map 2020-05-10 11:46:11 +02:00
josdejong 7dafdf8d9a Update dependencies of React examples 2020-05-03 10:13:57 +02:00
josdejong fe800bada7 Update devDependencies 2020-05-03 10:10:08 +02:00
71 changed files with 2490 additions and 30239 deletions

View File

@ -3,8 +3,84 @@
https://github.com/josdejong/jsoneditor https://github.com/josdejong/jsoneditor
## not yet published, version 8.6.7 ## not yet published, version 9.1.2
- Log a clear error in the console when the returned value of `onEditable` is
invalid. See #1112.
## 2020-09-23, version 9.1.1
- Fix #1111: Enum dropdown not showing when using patternProperties for schema.
Thanks @ziga-miklic.
- Fixed JSONEditor not working when opened in a new window, see #1098.
Thanks @joshkel.
- Fix quick-key `Ctrl+D` (duplicate) not working.
- Define "charset: utf-8" in all HTML examples.
## 2020-09-15, version 9.1.0
- Implemented German translation (`de`). Thanks @s-a.
- Fix quick-keys `Ctrl-\` (format) and `Ctrl-Shift-\` (compact) not working
in `code` mode.
- Updated dependencies to `ajv@6.12.5`.
## 2020-09-09, version 9.0.5
- Fix #1090: autocomplete firing on dragging or clicking a node.
- Fix #1096: editor crashing when passing an empty string as `name`.
- Updated dependencies to `ajv@6.12.4`.
## 2020-08-15, version 9.0.4
- Updated dependencies to `ace-builds@1.4.12`, `ajv@6.12.3`.
- Fix #1077: change the `main` field in `package.json` to point to the actual
bundled and minified file instead of a node.js index file.
## 2020-07-02, version 9.0.3
- Fix regression introduced in `v9.0.2` in the select boxes in the
Transform model not lighlighting the matches correctly.
## 2020-07-01, version 9.0.2
- Fix #1029: XSS vulnerabilities. Thanks @onemoreflag for reporting.
- Fix #1017: unable to style the color of a value containing a color.
Thanks @p3x-robot.
## 2020-06-24, version 9.0.1
- Fixed broken link to the Ace editor website (https://ace.c9.io/).
Thanks @p3x-robot.
- Fix #1027: create IE11 Array polyfills `find` and `findIndex` in such a way
that they are not iterable.
## 2020-05-24, version 9.0.0
- Implemented option `limitDragging`, see #962. This is a breaking change when
using a JSON schema: dragging is more restrictive by default in that case.
Set `limitDragging: false` to keep the old, non-restricted behavior.
## 2020-05-13, version 8.6.8
- Fix #936: too many return characters inserted when pasting formatted text
from OpenOffice.
## 2020-05-10, version 8.6.7
- Fix #858: the `dist/jsoneditor.js` bundle containing a link to a
non-existing source map.
- Fix #978: in some special cases the caret was jumping to the beginning of the
line whilst typing.
- Update dependencies to `ajv@6.12.2`. - Update dependencies to `ajv@6.12.2`.

View File

@ -4,7 +4,7 @@
[![Downloads](https://img.shields.io/npm/dm/jsoneditor.svg)](https://www.npmjs.com/package/jsoneditor) [![Downloads](https://img.shields.io/npm/dm/jsoneditor.svg)](https://www.npmjs.com/package/jsoneditor)
![Maintenance](https://img.shields.io/maintenance/yes/2020.svg) ![Maintenance](https://img.shields.io/maintenance/yes/2020.svg)
[![License](https://img.shields.io/github/license/josdejong/jsoneditor.svg)](https://github.com/josdejong/jsoneditor/blob/master/LICENSE) [![License](https://img.shields.io/github/license/josdejong/jsoneditor.svg)](https://github.com/josdejong/jsoneditor/blob/master/LICENSE)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor?ref=badge_shield) [![Greenkeeper badge](https://badges.greenkeeper.io/josdejong/jsoneditor.svg)](https://greenkeeper.io/) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor?ref=badge_shield)
JSON Editor is a web-based tool to view, edit, format, and validate JSON. JSON Editor is a web-based tool to view, edit, format, and validate JSON.
It has various modes such as a tree editor, a code editor, and a plain text It has various modes such as a tree editor, a code editor, and a plain text
@ -83,10 +83,10 @@ with npm (recommended):
```html ```html
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<!-- when using the mode "code", it's important to specify charset utf-8 --> <!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css"> <link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="jsoneditor/dist/jsoneditor.min.js"></script> <script src="jsoneditor/dist/jsoneditor.min.js"></script>

View File

@ -222,11 +222,15 @@ Constructs a new JSONEditor.
- `{boolean} escapeUnicode` - `{boolean} escapeUnicode`
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` - `{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. 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} limitDragging`
If `false`, nodes can be dragged from any parent node to any other parent node. If `true`, nodes can only be dragged inside the same parent node, which effectively only allows reordering of nodes. By default, `limitDragging` is `true` when no JSON `schema` is defined, and `false` otherwise.
- `{boolean} history` - `{boolean} history`
@ -438,6 +442,14 @@ Constructs a new JSONEditor.
``` ```
Only applicable when `mode` is 'form', 'tree' or 'view'. Only applicable when `mode` is 'form', 'tree' or 'view'.
- `{function} onFocus({ type: 'focus', target })`
Callback method, triggered when the editor comes into focus,
passing an object `{type, target}`, Applicable for all modes.
- `{function} onBlur({ type: 'blur', target })`
Callback method, triggered when the editor goes out of focus,
passing an object `{type, target}`, Applicable for all modes.
- `{boolean} colorPicker` - `{boolean} colorPicker`
If `true` (default), values containing a color name or color code will have a color picker rendered on their left side. If `true` (default), values containing a color name or color code will have a color picker rendered on their left side.
@ -543,7 +555,7 @@ Constructs a new JSONEditor.
- `{string} language` - `{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`, `zh-CN`, `tr`, `ja`, `fr-FR`. Other translations can be specified via the option `languages`. 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`, `zh-CN`, `pt-BR`, `tr`, `ja`, `fr-FR`, `de`. Other translations can be specified via the option `languages`.
- `{Object} languages` - `{Object} languages`
@ -755,7 +767,7 @@ See also `JSONEditor.update(json)`.
#### `JSONEditor.setMode(mode)` #### `JSONEditor.setMode(mode)`
Switch mode. Mode `code` requires the [Ace editor](http://ace.ajax.org/). Switch mode. Mode `code` requires the [Ace editor](https://ace.c9.io/).
*Parameters:* *Parameters:*

View File

@ -13,6 +13,7 @@ customized with several classes that reflect its type and state.
- `jsoneditor-undefined` - `jsoneditor-undefined`
- `jsoneditor-number` - `jsoneditor-number`
- `jsoneditor-string` - `jsoneditor-string`
- `jsoneditor-string jsoneditor-color-value`
- `jsoneditor-boolean` - `jsoneditor-boolean`
- `jsoneditor-regexp` - `jsoneditor-regexp`
- `jsoneditor-array` - `jsoneditor-array`

View File

@ -59,10 +59,10 @@ var json = editor.get();
```html ```html
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<!-- when using the mode "code", it's important to specify charset utf-8 --> <!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css"> <link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="jsoneditor/dist/jsoneditor.min.js"></script> <script src="jsoneditor/dist/jsoneditor.min.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Basic usage</title> <title>JSONEditor | Basic usage</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
@ -36,7 +38,8 @@
'number': 123, 'number': 123,
'object': {'a': 'b', 'c': 'd'}, 'object': {'a': 'b', 'c': 'd'},
'time': 1575599819000, 'time': 1575599819000,
'string': 'Hello World' 'string': 'Hello World',
'onlineDemo': 'https://jsoneditoronline.org/'
} }
editor.set(json) editor.set(json)
} }

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Viewer</title> <title>JSONEditor | Viewer</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,10 +1,10 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<title>JSONEditor | Switch mode</title>
<!-- when using the mode "code", it's important to specify charset utf-8 --> <!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<title>JSONEditor | Switch mode</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Load and save</title> <title>JSONEditor | Load and save</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Custom editable fields</title> <title>JSONEditor | Custom editable fields</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Custom styling</title> <title>JSONEditor | Custom styling</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
@ -35,7 +37,7 @@
// create the editor // create the editor
const container = document.getElementById('jsoneditor') const container = document.getElementById('jsoneditor')
const options = { const options = {
modes: ['text', 'tree'] modes: ['tree', 'text']
} }
const json = { const json = {
'array': [1, 2, 3], 'array': [1, 2, 3],

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | JSON schema validation</title> <title>JSONEditor | JSON schema validation</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Custom Ace</title> <title>JSONEditor | Custom Ace</title>
<!-- load a custom version of Ace editor --> <!-- load a custom version of Ace editor -->

View File

@ -1,10 +1,10 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<title>JSONEditor | Switch mode</title>
<!-- when using the mode "code", it's important to specify charset utf-8 --> <!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<title>JSONEditor | Switch mode</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Item templates</title> <title>JSONEditor | Item templates</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Auto Complete</title> <title>JSONEditor | Auto Complete</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Dynamic Auto Complete</title> <title>JSONEditor | Dynamic Auto Complete</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,9 +1,10 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Advanced Auto Complete</title> <title>JSONEditor | Advanced Auto Complete</title>
<meta charset="UTF-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>
<script src="https://unpkg.com/jsonpath@0.2.11/jsonpath.min.js"></script> <script src="https://unpkg.com/jsonpath@0.2.11/jsonpath.min.js"></script>

View File

@ -1,8 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<title>JSONEditor | Translate</title> <title>JSONEditor | Translate</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Synchronize two editors</title> <title>JSONEditor | Synchronize two editors</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Custom validation</title> <title>JSONEditor | Custom validation</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Custom validation (asynchronous)</title> <title>JSONEditor | Custom validation (asynchronous)</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>
@ -32,12 +32,21 @@
height: 500px; height: 500px;
} }
#containerRight .different_element { #containerRight .different_element {
background-color: greenyellow !important; background-color: #acee61;
} }
#containerRight .different_element div.jsoneditor-field,
#containerRight .different_element div.jsoneditor-value {
color: red;
}
#containerLeft .different_element { #containerLeft .different_element {
background-color: violet !important; background-color: pink;
} }
</style> #containerLeft .different_element div.jsoneditor-field,
#containerLeft .different_element div.jsoneditor-value {
color: red;
}
</style>
</head> </head>
<body> <body>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Basic usage</title> <title>JSONEditor | Basic usage</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | onValidationError</title> <title>JSONEditor | onValidationError</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -0,0 +1,89 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | New window</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>
<button id="openNewEditor">Open Editor in New Window</button>
<button id="setJSON">Set JSON</button>
<button id="getJSON">Get JSON</button>
</p>
<script>
let editor
function openNewEditor() {
const child = window.open("", "_blank", "width=400,height=400")
child.document.title = 'JSONEditor | New window'
child.onunload = function () {
editor = undefined
}
// make the necessary styles available within the child window
// for JSONEditor
const baseUrl = window.location.href.slice(0, window.location.href.lastIndexOf('/'))
const jsonEditorStyles = child.document.createElement("link")
jsonEditorStyles.setAttribute("href", baseUrl + "/../dist/jsoneditor.css")
jsonEditorStyles.setAttribute("rel", "stylesheet")
child.document.head.append(jsonEditorStyles)
// for vanilla-picker
const colorPickerStyles = JSONEditor.VanillaPicker.StyleElement.cloneNode(true)
child.document.head.append(colorPickerStyles)
const container = child.document.createElement("div")
child.document.body.append(container)
// create the editor
const options = {
// Show sort and transform modals in the child window, not the parent.
modalAnchor: child.document.body
}
editor = new JSONEditor(container, options)
}
// create a new window
document.getElementById('openNewEditor').onclick = openNewEditor
// set json
document.getElementById('setJSON').onclick = function () {
if (!editor) {
openNewEditor()
}
const json = {
'array': [1, 2, 3],
'boolean': true,
'color': '#82b92c',
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'time': 1575599819000,
'string': 'Hello World'
}
editor.set(json)
}
// get json
document.getElementById('getJSON').onclick = function () {
if (!editor) {
alert('No editor is open')
} else {
const json = editor.get()
alert(JSON.stringify(json, null, 2))
}
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -3,11 +3,11 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"jsoneditor": "^8.5.3", "jsoneditor": "latest",
"lodash": "4.17.15", "lodash": "4.17.15",
"react": "16.13.1", "react": "16.13.1",
"react-dom": "16.13.1", "react-dom": "16.13.1",
"react-scripts": "3.4.0" "react-scripts": "3.4.1"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"jsoneditor": "^8.5.3", "jsoneditor": "latest",
"react": "16.13.1", "react": "16.13.1",
"react-dom": "16.13.1", "react-dom": "16.13.1",
"react-scripts": "3.4.1" "react-scripts": "3.4.1"

View File

@ -43,6 +43,11 @@ const webpackConfigModule = {
use: { use: {
loader: 'babel-loader' loader: 'babel-loader'
} }
},
{
test: /\.js$/,
use: ['source-map-loader'],
enforce: 'pre'
} }
] ]
} }

2338
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "jsoneditor", "name": "jsoneditor",
"version": "8.6.6", "version": "9.1.1",
"main": "./index", "main": "./dist/jsoneditor.min.js",
"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": [
"json", "json",
@ -26,8 +26,8 @@
"prepublishOnly": "npm test && npm run build" "prepublishOnly": "npm test && npm run build"
}, },
"dependencies": { "dependencies": {
"ace-builds": "^1.4.11", "ace-builds": "^1.4.12",
"ajv": "^6.12.2", "ajv": "^6.12.5",
"javascript-natural-sort": "^0.7.1", "javascript-natural-sort": "^0.7.1",
"jmespath": "^0.15.0", "jmespath": "^0.15.0",
"json-source-map": "^0.6.1", "json-source-map": "^0.6.1",
@ -36,9 +36,9 @@
"vanilla-picker": "^2.10.1" "vanilla-picker": "^2.10.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.9.0", "@babel/core": "7.11.6",
"@babel/preset-env": "7.9.5", "@babel/preset-env": "7.11.5",
"@babel/register": "7.9.0", "@babel/register": "7.11.5",
"babel-loader": "8.1.0", "babel-loader": "8.1.0",
"btoa": "1.2.1", "btoa": "1.2.1",
"date-format": "3.0.0", "date-format": "3.0.0",
@ -46,14 +46,15 @@
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-clean-css": "4.3.0", "gulp-clean-css": "4.3.0",
"gulp-concat-css": "3.1.0", "gulp-concat-css": "3.1.0",
"gulp-sass": "4.0.2", "gulp-sass": "4.1.0",
"jsdom": "16.2.2", "jsdom": "16.4.0",
"json-loader": "0.5.7", "json-loader": "0.5.7",
"mkdirp": "1.0.4", "mkdirp": "1.0.4",
"mocha": "7.1.1", "mocha": "8.1.3",
"standard": "14.3.3", "source-map-loader": "1.1.0",
"uglify-js": "3.9.1", "standard": "14.3.4",
"webpack": "4.43.0" "uglify-js": "3.11.1",
"webpack": "4.44.2"
}, },
"files": [ "files": [
"dist", "dist",

View File

@ -107,7 +107,9 @@ export class ContextMenu {
buttonExpand.type = 'button' buttonExpand.type = 'button'
domItem.buttonExpand = buttonExpand domItem.buttonExpand = buttonExpand
buttonExpand.className = 'jsoneditor-expand' buttonExpand.className = 'jsoneditor-expand'
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>' const buttonExpandInner = document.createElement('div')
buttonExpandInner.className = 'jsoneditor-expand'
buttonExpand.appendChild(buttonExpandInner)
li.appendChild(buttonExpand) li.appendChild(buttonExpand)
if (item.submenuTitle) { if (item.submenuTitle) {
buttonExpand.title = item.submenuTitle buttonExpand.title = item.submenuTitle
@ -141,8 +143,14 @@ export class ContextMenu {
createMenuItems(ul, domSubItems, item.submenu) createMenuItems(ul, domSubItems, item.submenu)
} else { } else {
// no submenu, just a button with clickhandler // no submenu, just a button with clickhandler
button.innerHTML = '<div class="jsoneditor-icon"></div>' + const icon = document.createElement('div')
'<div class="jsoneditor-text">' + translate(item.text) + '</div>' icon.className = 'jsoneditor-icon'
button.appendChild(icon)
const text = document.createElement('div')
text.className = 'jsoneditor-text'
text.appendChild(document.createTextNode(translate(item.text)))
button.appendChild(text)
} }
domItems.push(domItem) domItems.push(domItem)
@ -425,5 +433,3 @@ export class ContextMenu {
// currently displayed context menu, a singleton. We may only have one visible context menu // currently displayed context menu, a singleton. We may only have one visible context menu
ContextMenu.visibleMenu = undefined ContextMenu.visibleMenu = undefined
export default ContextMenu

View File

@ -23,7 +23,7 @@ export class ErrorTable {
const additionalErrorsIndication = document.createElement('div') const additionalErrorsIndication = document.createElement('div')
additionalErrorsIndication.style.display = 'none' additionalErrorsIndication.style.display = 'none'
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein' additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein'
additionalErrorsIndication.innerHTML = 'Scroll for more &#9663;' additionalErrorsIndication.textContent = 'Scroll for more \u25BF'
this.dom.additionalErrorsIndication = additionalErrorsIndication this.dom.additionalErrorsIndication = additionalErrorsIndication
validationErrorsContainer.appendChild(additionalErrorsIndication) validationErrorsContainer.appendChild(additionalErrorsIndication)
@ -76,19 +76,15 @@ export class ErrorTable {
if (this.errorTableVisible && errors.length > 0) { if (this.errorTableVisible && errors.length > 0) {
const validationErrors = document.createElement('div') const validationErrors = document.createElement('div')
validationErrors.className = 'jsoneditor-validation-errors' validationErrors.className = 'jsoneditor-validation-errors'
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>'
const tbody = validationErrors.getElementsByTagName('tbody')[0] const table = document.createElement('table')
table.className = 'jsoneditor-text-errors'
validationErrors.appendChild(table)
const tbody = document.createElement('tbody')
table.appendChild(tbody)
errors.forEach(error => { errors.forEach(error => {
let message
if (typeof error === 'string') {
message = '<td colspan="2"><pre>' + error + '</pre></td>'
} else {
message =
'<td>' + (error.dataPath || '') + '</td>' +
'<td><pre>' + error.message + '</pre></td>'
}
let line let line
if (!isNaN(error.line)) { if (!isNaN(error.line)) {
@ -108,7 +104,36 @@ export class ErrorTable {
trEl.className += ' validation-error' trEl.className += ' validation-error'
} }
trEl.innerHTML = ('<td><button class="jsoneditor-schema-error"></button></td><td style="white-space:nowrap;">' + (!isNaN(line) ? ('Ln ' + line) : '') + '</td>' + message) const td1 = document.createElement('td')
const button = document.createElement('button')
button.className = 'jsoneditor-schema-error'
td1.appendChild(button)
trEl.appendChild(td1)
const td2 = document.createElement('td')
td2.style = 'white-space: nowrap;'
td2.textContent = (!isNaN(line) ? ('Ln ' + line) : '')
trEl.appendChild(td2)
if (typeof error === 'string') {
const td34 = document.createElement('td')
td34.colSpan = 2
const pre = document.createElement('pre')
pre.appendChild(document.createTextNode(error))
td34.appendChild(pre)
trEl.appendChild(td34)
} else {
const td3 = document.createElement('td')
td3.appendChild(document.createTextNode(error.dataPath || ''))
trEl.appendChild(td3)
const td4 = document.createElement('td')
const pre = document.createElement('pre')
pre.appendChild(document.createTextNode(error.message))
td4.appendChild(pre)
trEl.appendChild(td4)
}
trEl.onclick = () => { trEl.onclick = () => {
this.onFocusLine(line) this.onFocusLine(line)
} }

View File

@ -5,7 +5,7 @@ const VanillaPicker = require('./vanilla-picker') // may be undefined in case of
const { treeModeMixins } = require('./treemode') const { treeModeMixins } = require('./treemode')
const { textModeMixins } = require('./textmode') const { textModeMixins } = require('./textmode')
const { previewModeMixins } = require('./previewmode') const { previewModeMixins } = require('./previewmode')
const { clear, extend, getInternetExplorerVersion, parse } = require('./util') const { clear, extend, getInnerText, getInternetExplorerVersion, parse } = require('./util')
const { tryRequireAjv } = require('./tryRequireAjv') const { tryRequireAjv } = require('./tryRequireAjv')
const { showTransformModal } = require('./showTransformModal') const { showTransformModal } = require('./showTransformModal')
const { showSortModal } = require('./showSortModal') const { showSortModal } = require('./showSortModal')
@ -184,7 +184,7 @@ JSONEditor.VALID_OPTIONS = [
'colorPicker', 'onColorPicker', 'colorPicker', 'onColorPicker',
'timestampTag', 'timestampFormat', 'timestampTag', 'timestampFormat',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform', 'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform', 'limitDragging',
'maxVisibleChilds', 'onValidationError', 'maxVisibleChilds', 'onValidationError',
'modalAnchor', 'popupAnchor', 'modalAnchor', 'popupAnchor',
'createQuery', 'executeQuery', 'queryDescription' 'createQuery', 'executeQuery', 'queryDescription'
@ -484,6 +484,7 @@ JSONEditor.VanillaPicker = VanillaPicker
// expose some utils (this is undocumented, unofficial) // expose some utils (this is undocumented, unofficial)
JSONEditor.showTransformModal = showTransformModal JSONEditor.showTransformModal = showTransformModal
JSONEditor.showSortModal = showSortModal JSONEditor.showSortModal = showSortModal
JSONEditor.getInnerText = getInnerText
// default export for TypeScript ES6 projects // default export for TypeScript ES6 projects
JSONEditor.default = JSONEditor JSONEditor.default = JSONEditor

View File

@ -83,7 +83,7 @@ export class ModeSwitcher {
const box = document.createElement('button') const box = document.createElement('button')
box.type = 'button' box.type = 'button'
box.className = 'jsoneditor-modes jsoneditor-separator' box.className = 'jsoneditor-modes jsoneditor-separator'
box.innerHTML = currentTitle + ' &#x25BE;' box.textContent = currentTitle + ' \u25BE'
box.title = translate('modeEditorTitle') box.title = translate('modeEditorTitle')
box.onclick = () => { box.onclick = () => {
const menu = new ContextMenu(items) const menu = new ContextMenu(items)

View File

@ -104,9 +104,17 @@ export class Node {
if (typeof editable === 'boolean') { if (typeof editable === 'boolean') {
this.editable.field = editable this.editable.field = editable
this.editable.value = editable this.editable.value = editable
} else { } else if (typeof editable === 'object' && editable !== null) {
if (typeof editable.field === 'boolean') this.editable.field = editable.field if (typeof editable.field === 'boolean') this.editable.field = editable.field
if (typeof editable.value === 'boolean') this.editable.value = editable.value if (typeof editable.value === 'boolean') this.editable.value = editable.value
} else {
console.error(
'Invalid return value for function onEditable.',
'Actual value:', editable, '.',
'Either a boolean or object { field: boolean, value: boolean } expected.')
this.editable.field = false
this.editable.value = false
} }
} }
} }
@ -1507,6 +1515,12 @@ export class Node {
if (this.dom.value && this.type !== 'array' && this.type !== 'object') { if (this.dom.value && this.type !== 'array' && this.type !== 'object') {
this.valueInnerText = getInnerText(this.dom.value) this.valueInnerText = getInnerText(this.dom.value)
if (this.valueInnerText === '' && this.dom.value.innerHTML !== '') {
// When clearing the contents, often a <br/> remains, messing up the
// styling of the empty text box. Therefore we remove the <br/>
this.dom.value.textContent = ''
}
} }
if (this.valueInnerText !== undefined) { if (this.valueInnerText !== undefined) {
@ -1712,14 +1726,14 @@ export class Node {
// Create the default empty option // Create the default empty option
this.dom.select.option = document.createElement('option') this.dom.select.option = document.createElement('option')
this.dom.select.option.value = '' this.dom.select.option.value = ''
this.dom.select.option.innerHTML = '--' this.dom.select.option.textContent = '--'
this.dom.select.appendChild(this.dom.select.option) this.dom.select.appendChild(this.dom.select.option)
// Iterate all enum values and add them as options // Iterate all enum values and add them as options
for (let i = 0; i < this.enum.length; i++) { for (let i = 0; i < this.enum.length; i++) {
this.dom.select.option = document.createElement('option') this.dom.select.option = document.createElement('option')
this.dom.select.option.value = this.enum[i] this.dom.select.option.value = this.enum[i]
this.dom.select.option.innerHTML = this.enum[i] this.dom.select.option.textContent = this.enum[i]
if (this.dom.select.option.value === this.value) { if (this.dom.select.option.value === this.value) {
this.dom.select.option.selected = true this.dom.select.option.selected = true
} }
@ -1741,7 +1755,7 @@ export class Node {
) { ) {
this.valueFieldHTML = this.dom.tdValue.innerHTML this.valueFieldHTML = this.dom.tdValue.innerHTML
this.dom.tdValue.style.visibility = 'hidden' this.dom.tdValue.style.visibility = 'hidden'
this.dom.tdValue.innerHTML = '' this.dom.tdValue.textContent = ''
} else { } else {
delete this.valueFieldHTML delete this.valueFieldHTML
} }
@ -1771,12 +1785,10 @@ export class Node {
this.dom.tdColor.appendChild(this.dom.color) this.dom.tdColor.appendChild(this.dom.color)
this.dom.tdValue.parentNode.insertBefore(this.dom.tdColor, this.dom.tdValue) this.dom.tdValue.parentNode.insertBefore(this.dom.tdColor, this.dom.tdValue)
// this is a bit hacky, overriding the text color like this. find a nicer solution
this.dom.value.style.color = '#1A1A1A'
} }
// update the color background // update styling of value and color background
addClassName(this.dom.value, 'jsoneditor-color-value')
this.dom.color.style.backgroundColor = value this.dom.color.style.backgroundColor = value
} else { } else {
// cleanup color picker when displayed // cleanup color picker when displayed
@ -1800,7 +1812,7 @@ export class Node {
}) })
} }
if (!title) { if (!title) {
this.dom.date.innerHTML = new Date(value).toISOString() this.dom.date.textContent = new Date(value).toISOString()
} else { } else {
while (this.dom.date.firstChild) { while (this.dom.date.firstChild) {
this.dom.date.removeChild(this.dom.date.firstChild) this.dom.date.removeChild(this.dom.date.firstChild)
@ -1829,7 +1841,7 @@ export class Node {
delete this.dom.tdColor delete this.dom.tdColor
delete this.dom.color delete this.dom.color
this.dom.value.style.color = '' removeClassName(this.dom.value, 'jsoneditor-color-value')
} }
} }
@ -1848,8 +1860,8 @@ export class Node {
domField.title = tooltip domField.title = tooltip
} }
// make backgound color lightgray when empty // make background color lightgray when empty
const isEmpty = (String(this.field) === '' && this.parent.type !== 'array') const isEmpty = (String(this.field) === '' && this.parent && this.parent.type !== 'array')
if (isEmpty) { if (isEmpty) {
addClassName(domField, 'jsoneditor-empty') addClassName(domField, 'jsoneditor-empty')
} else { } else {
@ -1884,6 +1896,12 @@ export class Node {
if (this.dom.field && this.fieldEditable) { if (this.dom.field && this.fieldEditable) {
this.fieldInnerText = getInnerText(this.dom.field) this.fieldInnerText = getInnerText(this.dom.field)
if (this.fieldInnerText === '' && this.dom.field.innerHTML !== '') {
// When clearing the contents, often a <br/> remains, messing up the
// styling of the empty text box. Therefore we remove the <br/>
this.dom.field.textContent = ''
}
} }
if (this.fieldInnerText !== undefined) { if (this.fieldInnerText !== undefined) {
@ -2213,8 +2231,17 @@ export class Node {
fieldText = '' fieldText = ''
} }
} }
domField.innerHTML = this._escapeHTML(fieldText)
const escapedField = this._escapeHTML(fieldText)
if (
document.activeElement !== domField ||
escapedField !== this._unescapeHTML(getInnerText(domField))
) {
// only update if it not has the focus or when there is an actual change,
// else you would needlessly loose the caret position when changing tabs
// or whilst typing
domField.innerHTML = escapedField
}
this._updateSchema() this._updateSchema()
} }
@ -2224,7 +2251,16 @@ export class Node {
if (this.type === 'array' || this.type === 'object') { if (this.type === 'array' || this.type === 'object') {
this.updateNodeName() this.updateNodeName()
} else { } else {
domValue.innerHTML = this._escapeHTML(this.value) const escapedValue = this._escapeHTML(this.value)
if (
document.activeElement !== domValue ||
escapedValue !== this._unescapeHTML(getInnerText(domValue))
) {
// only update if it not has the focus or when there is an actual change,
// else you would needlessly loose the caret position when changing tabs
// or whilst typing
domValue.innerHTML = escapedValue
}
} }
} }
@ -2321,7 +2357,7 @@ export class Node {
child.index = index child.index = index
const childField = child.dom.field const childField = child.dom.field
if (childField) { if (childField) {
childField.innerHTML = index childField.textContent = index
} }
}) })
} else if (this.type === 'object') { } else if (this.type === 'object') {
@ -2347,10 +2383,10 @@ export class Node {
if (this.type === 'array') { if (this.type === 'array') {
domValue = document.createElement('div') domValue = document.createElement('div')
domValue.innerHTML = '[...]' domValue.textContent = '[...]'
} else if (this.type === 'object') { } else if (this.type === 'object') {
domValue = document.createElement('div') domValue = document.createElement('div')
domValue.innerHTML = '{...}' domValue.textContent = '{...}'
} else { } else {
if (!this.editable.value && isUrl(this.value)) { if (!this.editable.value && isUrl(this.value)) {
// create a link in case of read-only editor and value containing an url // create a link in case of read-only editor and value containing an url
@ -2497,14 +2533,14 @@ export class Node {
// swap the value of a boolean when the checkbox displayed left is clicked // swap the value of a boolean when the checkbox displayed left is clicked
if (type === 'change' && target === dom.checkbox) { if (type === 'change' && target === dom.checkbox) {
this.dom.value.innerHTML = !this.value this.dom.value.textContent = String(!this.value)
this._getDomValue() this._getDomValue()
this._updateDomDefault() this._updateDomDefault()
} }
// update the value of the node based on the selected option // update the value of the node based on the selected option
if (type === 'change' && target === dom.select) { if (type === 'change' && target === dom.select) {
this.dom.value.innerHTML = dom.select.value this.dom.value.innerHTML = this._escapeHTML(dom.select.value)
this._getDomValue() this._getDomValue()
this._updateDomValue() this._updateDomValue()
} }
@ -2519,9 +2555,11 @@ export class Node {
this._getDomValue() this._getDomValue()
this._clearValueError() this._clearValueError()
this._updateDomValue() this._updateDomValue()
const escapedValue = this._escapeHTML(this.value) const escapedValue = this._escapeHTML(this.value)
if (domValue.innerHTML !== escapedValue) { if (escapedValue !== this._unescapeHTML(getInnerText(domValue))) {
// only update if changed, else you lose the caret position when changing tabs for example // only update when there is an actual change, else you loose the
// caret position when changing tabs or whilst typing
domValue.innerHTML = escapedValue domValue.innerHTML = escapedValue
} }
break break
@ -2544,7 +2582,7 @@ export class Node {
// if read-only, we use the regular click behavior of an anchor // if read-only, we use the regular click behavior of an anchor
if (isUrl(this.value)) { if (isUrl(this.value)) {
event.preventDefault() event.preventDefault()
window.open(this.value, '_blank') window.open(this.value, '_blank', 'noopener')
} }
} }
break break
@ -2572,9 +2610,11 @@ export class Node {
case 'blur': { case 'blur': {
this._getDomField(true) this._getDomField(true)
this._updateDomField() this._updateDomField()
const escapedField = this._escapeHTML(this.field) const escapedField = this._escapeHTML(this.field)
if (domField.innerHTML !== escapedField) { if (escapedField !== this._unescapeHTML(getInnerText(domField))) {
// only update if changed, else you lose the caret position when changing tabs for example // only update when there is an actual change, else you loose the
// caret position when changing tabs or whilst typing
domField.innerHTML = escapedField domField.innerHTML = escapedField
} }
break break
@ -2697,7 +2737,7 @@ export class Node {
if (target === this.dom.value) { if (target === this.dom.value) {
if (!this.editable.value || event.ctrlKey) { if (!this.editable.value || event.ctrlKey) {
if (isUrl(this.value)) { if (isUrl(this.value)) {
window.open(this.value, '_blank') window.open(this.value, '_blank', 'noopener')
handled = true handled = true
} }
} }
@ -3885,7 +3925,7 @@ export class Node {
const json = this.getValue() const json = this.getValue()
showTransformModal({ showTransformModal({
anchor: modalAnchor || DEFAULT_MODAL_ANCHOR, container: modalAnchor || DEFAULT_MODAL_ANCHOR,
json, json,
queryDescription, // can be undefined queryDescription, // can be undefined
createQuery, createQuery,
@ -4015,7 +4055,7 @@ export class Node {
} }
} }
this.dom.value.innerHTML = (this.type === 'object') this.dom.value.textContent = (this.type === 'object')
? ('{' + (nodeName || count) + '}') ? ('{' + (nodeName || count) + '}')
: ('[' + (nodeName || count) + ']') : ('[' + (nodeName || count) + ']')
} }
@ -4084,13 +4124,13 @@ Node.onDragStart = (nodes, event) => {
const offsetY = getAbsoluteTop(draggedNode.dom.tr) - getAbsoluteTop(firstNode.dom.tr) const offsetY = getAbsoluteTop(draggedNode.dom.tr) - getAbsoluteTop(firstNode.dom.tr)
if (!editor.mousemove) { if (!editor.mousemove) {
editor.mousemove = addEventListener(window, 'mousemove', event => { editor.mousemove = addEventListener(event.view, 'mousemove', event => {
Node.onDrag(nodes, event) Node.onDrag(nodes, event)
}) })
} }
if (!editor.mouseup) { if (!editor.mouseup) {
editor.mouseup = addEventListener(window, 'mouseup', event => { editor.mouseup = addEventListener(event.view, 'mouseup', event => {
Node.onDragEnd(nodes, event) Node.onDragEnd(nodes, event)
}) })
} }
@ -4175,7 +4215,10 @@ Node.onDrag = (nodes, event) => {
} }
} }
if (nodePrev) { if (
nodePrev &&
(editor.options.limitDragging === false || nodePrev.parent === nodes[0].parent)
) {
nodes.forEach(node => { nodes.forEach(node => {
nodePrev.parent.moveBefore(node, nodePrev) nodePrev.parent.moveBefore(node, nodePrev)
}) })
@ -4251,7 +4294,11 @@ Node.onDrag = (nodes, event) => {
} }
// move the node when its position is changed // move the node when its position is changed
if (nodeNext && nodeNext.dom.tr && trLast.nextSibling !== nodeNext.dom.tr) { if (
nodeNext &&
(editor.options.limitDragging === false || nodeNext.parent === nodes[0].parent) &&
nodeNext.dom.tr && nodeNext.dom.tr !== trLast.nextSibling
) {
nodes.forEach(node => { nodes.forEach(node => {
nodeNext.parent.moveBefore(node, nodeNext) nodeNext.parent.moveBefore(node, nodeNext)
}) })
@ -4339,11 +4386,11 @@ Node.onDragEnd = (nodes, event) => {
delete editor.drag delete editor.drag
if (editor.mousemove) { if (editor.mousemove) {
removeEventListener(window, 'mousemove', editor.mousemove) removeEventListener(event.view, 'mousemove', editor.mousemove)
delete editor.mousemove delete editor.mousemove
} }
if (editor.mouseup) { if (editor.mouseup) {
removeEventListener(window, 'mouseup', editor.mouseup) removeEventListener(event.view, 'mouseup', editor.mouseup)
delete editor.mouseup delete editor.mouseup
} }
@ -4409,7 +4456,7 @@ Node._findSchema = (schema, schemaRefs, path) => {
if (typeof key === 'string' && childSchema.patternProperties && !(childSchema.properties && key in childSchema.properties)) { if (typeof key === 'string' && childSchema.patternProperties && !(childSchema.properties && key in childSchema.properties)) {
for (const prop in childSchema.patternProperties) { for (const prop in childSchema.patternProperties) {
if (key.match(prop)) { if (key.match(prop) && (foundSchema.properties || foundSchema.patternProperties)) {
foundSchema = Node._findSchema(childSchema.patternProperties[prop], schemaRefs, nextPath) foundSchema = Node._findSchema(childSchema.patternProperties[prop], schemaRefs, nextPath)
} }
} }
@ -4516,7 +4563,7 @@ Node.onDuplicate = nodes => {
if (clones[0].parent.type === 'object') { if (clones[0].parent.type === 'object') {
// when duplicating a single object property, // when duplicating a single object property,
// set focus to the field and keep the original field name // set focus to the field and keep the original field name
clones[0].dom.field.innerHTML = nodes[0].field clones[0].dom.field.innerHTML = nodes[0]._escapeHTML(nodes[0].field)
clones[0].focus('field') clones[0].focus('field')
} else { } else {
clones[0].focus() clones[0].focus()

View File

@ -229,16 +229,16 @@ export class SearchBox {
if (text !== undefined) { if (text !== undefined) {
const resultCount = this.results.length const resultCount = this.results.length
if (resultCount === 0) { if (resultCount === 0) {
this.dom.results.innerHTML = 'no&nbsp;results' this.dom.results.textContent = 'no\u00A0results'
} else if (resultCount === 1) { } else if (resultCount === 1) {
this.dom.results.innerHTML = '1&nbsp;result' this.dom.results.textContent = '1\u00A0result'
} else if (resultCount > MAX_SEARCH_RESULTS) { } else if (resultCount > MAX_SEARCH_RESULTS) {
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + '+&nbsp;results' this.dom.results.textContent = MAX_SEARCH_RESULTS + '+\u00A0results'
} else { } else {
this.dom.results.innerHTML = resultCount + '&nbsp;results' this.dom.results.textContent = resultCount + '\u00A0results'
} }
} else { } else {
this.dom.results.innerHTML = '' this.dom.results.textContent = ''
} }
} }
} }

View File

@ -27,7 +27,7 @@ export class TreePath {
* Reset component to initial status * Reset component to initial status
*/ */
reset () { reset () {
this.path.innerHTML = translate('selectNode') this.path.textContent = translate('selectNode')
} }
/** /**
@ -38,7 +38,7 @@ export class TreePath {
setPath (pathObjs) { setPath (pathObjs) {
const me = this const me = this
this.path.innerHTML = '' this.path.textContent = ''
if (pathObjs && pathObjs.length) { if (pathObjs && pathObjs.length) {
pathObjs.forEach((pathObj, idx) => { pathObjs.forEach((pathObj, idx) => {
@ -53,7 +53,7 @@ export class TreePath {
if (pathObj.children.length) { if (pathObj.children.length) {
sepEl = document.createElement('span') sepEl = document.createElement('span')
sepEl.className = 'jsoneditor-treepath-seperator' sepEl.className = 'jsoneditor-treepath-seperator'
sepEl.innerHTML = '&#9658;' sepEl.textContent = '\u25BA'
sepEl.onclick = () => { sepEl.onclick = () => {
me.contentMenuClicked = true me.contentMenuClicked = true
@ -82,7 +82,7 @@ export class TreePath {
const showAllBtn = document.createElement('span') const showAllBtn = document.createElement('span')
showAllBtn.className = 'jsoneditor-treepath-show-all-btn' showAllBtn.className = 'jsoneditor-treepath-show-all-btn'
showAllBtn.title = 'show all path' showAllBtn.title = 'show all path'
showAllBtn.innerHTML = '...' showAllBtn.textContent = '...'
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs) showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs)
me.path.insertBefore(showAllBtn, me.path.firstChild) me.path.insertBefore(showAllBtn, me.path.firstChild)
} }

View File

@ -9,6 +9,7 @@ if (window.ace) {
// load required Ace plugins // load required Ace plugins
require('ace-builds/src-noconflict/mode-json') require('ace-builds/src-noconflict/mode-json')
require('ace-builds/src-noconflict/mode-text')
require('ace-builds/src-noconflict/ext-searchbox') require('ace-builds/src-noconflict/ext-searchbox')
// embed Ace json worker // embed Ace json worker

View File

@ -64,7 +64,7 @@ export function appendNodeFactory (Node) {
// a cell for the contents (showing text 'empty') // a cell for the contents (showing text 'empty')
const tdAppend = document.createElement('td') const tdAppend = document.createElement('td')
const domText = document.createElement('div') const domText = document.createElement('div')
domText.innerHTML = '(' + translate('empty') + ')' domText.appendChild(document.createTextNode('(' + translate('empty') + ')'))
domText.className = 'jsoneditor-readonly' domText.className = 'jsoneditor-readonly'
tdAppend.appendChild(domText) tdAppend.appendChild(domText)
dom.td = tdAppend dom.td = tdAppend
@ -100,7 +100,7 @@ export function appendNodeFactory (Node) {
const domText = dom.text const domText = dom.text
if (domText) { if (domText) {
domText.innerHTML = '(' + translate('empty') + ' ' + this.parent.type + ')' domText.firstChild.nodeValue = '(' + translate('empty') + ' ' + this.parent.type + ')'
} }
// attach or detach the contents of the append node: // attach or detach the contents of the append node:

View File

@ -187,7 +187,7 @@ var util = {
var i; var i;
for (i in a) for (i in a)
if (i in el) el[i] = a[i]; if (i in el) el[i] = a[i];
else if ("html" === i) el.innerHTML = a[i]; else if ("html" === i) el.textContent = a[i];
else if ("text" === i) { else if ("text" === i) {
var t = d.createTextNode(a[i]); var t = d.createTextNode(a[i]);
el.appendChild(t); el.appendChild(t);
@ -287,7 +287,7 @@ function appendItem(item, parent, custom) {
util.removeClass(item, "excluded"); util.removeClass(item, "excluded");
if (!custom) { if (!custom) {
item.innerHTML = item.textContent; item.textContent = item.textContent + ''; // clear highlighting
} }
} }
@ -829,7 +829,7 @@ var addTag = function(item) {
docFrag.appendChild(tg); docFrag.appendChild(tg);
}); });
this.label.innerHTML = ""; this.label.textContent = "";
} else { } else {
docFrag.appendChild(tag); docFrag.appendChild(tag);
@ -917,7 +917,7 @@ var clearSearch = function() {
util.removeClass(item, "excluded"); util.removeClass(item, "excluded");
// Remove the span element for underlining matched items // Remove the span element for underlining matched items
if (!this.customOption) { if (!this.customOption) {
item.innerHTML = item.textContent; item.textContent = item.textContent + ''; // clear highlighting
} }
}, this); }, this);
} }
@ -926,15 +926,21 @@ var clearSearch = function() {
/** /**
* Query matching for searches * Query matching for searches
* @param {string} query * @param {string} query
* @param {HTMLOptionElement} option * @param {string} text
* @return {bool}
*/ */
var match = function(query, option) { var match = function(query, text) {
var result = new RegExp(query, "i").exec(option.textContent); var result = new RegExp(query, "i").exec(text);
if (result) { if (result) {
return option.textContent.replace(result[0], "<span class='selectr-match'>" + result[0] + "</span>"); var start = result.index;
var end = result.index + result[0].length;
return {
before: text.substring(0, start),
match: text.substring(start, end),
after: text.substring(end)
};
} }
return false; return null;
}; };
// Main Lib // Main Lib
@ -1383,7 +1389,7 @@ Selectr.prototype.destroy = function() {
} }
if (this.config.data) { if (this.config.data) {
this.el.innerHTML = ""; this.el.textContent = "";
} }
// Remove the className from select element // Remove the className from select element
@ -1457,7 +1463,7 @@ Selectr.prototype.select = function(index) {
addTag.call(this, item); addTag.call(this, item);
} else { } else {
var data = this.data ? this.data[index] : option; var data = this.data ? this.data[index] : option;
this.label.innerHTML = this.customSelected ? this.config.renderSelection(data) : option.textContent; this.label.textContent = this.customSelected ? this.config.renderSelection(data) : option.textContent;
this.selectedValue = option.value; this.selectedValue = option.value;
this.selectedIndex = index; this.selectedIndex = index;
@ -1519,7 +1525,7 @@ Selectr.prototype.deselect = function(index, force) {
return false; return false;
} }
this.label.innerHTML = ""; this.label.textContent = "";
this.selectedValue = null; this.selectedValue = null;
this.el.selectedIndex = this.selectedIndex = -1; this.el.selectedIndex = this.selectedIndex = -1;
@ -1805,7 +1811,17 @@ Selectr.prototype.search = function(string) {
// Underline the matching results // Underline the matching results
if (!this.customOption) { if (!this.customOption) {
item.innerHTML = match(string, option); item.textContent = ''
var result = match(string, option.textContent);
if (result) {
item.appendChild(document.createTextNode(result.before));
var highlight = document.createElement('span');
highlight.className = 'selectr-match';
highlight.appendChild(document.createTextNode(result.match));
item.appendChild(highlight);
item.appendChild(document.createTextNode(result.after));
}
} }
} else { } else {
util.addClass(item, "excluded"); util.addClass(item, "excluded");
@ -2081,7 +2097,7 @@ Selectr.prototype.setPlaceholder = function(placeholder) {
placeholder = "No options available"; placeholder = "No options available";
} }
this.placeEl.innerHTML = placeholder; this.placeEl.textContent = placeholder;
}; };
/** /**
@ -2119,7 +2135,7 @@ Selectr.prototype.setMessage = function(message, close) {
*/ */
Selectr.prototype.removeMessage = function() { Selectr.prototype.removeMessage = function() {
util.removeClass(this.container, "notice"); util.removeClass(this.container, "notice");
this.notice.innerHTML = ""; this.notice.textContent = "";
}; };
/** /**

View File

@ -52,7 +52,7 @@ export function autocomplete (config) {
refresh: function (token, array) { refresh: function (token, array) {
elem.style.visibility = 'hidden' elem.style.visibility = 'hidden'
ix = 0 ix = 0
elem.innerHTML = '' elem.textContent = ''
const vph = (window.innerHeight || document.documentElement.clientHeight) const vph = (window.innerHeight || document.documentElement.clientHeight)
const rect = elem.parentNode.getBoundingClientRect() const rect = elem.parentNode.getBoundingClientRect()
const distanceToTop = rect.top - 6 // heuristic give 6px const distanceToTop = rect.top - 6 // heuristic give 6px
@ -71,7 +71,11 @@ export function autocomplete (config) {
divRow.onmouseout = onMouseOut divRow.onmouseout = onMouseOut
divRow.onmousedown = onMouseDown divRow.onmousedown = onMouseDown
divRow.__hint = row divRow.__hint = row
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>' divRow.textContent = ''
divRow.appendChild(document.createTextNode(row.substring(0, token.length)))
const b = document.createElement('b')
b.appendChild(document.createTextNode(row.substring(token.length)))
divRow.appendChild(b)
elem.appendChild(divRow) elem.appendChild(divRow)
return divRow return divRow
}) })
@ -153,13 +157,7 @@ export function autocomplete (config) {
document.body.appendChild(spacer) document.body.appendChild(spacer)
} }
// Used to encode an HTML string into a plain text. spacer.textContent = text
// taken from http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding
spacer.innerHTML = String(text).replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
return spacer.getBoundingClientRect().right return spacer.getBoundingClientRect().right
} }

View File

@ -4,7 +4,7 @@
import './polyfills' import './polyfills'
const _locales = ['en', 'pt-BR', 'zh-CN', 'tr', 'ja', 'fr-FR'] const _locales = ['en', 'pt-BR', 'zh-CN', 'tr', 'ja', 'fr-FR', 'de']
const _defs = { const _defs = {
en: { en: {
array: 'Array', array: 'Array',
@ -102,7 +102,9 @@ const _defs = {
modePreviewText: 'Preview', modePreviewText: 'Preview',
modePreviewTitle: 'Switch to preview mode', modePreviewTitle: 'Switch to preview mode',
examples: 'Examples', examples: 'Examples',
default: 'Default' default: 'Default',
containsInvalidProperties: 'Contains invalid properties',
containsInvalidItems: 'Contains invalid items'
}, },
'zh-CN': { 'zh-CN': {
array: '数组', array: '数组',
@ -196,7 +198,9 @@ const _defs = {
modePreviewText: '预览', modePreviewText: '预览',
modePreviewTitle: '切换至预览模式', modePreviewTitle: '切换至预览模式',
examples: '例子', examples: '例子',
default: '缺省' default: '缺省',
containsInvalidProperties: '包含无效的属性',
containsInvalidItems: '包含无效项目'
}, },
'pt-BR': { 'pt-BR': {
array: 'Lista', array: 'Lista',
@ -276,7 +280,9 @@ const _defs = {
'Campo do tipo nao é determinado através do seu valor, ' + 'Campo do tipo nao é determinado através do seu valor, ' +
'mas sempre retornara um texto.', 'mas sempre retornara um texto.',
examples: 'Exemplos', examples: 'Exemplos',
default: 'Revelia' default: 'Revelia',
containsInvalidProperties: 'Contém propriedades inválidas',
containsInvalidItems: 'Contém itens inválidos'
}, },
tr: { tr: {
array: 'Dizin', array: 'Dizin',
@ -363,7 +369,9 @@ const _defs = {
modeViewText: 'Görünüm', modeViewText: 'Görünüm',
modeViewTitle: 'Ağaç görünümüne geç', modeViewTitle: 'Ağaç görünümüne geç',
examples: 'Örnekler', examples: 'Örnekler',
default: 'Varsayılan' default: 'Varsayılan',
containsInvalidProperties: 'Geçersiz özellikler içeriyor',
containsInvalidItems: 'Geçersiz öğeler içeriyor'
}, },
ja: { ja: {
array: '配列', array: '配列',
@ -454,7 +462,9 @@ const _defs = {
modePreviewText: 'プレビュー', modePreviewText: 'プレビュー',
modePreviewTitle: 'プレビューに切り替え', modePreviewTitle: 'プレビューに切り替え',
examples: '例', examples: '例',
default: 'デフォルト' default: 'デフォルト',
containsInvalidProperties: '無効なプロパティが含まれています',
containsInvalidItems: '無効なアイテムが含まれています'
}, },
'fr-FR': { 'fr-FR': {
array: 'Liste', array: 'Liste',
@ -549,7 +559,102 @@ const _defs = {
modePreviewText: 'Prévisualisation', modePreviewText: 'Prévisualisation',
modePreviewTitle: 'Activer mode prévisualiser', modePreviewTitle: 'Activer mode prévisualiser',
examples: 'Exemples', examples: 'Exemples',
default: 'Défaut' default: 'Défaut',
containsInvalidProperties: 'Contient des propriétés non valides',
containsInvalidItems: 'Contient des éléments invalides'
},
de: {
array: 'Auflistung',
auto: 'Auto',
appendText: 'anhängen',
appendTitle: 'Fügen Sie nach diesem Feld ein neues Feld mit dem Typ \'auto\' ein (Strg+Umschalt+Ein)',
appendSubmenuTitle: 'Wählen Sie den Typ des neuen Feldes',
appendTitleAuto: 'Ein neues Feld vom Typ \'auto\' hinzufügen (Strg+Umschalt+Ein)',
ascending: 'Aufsteigend',
ascendingTitle: 'Sortieren Sie die Elemente dieses ${type} in aufsteigender Reihenfolge',
actionsMenu: 'Klicken Sie zum Öffnen des Aktionsmenüs (Strg+M)',
cannotParseFieldError: 'Feld kann nicht in JSON geparst werden',
cannotParseValueError: 'Wert kann nicht in JSON geparst werden',
collapseAll: 'Alle Felder zuklappen',
compactTitle: 'JSON-Daten verdichten, alle Leerzeichen entfernen (Strg+Umschalt+\\)',
descending: 'Absteigend',
descendingTitle: 'Sortieren Sie die Elemente dieses ${type} in absteigender Reihenfolge',
drag: 'Ziehen, um dieses Feld zu verschieben (Alt+Umschalt+Pfeile)',
duplicateKey: 'Doppelter Schlüssel',
duplicateText: 'Duplikat',
duplicateTitle: 'Ausgewählte Felder duplizieren (Strg+D)',
duplicateField: 'Dieses Feld duplizieren (Strg+D)',
duplicateFieldError: 'Doppelter Feldname',
empty: 'leer',
expandAll: 'Alle Felder anzeigen',
expandTitle: 'Klicken Sie, um dieses Feld zu erweitern/zu kollabieren (Strg+E). \nStrg+Klicken Sie, um dieses Feld einschließlich aller Elemente zu erweitern/zu kollabieren.',
formatTitle: 'JSON-Daten mit korrekter Einrückung und Zeilenvorschüben formatieren (Strg+\\)',
insert: 'einfügen',
insertTitle: 'Fügen Sie vor diesem Feld ein neues Feld mit dem Typ \'auto\' ein (Strg+Einfg)',
insertSub: 'Wählen Sie den Typ des neuen Feldes',
object: 'Objekt',
ok: 'Ok',
redo: 'Wiederholen (Strg+Umschalt+Z)',
removeText: 'entfernen',
removeTitle: 'Ausgewählte Felder entfernen (Strg+Entf)',
removeField: 'Dieses Feld entfernen (Strg+Entf)',
repairTitle: 'JSON reparieren: Anführungszeichen und Escape-Zeichen korrigieren, Kommentare und JSONP-Notation entfernen, JavaScript-Objekte in JSON umwandeln.',
searchTitle: 'Suchfelder und Werte',
searchNextResultTitle: 'Nächstes Ergebnis (Enter)',
searchPreviousResultTitle: 'Vorheriges Ergebnis (Umschalt + Eingabe)',
selectNode: 'Wählen Sie einen Knoten aus...',
showAll: 'alle anzeigen',
showMore: 'mehr anzeigen',
showMoreStatus: 'Anzeige von ${visibleChilds} von ${totalChilds}-Elementen.',
sort: 'Sortieren',
sortTitle: 'Sortieren Sie die Elemente dieses ${type}',
sortTitleShort: 'Inhalt sortieren',
sortFieldLabel: 'Feld:',
sortDirectionLabel: 'Richtung:',
sortFieldTitle: 'Wählen Sie das verschachtelte Feld, nach dem das Array oder Objekt sortiert werden soll.',
sortAscending: 'Aufsteigend',
sortAscendingTitle: 'Sortieren Sie das ausgewählte Feld in aufsteigender Reihenfolge',
sortDescending: 'Absteigend',
sortDescendingTitle: 'Sortieren Sie das ausgewählte Feld in absteigender Reihenfolge',
string: 'Zeichenfolge',
transform: 'Verwandeln',
transformTitle: 'Die Elemente dieses ${type} filtern, sortieren oder transformieren',
transformTitleShort: 'Inhalte filtern, sortieren oder transformieren',
extract: 'Auszug',
extractTitle: 'Extrahieren Sie diesen ${type}',
transformQueryTitle: 'Eine JMESPath-Abfrage eingeben',
transformWizardLabel: 'Zauberer',
transformWizardFilter: 'Filter',
transformWizardSortBy: 'Sortieren nach',
transformWizardSelectFields: 'Felder auswählen',
transformQueryLabel: 'Anfrage',
transformPreviewLabel: 'Vorschau',
type: 'Geben Sie ein.',
typeTitle: 'Ändern Sie den Typ dieses Feldes',
openUrl: 'Strg+Klicken oder Strg+Eingabe, um die URL in einem neuen Fenster zu öffnen',
undo: 'Letzte Aktion rückgängig machen (Strg+Z)',
validationCannotMove: 'Kann ein Feld nicht in ein Kind seiner selbst verschieben',
autoType: 'Feldtyp "auto". Der Feldtyp wird automatisch aus dem Wert bestimmt und kann ein String, eine Zahl, boolesch oder null sein.',
objectType: 'Feldtyp "Objekt". Ein Objekt enthält eine ungeordnete Menge von Schlüssel/Wert-Paaren.',
arrayType: 'Feldtyp "Array". Ein Array enthält eine geordnete Sammlung von Werten.',
stringType: 'Feldtyp "Zeichenfolge". Der Feldtyp wird nicht aus dem Wert bestimmt, sondern immer als Zeichenfolge zurückgegeben.',
modeEditorTitle: 'Editor-Modus umschalten',
modeCodeText: 'Code',
modeCodeTitle: 'Umschalten auf Code-Highlighter',
modeFormText: 'Formular',
modeFormTitle: 'Zum Formular-Editor wechseln',
modeTextText: 'Text',
modeTextTitle: 'Zum Editor für einfachen Text wechseln',
modeTreeText: 'Baum',
modeTreeTitle: 'Zum Baum-Editor wechseln',
modeViewText: 'Siehe',
modeViewTitle: 'Zur Baumansicht wechseln',
modePreviewText: 'Vorschau',
modePreviewTitle: 'In den Vorschau-Modus wechseln',
examples: 'Beispiele',
default: 'Standardmäßig',
containsInvalidProperties: 'Enthält ungültige Eigenschaften',
containsInvalidItems: 'Enthält ungültige Elemente'
} }
} }

View File

@ -25,24 +25,32 @@ if (typeof Element !== 'undefined') {
// simple polyfill for Array.findIndex // simple polyfill for Array.findIndex
if (!Array.prototype.findIndex) { if (!Array.prototype.findIndex) {
// eslint-disable-next-line no-extend-native // eslint-disable-next-line no-extend-native
Array.prototype.findIndex = function (predicate) { Object.defineProperty(Array.prototype, 'findIndex', {
for (let i = 0; i < this.length; i++) { value: function (predicate) {
const element = this[i] for (let i = 0; i < this.length; i++) {
if (predicate.call(this, element, i, this)) { const element = this[i]
return i if (predicate.call(this, element, i, this)) {
return i
}
} }
} return -1
return -1 },
} configurable: true,
writable: true
})
} }
// Polyfill for Array.find // Polyfill for Array.find
if (!Array.prototype.find) { if (!Array.prototype.find) {
// eslint-disable-next-line no-extend-native // eslint-disable-next-line no-extend-native
Array.prototype.find = function (predicate) { Object.defineProperty(Array.prototype, 'find', {
const i = this.findIndex(predicate) value: function (predicate) {
return this[i] const i = this.findIndex(predicate)
} return this[i]
},
configurable: true,
writable: true
})
} }
// Polyfill for String.trim // Polyfill for String.trim

View File

@ -100,7 +100,7 @@ previewmode.create = function (container, options = {}) {
this.dom.busy = document.createElement('div') this.dom.busy = document.createElement('div')
this.dom.busy.className = 'jsoneditor-busy' this.dom.busy.className = 'jsoneditor-busy'
this.dom.busyContent = document.createElement('span') this.dom.busyContent = document.createElement('span')
this.dom.busyContent.innerHTML = 'busy...' this.dom.busyContent.textContent = 'busy...'
this.dom.busy.appendChild(this.dom.busyContent) this.dom.busy.appendChild(this.dom.busyContent)
this.content.appendChild(this.dom.busy) this.content.appendChild(this.dom.busy)
@ -398,7 +398,7 @@ previewmode._showTransformModal = function () {
this._renderPreview() // update array count this._renderPreview() // update array count
showTransformModal({ showTransformModal({
anchor: modalAnchor || DEFAULT_MODAL_ANCHOR, container: modalAnchor || DEFAULT_MODAL_ANCHOR,
json, json,
queryDescription, // can be undefined queryDescription, // can be undefined
createQuery, createQuery,

View File

@ -136,7 +136,7 @@ export function showTransformModal (
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
wizard.style.fontStyle = 'italic' wizard.style.fontStyle = 'italic'
wizard.innerHTML = '(wizard not available for objects, only for arrays)' wizard.textContent = '(wizard not available for objects, only for arrays)'
} }
const sortablePaths = getChildPaths(json) const sortablePaths = getChildPaths(json)

View File

@ -68,7 +68,7 @@ textmode.create = function (container, options = {}) {
// TODO: make the option options.ace deprecated, it's not needed anymore (see #309) // TODO: make the option options.ace deprecated, it's not needed anymore (see #309)
// determine mode // determine mode
this.mode = (options.mode === 'code') ? 'code' : 'text' this.mode = (options.mode === 'code') ? 'code' : ((options.mode === 'text') ? 'text' : 'text-plain')
if (this.mode === 'code') { if (this.mode === 'code') {
// verify whether Ace editor is available and supported // verify whether Ace editor is available and supported
if (typeof _ace === 'undefined') { if (typeof _ace === 'undefined') {
@ -132,37 +132,41 @@ textmode.create = function (container, options = {}) {
this.frame.appendChild(this.menu) this.frame.appendChild(this.menu)
// create format button // create format button
const buttonFormat = document.createElement('button') if(this.mode !== 'text-plain') {
buttonFormat.type = 'button' const buttonFormat = document.createElement('button')
buttonFormat.className = 'jsoneditor-format' buttonFormat.type = 'button'
buttonFormat.title = translate('formatTitle') buttonFormat.className = 'jsoneditor-format'
this.menu.appendChild(buttonFormat) buttonFormat.title = translate('formatTitle')
buttonFormat.onclick = () => { this.menu.appendChild(buttonFormat)
try { buttonFormat.onclick = () => {
me.format() try {
me._onChange() me.format()
} catch (err) { me._onChange()
me._onError(err) } catch (err) {
me._onError(err)
}
} }
} }
// create compact button // create compact button
const buttonCompact = document.createElement('button') if(this.mode !== 'text-plain') {
buttonCompact.type = 'button' const buttonCompact = document.createElement('button')
buttonCompact.className = 'jsoneditor-compact' buttonCompact.type = 'button'
buttonCompact.title = translate('compactTitle') buttonCompact.className = 'jsoneditor-compact'
this.menu.appendChild(buttonCompact) buttonCompact.title = translate('compactTitle')
buttonCompact.onclick = () => { this.menu.appendChild(buttonCompact)
try { buttonCompact.onclick = () => {
me.compact() try {
me._onChange() me.compact()
} catch (err) { me._onChange()
me._onError(err) } catch (err) {
me._onError(err)
}
} }
} }
// create sort button // create sort button
if (this.options.enableSort) { if (this.options.enableSort && this.mode !== 'text-plain') {
const sort = document.createElement('button') const sort = document.createElement('button')
sort.type = 'button' sort.type = 'button'
sort.className = 'jsoneditor-sort' sort.className = 'jsoneditor-sort'
@ -174,7 +178,7 @@ textmode.create = function (container, options = {}) {
} }
// create transform button // create transform button
if (this.options.enableTransform) { if (this.options.enableTransform && this.mode !== 'text-plain') {
const transform = document.createElement('button') const transform = document.createElement('button')
transform.type = 'button' transform.type = 'button'
transform.title = translate('transformTitleShort') transform.title = translate('transformTitleShort')
@ -186,22 +190,24 @@ textmode.create = function (container, options = {}) {
} }
// create repair button // create repair button
const buttonRepair = document.createElement('button') if(this.mode !== 'text-plain') {
buttonRepair.type = 'button' const buttonRepair = document.createElement('button')
buttonRepair.className = 'jsoneditor-repair' buttonRepair.type = 'button'
buttonRepair.title = translate('repairTitle') buttonRepair.className = 'jsoneditor-repair'
this.menu.appendChild(buttonRepair) buttonRepair.title = translate('repairTitle')
buttonRepair.onclick = () => { this.menu.appendChild(buttonRepair)
try { buttonRepair.onclick = () => {
me.repair() try {
me._onChange() me.repair()
} catch (err) { me._onChange()
me._onError(err) } catch (err) {
me._onError(err)
}
} }
} }
// create undo/redo buttons // create undo/redo buttons
if (this.mode === 'code') { if (this.mode === 'code' || this.mode === 'text-plain') {
// create undo button // create undo button
const undo = document.createElement('button') const undo = document.createElement('button')
undo.type = 'button' undo.type = 'button'
@ -234,17 +240,17 @@ textmode.create = function (container, options = {}) {
}) })
} }
if (this.mode === 'code') { if (this.mode === 'code' || this.mode === 'text-plain') {
const poweredBy = document.createElement('a') const poweredBy = document.createElement('a')
poweredBy.appendChild(document.createTextNode('powered by ace')) poweredBy.appendChild(document.createTextNode('powered by ace'))
poweredBy.href = 'http://ace.ajax.org' poweredBy.href = 'https://ace.c9.io/'
poweredBy.target = '_blank' poweredBy.target = '_blank'
poweredBy.className = 'jsoneditor-poweredBy' poweredBy.className = 'jsoneditor-poweredBy'
poweredBy.onclick = () => { poweredBy.onclick = () => {
// TODO: this anchor falls below the margin of the content, // TODO: this anchor falls below the margin of the content,
// therefore the normal a.href does not work. We use a click event // therefore the normal a.href does not work. We use a click event
// for now, but this should be fixed. // for now, but this should be fixed.
window.open(poweredBy.href, poweredBy.target) window.open(poweredBy.href, poweredBy.target, 'noopener')
} }
this.menu.appendChild(poweredBy) this.menu.appendChild(poweredBy)
} }
@ -258,7 +264,7 @@ textmode.create = function (container, options = {}) {
this.frame.appendChild(this.content) this.frame.appendChild(this.content)
this.container.appendChild(this.frame) this.container.appendChild(this.frame)
if (this.mode === 'code') { if (this.mode === 'code' || this.mode === 'text-plain') {
this.editorDom = document.createElement('div') this.editorDom = document.createElement('div')
this.editorDom.style.height = '100%' // TODO: move to css this.editorDom.style.height = '100%' // TODO: move to css
this.editorDom.style.width = '100%' // TODO: move to css this.editorDom.style.width = '100%' // TODO: move to css
@ -271,7 +277,12 @@ textmode.create = function (container, options = {}) {
aceEditor.setOptions({ readOnly: isReadOnly }) aceEditor.setOptions({ readOnly: isReadOnly })
aceEditor.setShowPrintMargin(false) aceEditor.setShowPrintMargin(false)
aceEditor.setFontSize('13px') aceEditor.setFontSize('13px')
aceSession.setMode('ace/mode/json') if(this.mode === 'text-plain') {
aceSession.setMode('ace/mode/text')
}
else{
aceSession.setMode('ace/mode/json')
}
aceSession.setTabSize(this.indentation) aceSession.setTabSize(this.indentation)
aceSession.setUseSoftTabs(true) aceSession.setUseSoftTabs(true)
aceSession.setUseWrapMode(true) aceSession.setUseWrapMode(true)
@ -282,8 +293,16 @@ textmode.create = function (container, options = {}) {
originalSetAnnotations.call(this, annotations && annotations.length ? annotations : me.annotations) originalSetAnnotations.call(this, annotations && annotations.length ? annotations : me.annotations)
} }
aceEditor.commands.bindKey('Ctrl-L', null) // disable Ctrl+L (is used by the browser to select the address bar) // disable Ctrl+L quickkey of Ace (is used by the browser to select the address bar)
aceEditor.commands.bindKey('Command-L', null) // disable Ctrl+L (is used by the browser to select the address bar) aceEditor.commands.bindKey('Ctrl-L', null)
aceEditor.commands.bindKey('Command-L', null)
// disable the quickkeys we want to use for Format and Compact
aceEditor.commands.bindKey('Ctrl-\\', null)
aceEditor.commands.bindKey('Command-\\', null)
aceEditor.commands.bindKey('Ctrl-Shift-\\', null)
aceEditor.commands.bindKey('Command-Shift-\\', null)
this.aceEditor = aceEditor this.aceEditor = aceEditor
// register onchange event // register onchange event
@ -476,7 +495,7 @@ textmode._showTransformModal = function () {
const json = this.get() const json = this.get()
showTransformModal({ showTransformModal({
anchor: modalAnchor || DEFAULT_MODAL_ANCHOR, container: modalAnchor || DEFAULT_MODAL_ANCHOR,
json, json,
queryDescription, // can be undefined queryDescription, // can be undefined
createQuery, createQuery,
@ -683,17 +702,24 @@ textmode.compact = function () {
*/ */
textmode.format = function () { textmode.format = function () {
const json = this.get() const json = this.get()
const text = JSON.stringify(json, null, this.indentation) if(this.mode !== 'text-plain') {
this.updateText(text) const text = JSON.stringify(json, null, this.indentation)
this.updateText(text)
}
else {
this.updateText(json)
}
} }
/** /**
* Repair the code in the text editor * Repair the code in the text editor
*/ */
textmode.repair = function () { textmode.repair = function () {
const text = this.getText() if(this.mode !== 'text-plain') {
const repairedText = repair(text) const text = this.getText()
this.updateText(repairedText) const repairedText = repair(text)
this.updateText(repairedText)
}
} }
/** /**
@ -723,7 +749,12 @@ textmode.resize = function () {
* @param {*} json * @param {*} json
*/ */
textmode.set = function (json) { textmode.set = function (json) {
this.setText(JSON.stringify(json, null, this.indentation)) if(this.mode !== 'text-plain') {
this.setText(JSON.stringify(json, null, this.indentation))
}
else{
this.setText(json)
}
} }
/** /**
@ -821,6 +852,9 @@ textmode.updateText = function (jsonText) {
* Throws an exception when no JSON schema is configured * Throws an exception when no JSON schema is configured
*/ */
textmode.validate = function () { textmode.validate = function () {
if(this.mode === 'text-plain') {
return
}
let schemaErrors = [] let schemaErrors = []
let parseErrors = [] let parseErrors = []
let json let json
@ -1055,5 +1089,11 @@ export const textModeMixins = [
mixin: textmode, mixin: textmode,
data: 'text', data: 'text',
load: load load: load
},
{
mode: 'text-plain',
mixin: textmode,
data: 'text',
load: load
} }
] ]

View File

@ -25,7 +25,8 @@ import {
repair, repair,
selectContentEditable, selectContentEditable,
setSelectionOffset, setSelectionOffset,
isValidationErrorChanged isValidationErrorChanged,
getWindow
} from './util' } from './util'
import { autocomplete } from './autocomplete' import { autocomplete } from './autocomplete'
import { setLanguage, setLanguages, translate } from './i18n' import { setLanguage, setLanguages, translate } from './i18n'
@ -127,6 +128,7 @@ treemode._setOptions = function (options) {
autocomplete: null, autocomplete: null,
navigationBar: true, navigationBar: true,
mainMenuBar: true, mainMenuBar: true,
limitDragging: false,
onSelectionChange: null, onSelectionChange: null,
colorPicker: true, colorPicker: true,
onColorPicker: function (parent, color, onChange) { onColorPicker: function (parent, color, onChange) {
@ -135,7 +137,7 @@ treemode._setOptions = function (options) {
// when there is not enough space below, and there is enough space above // when there is not enough space below, and there is enough space above
const pickerHeight = 300 // estimated height of the color picker const pickerHeight = 300 // estimated height of the color picker
const top = parent.getBoundingClientRect().top const top = parent.getBoundingClientRect().top
const windowHeight = window.innerHeight const windowHeight = getWindow(parent).innerHeight
const showOnTop = ((windowHeight - top) < pickerHeight && top > pickerHeight) const showOnTop = ((windowHeight - top) < pickerHeight && top > pickerHeight)
new VanillaPicker({ new VanillaPicker({
@ -169,6 +171,11 @@ treemode._setOptions = function (options) {
Object.keys(options).forEach(prop => { Object.keys(options).forEach(prop => {
this.options[prop] = options[prop] this.options[prop] = options[prop]
}) })
// default limitDragging to true when a JSON schema is defined
if (options.limitDragging == null && options.schema != null) {
this.options.limitDragging = true
}
} }
// compile a JSON schema validator if a JSON schema is provided // compile a JSON schema validator if a JSON schema is provided
@ -626,8 +633,8 @@ treemode._renderValidationErrors = function (errorNodes) {
error: { error: {
message: pair[0].type === 'object' message: pair[0].type === 'object'
? 'Contains invalid properties' // object ? translate('containsInvalidProperties') // object
: 'Contains invalid items' // array : translate('containsInvalidItems') // array
} }
})) }))
.concat(errorNodes) .concat(errorNodes)
@ -1274,7 +1281,7 @@ treemode._updateDragDistance = function (event) {
/** /**
* Start multi selection of nodes by dragging the mouse * Start multi selection of nodes by dragging the mouse
* @param event * @param {MouseEvent} event
* @private * @private
*/ */
treemode._onMultiSelectStart = function (event) { treemode._onMultiSelectStart = function (event) {
@ -1296,12 +1303,12 @@ treemode._onMultiSelectStart = function (event) {
const editor = this const editor = this
if (!this.mousemove) { if (!this.mousemove) {
this.mousemove = addEventListener(window, 'mousemove', event => { this.mousemove = addEventListener(event.view, 'mousemove', event => {
editor._onMultiSelect(event) editor._onMultiSelect(event)
}) })
} }
if (!this.mouseup) { if (!this.mouseup) {
this.mouseup = addEventListener(window, 'mouseup', event => { this.mouseup = addEventListener(event.view, 'mouseup', event => {
editor._onMultiSelectEnd(event) editor._onMultiSelectEnd(event)
}) })
} }
@ -1311,7 +1318,7 @@ treemode._onMultiSelectStart = function (event) {
/** /**
* Multiselect nodes by dragging * Multiselect nodes by dragging
* @param event * @param {MouseEvent} event
* @private * @private
*/ */
treemode._onMultiSelect = function (event) { treemode._onMultiSelect = function (event) {
@ -1354,9 +1361,10 @@ treemode._onMultiSelect = function (event) {
/** /**
* End of multiselect nodes by dragging * End of multiselect nodes by dragging
* @param {MouseEvent} event
* @private * @private
*/ */
treemode._onMultiSelectEnd = function () { treemode._onMultiSelectEnd = function (event) {
// set focus to the context menu button of the first node // set focus to the context menu button of the first node
if (this.multiselection.nodes[0]) { if (this.multiselection.nodes[0]) {
this.multiselection.nodes[0].dom.menu.focus() this.multiselection.nodes[0].dom.menu.focus()
@ -1367,11 +1375,11 @@ treemode._onMultiSelectEnd = function () {
// cleanup global event listeners // cleanup global event listeners
if (this.mousemove) { if (this.mousemove) {
removeEventListener(window, 'mousemove', this.mousemove) removeEventListener(event.view, 'mousemove', this.mousemove)
delete this.mousemove delete this.mousemove
} }
if (this.mouseup) { if (this.mouseup) {
removeEventListener(window, 'mouseup', this.mouseup) removeEventListener(event.view, 'mouseup', this.mouseup)
delete this.mouseup delete this.mouseup
} }
} }
@ -1484,6 +1492,11 @@ treemode._showAutoComplete = function (element) {
if (element.className.indexOf('jsoneditor-value') >= 0) jsonElementType = 'value' if (element.className.indexOf('jsoneditor-value') >= 0) jsonElementType = 'value'
if (element.className.indexOf('jsoneditor-field') >= 0) jsonElementType = 'field' if (element.className.indexOf('jsoneditor-field') >= 0) jsonElementType = 'field'
if (jsonElementType === '') {
// Unknown element field. Could be a button or something else
return
}
const self = this const self = this
setTimeout(() => { setTimeout(() => {

View File

@ -455,6 +455,16 @@ export function isArray (obj) {
return Object.prototype.toString.call(obj) === '[object Array]' return Object.prototype.toString.call(obj) === '[object Array]'
} }
/**
* Gets a DOM element's Window. This is normally just the global `window`
* variable, but if we opened a child window, it may be different.
* @param {HTMLElement} element
* @return {Window}
*/
export function getWindow (element) {
return element.ownerDocument.defaultView
}
/** /**
* Retrieve the absolute left value of a DOM element * Retrieve the absolute left value of a DOM element
* @param {Element} elem A dom element, for example a div * @param {Element} elem A dom element, for example a div
@ -663,7 +673,6 @@ export function setSelectionOffset (params) {
} }
} }
} }
/** /**
* Get the inner text of an HTML element (for example a div element) * Get the inner text of an HTML element (for example a div element)
* @param {Element} element * @param {Element} element
@ -674,21 +683,28 @@ export function getInnerText (element, buffer) {
const first = (buffer === undefined) const first = (buffer === undefined)
if (first) { if (first) {
buffer = { buffer = {
text: '', _text: '',
flush: function () { flush: function () {
const text = this.text const text = this._text
this.text = '' this._text = ''
return text return text
}, },
set: function (text) { set: function (text) {
this.text = text this._text = text
} }
} }
} }
// text node // text node
if (element.nodeValue) { if (element.nodeValue) {
return buffer.flush() + element.nodeValue // remove return characters and the whitespace surrounding return characters
const trimmedValue = element.nodeValue.replace(/\s*\n\s*/g, '')
if (trimmedValue !== '') {
return buffer.flush() + trimmedValue
} else {
// ignore empty text
return ''
}
} }
// divs or other HTML elements // divs or other HTML elements
@ -703,7 +719,9 @@ export function getInnerText (element, buffer) {
const prevChild = childNodes[i - 1] const prevChild = childNodes[i - 1]
const prevName = prevChild ? prevChild.nodeName : undefined const prevName = prevChild ? prevChild.nodeName : undefined
if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') { if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') {
innerText += '\n' if (innerText !== '') {
innerText += '\n'
}
buffer.flush() buffer.flush()
} }
innerText += getInnerText(child, buffer) innerText += getInnerText(child, buffer)
@ -717,15 +735,6 @@ export function getInnerText (element, buffer) {
} }
return innerText return innerText
} else {
if (element.nodeName === 'P' && getInternetExplorerVersion() !== -1) {
// On Internet Explorer, a <p> with hasChildNodes()==false is
// rendered with a new line. Note that a <p> with
// hasChildNodes()==true is rendered without a new line
// Other browsers always ensure there is a <br> inside the <p>,
// and if not, the <p> does not render a new line
return buffer.flush()
}
} }
// br or unknown // br or unknown
@ -790,7 +799,7 @@ export function isFirefox () {
var _ieVersion = -1 var _ieVersion = -1
/** /**
* Add and event listener. Works for all browsers * Add an event listener. Works for all browsers
* @param {Element} element An html element * @param {Element} element An html element
* @param {string} action The action, for example "click", * @param {string} action The action, for example "click",
* without the prefix "on" * without the prefix "on"
@ -1140,7 +1149,7 @@ export function getInputSelection (el) {
} }
/** /**
* Returns the index for certaion position in text element * Returns the index for certain position in text element
* @param {DOMElement} el A dom element of a textarea or input text. * @param {DOMElement} el A dom element of a textarea or input text.
* @param {Number} row row value, > 0, if exceeds rows number - last row will be returned * @param {Number} row row value, > 0, if exceeds rows number - last row will be returned
* @param {Number} column column value, > 0, if exceeds column length - end of column will be returned * @param {Number} column column value, > 0, if exceeds column length - end of column will be returned
@ -1500,7 +1509,7 @@ export function contains (array, item) {
} }
/** /**
* Checkes if validation has changed from the previous execution * Checks if validation has changed from the previous execution
* @param {Array} currErr current validation errors * @param {Array} currErr current validation errors
* @param {Array} prevErr previous validation errors * @param {Array} prevErr previous validation errors
*/ */

View File

@ -6,7 +6,7 @@
.jsoneditor-contextmenu { .jsoneditor-contextmenu {
position: absolute; position: absolute;
box-sizing: content-box; box-sizing: content-box;
z-index: 1; z-index: 2;
.jsoneditor-menu { .jsoneditor-menu {
position: relative; position: relative;
left: 0; left: 0;

View File

@ -46,6 +46,9 @@ div {
&.jsoneditor-null { &.jsoneditor-null {
color: $jse-null; color: $jse-null;
} }
&.jsoneditor-color-value {
color: $jse-color-value;
}
&.jsoneditor-invalid { &.jsoneditor-invalid {
color: $jse-invalid; color: $jse-invalid;
} }

View File

@ -8,7 +8,8 @@ $jse-string: #006000 !default;
$jse-number: #ee422e !default; $jse-number: #ee422e !default;
$jse-boolean: #ff8c00 !default; $jse-boolean: #ff8c00 !default;
$jse-null: #004ed0 !default; $jse-null: #004ed0 !default;
$jse-invalid: #000000 !default; $jse-color-value: $jse-content-color !default;
$jse-invalid: $jse-content-color !default;
$jse-readonly: #808080 !default; $jse-readonly: #808080 !default;
$jse-empty: #d3d3d3 !default; $jse-empty: #d3d3d3 !default;
$jse-preview: #f5f5f5 !default; $jse-preview: #f5f5f5 !default;

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css"> <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<!--<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css" rel="stylesheet" type="text/css">--> <!--<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css" rel="stylesheet" type="text/css">-->

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>
@ -50,6 +50,7 @@
mode: 'tree', mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes
onError: function (err) { onError: function (err) {
console.error(err);
alert(err.toString()); alert(err.toString());
}, },
onChange: function () { onChange: function () {
@ -57,6 +58,9 @@
}, },
onChangeJSON: function (json) { onChangeJSON: function (json) {
console.log('onChangeJSON', json); console.log('onChangeJSON', json);
// test feedback loop which is typical in React -> should not change anything
editorTest.update(json)
}, },
onChangeText: function (text) { onChangeText: function (text) {
console.log('onChangeText', text); console.log('onChangeText', text);
@ -68,7 +72,8 @@
console.log("Blur : ",event); console.log("Blur : ",event);
}, },
indentation: 4, indentation: 4,
escapeUnicode: true // escapeUnicode: true,
limitDragging: true
}; };
json = { json = {
@ -77,14 +82,20 @@
"color": "#82b92c", "color": "#82b92c",
"htmlcode": '&quot;', "htmlcode": '&quot;',
"escaped_unicode": '\\u20b9', "escaped_unicode": '\\u20b9',
"unicode": '\u20b9,\uD83D\uDCA9', "unicode": '\u{1F600},\uD83D\uDCA9',
"return": '\n', "return": '\n',
"null": null, "null": null,
"number": 123, "number": 123,
"object": {"a": "b", "c": "d"}, "object": {"a": "b", "c": "d"},
"string": "Hello World", "string": "Hello World",
"timestamp": 1534952749890, "timestamp": 1534952749890,
"url": "http://jsoneditoronline.org" "url": "http://jsoneditoronline.org",
"<button onclick=alert('oopsie!!!')>test xss</button>": "xss?",
"xss array": [
{
"<button onclick=alert('oopsie!!!')>test xss</button>": "xss?"
}
]
}; };
editorTest = new JSONEditor(container, options, json); editorTest = new JSONEditor(container, options, json);

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.min.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.min.js"></script> <script src="../dist/jsoneditor.min.js"></script>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor test getInnerHtml</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style>
html, body {
font-family: verdana;
background: #f5f5f5;
font-size: 11pt;
}
#editableDiv {
width: 600px;
height: 200px;
border: 1px solid red;
background: white;
font-family: monospace;
}
#editableDiv p {
margin: 0;
}
#innerText,
#getInnerText,
#innerTextStr,
#textContentStr {
width: 600px;
}
#innerText,
#getInnerText {
height: 200px;
border: 1px solid green;
}
#innerTextStr,
#textContentStr {
width: 600px;
border: 1px solid gray;
background: #f5f5f5;
font-family: monospace;
}
</style>
</head>
<body>
contenteditable div:
<div id="editableDiv" contenteditable="true">
<p>Hello world</p>
<p>test paste from OpenOffice </p>
a
<p>
<br>
</p>
<p>test</p>
</div>
<p>
innerText: <br/>
<textarea id="innerText"></textarea>
</p>
<p>
getInnerText: <br/>
<textarea id="getInnerText"></textarea>
</p>
<p>
<p>
inner text (stringified): <br/>
<input id="innerTextStr" readonly />
</p>
<p>
text content (stringified): <br/>
<input id="textContentStr" readonly />
</p>
<script>
const editableDiv = document.getElementById('editableDiv')
const innerText = document.getElementById('innerText')
const getInnerTextDiv = document.getElementById('getInnerText')
const innerTextStr = document.getElementById('innerTextStr')
const textContentStr = document.getElementById('textContentStr')
function updateInnerTexts () {
innerText.value = editableDiv.innerText
getInnerTextDiv.value = JSONEditor.getInnerText(editableDiv)
innerTextStr.value = JSON.stringify(editableDiv.innerText)
textContentStr.value = JSON.stringify(editableDiv.textContent)
}
editableDiv.oninput = updateInnerTexts
updateInnerTexts()
innerText.oninput = function () {
editableDiv.innerText = innerText.value
getInnerTextDiv.value = getInnerText(editableDiv)
}
getInnerTextDiv.oninput = function () {
editableDiv.innerText = getInnerTextDiv.value
innerText.value = editableDiv.innerText
}
</script>
</body>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<!-- materialize css --> <!-- materialize css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.min.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor-minimalist.min.js"></script> <script src="../dist/jsoneditor-minimalist.min.js"></script>

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | JSON schema validation</title> <title>JSONEditor | JSON schema validation</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,6 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8">
<title>JSONEditor | Preview mode load and save</title> <title>JSONEditor | Preview mode load and save</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>

View File

@ -1,10 +1,10 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html lang="en">
<head> <head>
<title>JSONEditor | Update JSON</title>
<!-- when using the mode "code", it's important to specify charset utf-8 --> <!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta charset="utf-8">
<title>JSONEditor | Update JSON</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>