Implemented advanced react example and some minor improvements
This commit is contained in:
parent
983fafdf9c
commit
393dc3f809
|
@ -12,6 +12,7 @@ integrated in React, Vue, and Angular!_
|
||||||
of the editor (expanded nodes, search, selection). This makes it easy to
|
of the editor (expanded nodes, search, selection). This makes it easy to
|
||||||
integrate in frameworks like React.
|
integrate in frameworks like React.
|
||||||
- Implemented options `onChangeJSON(json)` and `onChangeText(jsonString)`.
|
- Implemented options `onChangeJSON(json)` and `onChangeText(jsonString)`.
|
||||||
|
- Added two React examples to the `examples` folder.
|
||||||
|
|
||||||
|
|
||||||
## 2018-08-02, version 5.19.2
|
## 2018-08-02, version 5.19.2
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
};
|
};
|
||||||
editor1.set(json);
|
editor1.set(json);
|
||||||
editor2.set(json);
|
editor2.set(json);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
|
@ -0,0 +1,21 @@
|
||||||
|
# JSONEditor React advanced demo
|
||||||
|
|
||||||
|
This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install dependencies once:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
To run the demo:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
This will open a development server at http://localhost:3000
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "react_advanced_demo",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"jsoneditor": "file:../..",
|
||||||
|
"lodash": "4.17.10",
|
||||||
|
"react": "16.4.2",
|
||||||
|
"react-dom": "16.4.2",
|
||||||
|
"react-scripts": "1.1.4"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build",
|
||||||
|
"test": "react-scripts test --env=jsdom",
|
||||||
|
"eject": "react-scripts eject"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta name="theme-color" content="#000000">
|
||||||
|
<!--
|
||||||
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||||
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
|
-->
|
||||||
|
<title>JSONEditor | React advanced demo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
You need to enable JavaScript to run this app.
|
||||||
|
</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
<!--
|
||||||
|
This HTML file is a template.
|
||||||
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file.
|
||||||
|
The build step will place the bundled scripts into the <body> tag.
|
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,13 @@
|
||||||
|
.app .contents {
|
||||||
|
width: 500px;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app .contents .mode {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app .contents .code {
|
||||||
|
background: #f5f5f5;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import JSONEditorReact from './JSONEditorReact';
|
||||||
|
import './App.css';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
title: 'Example Schema',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
array: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'number'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
type: 'number'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['array', 'string', 'boolean']
|
||||||
|
};
|
||||||
|
|
||||||
|
const json = {
|
||||||
|
'array': [1, 2, 3],
|
||||||
|
'boolean': true,
|
||||||
|
'null': null,
|
||||||
|
'number': 'four',
|
||||||
|
'object': {'a': 'b', 'c': 'd'},
|
||||||
|
'string': 'Hello World'
|
||||||
|
};
|
||||||
|
|
||||||
|
const modes = ['tree', 'form', 'view', 'code', 'text'];
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
state = {
|
||||||
|
schema,
|
||||||
|
text: JSON.stringify(json, null, 2),
|
||||||
|
mode: 'tree'
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<h1>JSONEditor React advanced demo</h1>
|
||||||
|
<div className="contents">
|
||||||
|
<div className="mode">
|
||||||
|
mode: <select value={this.state.mode} onChange={this.onModeChangeSelect}>
|
||||||
|
{
|
||||||
|
modes.map(mode => <option key={mode} value={mode}>{mode}</option>)
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<JSONEditorReact
|
||||||
|
schema={this.state.schema}
|
||||||
|
text={this.state.text}
|
||||||
|
mode={this.state.mode}
|
||||||
|
modes={modes}
|
||||||
|
indentation={4}
|
||||||
|
onChangeText={this.onChangeText}
|
||||||
|
onModeChange={this.onModeChange}
|
||||||
|
/>
|
||||||
|
<div className="code">
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
{this.state.text}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeText = (text) => {
|
||||||
|
this.setState({ text });
|
||||||
|
};
|
||||||
|
|
||||||
|
onModeChangeSelect = (event) => {
|
||||||
|
this.setState({ mode: event.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
onModeChange = (mode) => {
|
||||||
|
this.setState({ mode });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
ReactDOM.render(<App />, div);
|
||||||
|
ReactDOM.unmountComponentAtNode(div);
|
||||||
|
});
|
|
@ -0,0 +1,4 @@
|
||||||
|
.jsoneditor-react-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
|
||||||
|
import * as JSONEditor from 'jsoneditor';
|
||||||
|
import 'jsoneditor/dist/jsoneditor.css';
|
||||||
|
|
||||||
|
import './JSONEditorReact.css';
|
||||||
|
|
||||||
|
export default class JSONEditorReact extends Component {
|
||||||
|
componentDidMount () {
|
||||||
|
// copy all properties into options for the editor
|
||||||
|
// (except the properties for the JSONEditorReact component itself)
|
||||||
|
const options = Object.assign({}, this.props);
|
||||||
|
delete options.json;
|
||||||
|
delete options.text;
|
||||||
|
|
||||||
|
this.jsoneditor = new JSONEditor(this.container, options);
|
||||||
|
|
||||||
|
if ('json' in this.props) {
|
||||||
|
this.jsoneditor.set(this.props.json);
|
||||||
|
}
|
||||||
|
if ('text' in this.props) {
|
||||||
|
this.jsoneditor.setText(this.props.text);
|
||||||
|
}
|
||||||
|
this.schema = cloneDeep(this.props.schema);
|
||||||
|
this.schemaRefs = cloneDeep(this.props.schemaRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUpdate(nextProps, nextState) {
|
||||||
|
if ('json' in nextProps) {
|
||||||
|
this.jsoneditor.update(nextProps.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('text' in nextProps) {
|
||||||
|
this.jsoneditor.updateText(nextProps.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('mode' in nextProps) {
|
||||||
|
this.jsoneditor.setMode(nextProps.mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// store a clone of the schema to keep track on when it actually changes.
|
||||||
|
// (When using a PureComponent all of this would be redundant)
|
||||||
|
const schemaChanged = !isEqual(nextProps.schema, this.schema);
|
||||||
|
const schemaRefsChanged = !isEqual(nextProps.schemaRefs, this.schemaRefs);
|
||||||
|
if (schemaChanged || schemaRefsChanged) {
|
||||||
|
this.schema = cloneDeep(nextProps.schema);
|
||||||
|
this.schemaRefs = cloneDeep(nextProps.schemaRefs);
|
||||||
|
this.jsoneditor.setSchema(nextProps.schema, nextProps.schemaRefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
if (this.jsoneditor) {
|
||||||
|
this.jsoneditor.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="jsoneditor-react-container" ref={elem => this.container = elem} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import './index.css';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
ReactDOM.render(<App />, document.getElementById('root'));
|
|
@ -23,7 +23,7 @@ export default class JSONEditorDemo extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
componentWillUpdate(nextProps, nextState) {
|
||||||
this.jsoneditor.update(nextProps.json)
|
this.jsoneditor.update(nextProps.json);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ table.jsoneditor-search div.jsoneditor-results {
|
||||||
color: white;
|
color: white;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
padding-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.jsoneditor-search {
|
table.jsoneditor-search {
|
||||||
|
|
|
@ -104,7 +104,8 @@ function JSONEditor (container, options, json) {
|
||||||
if (options.onChangeJSON) {
|
if (options.onChangeJSON) {
|
||||||
if (options.mode === 'text' || options.mode === 'code' ||
|
if (options.mode === 'text' || options.mode === 'code' ||
|
||||||
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
|
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
|
||||||
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". Use "onChangeText" instead.');
|
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' +
|
||||||
|
'Use "onChangeText" or "onChange" instead.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +232,11 @@ JSONEditor.prototype.getName = function () {
|
||||||
* 'text', and 'code'.
|
* 'text', and 'code'.
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.setMode = function (mode) {
|
JSONEditor.prototype.setMode = function (mode) {
|
||||||
|
// if the mode is the same as current mode (and it's not the first time), do nothing.
|
||||||
|
if (mode === this.options.mode && this.create) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var container = this.container;
|
var container = this.container;
|
||||||
var options = util.extend({}, this.options);
|
var options = util.extend({}, this.options);
|
||||||
var oldMode = options.mode;
|
var oldMode = options.mode;
|
||||||
|
|
|
@ -322,6 +322,10 @@ textmode.create = function (container, options) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
textmode._onChange = function () {
|
textmode._onChange = function () {
|
||||||
|
if (this.onChangeDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// validate JSON schema (if configured)
|
// validate JSON schema (if configured)
|
||||||
this._debouncedValidate();
|
this._debouncedValidate();
|
||||||
|
|
||||||
|
@ -626,12 +630,11 @@ textmode.setText = function(jsonText) {
|
||||||
}
|
}
|
||||||
if (this.aceEditor) {
|
if (this.aceEditor) {
|
||||||
// prevent emitting onChange events while setting new text
|
// prevent emitting onChange events while setting new text
|
||||||
var originalOnChange = this.options.onChange;
|
this.onChangeDisabled = true;
|
||||||
this.options.onChange = null;
|
|
||||||
|
|
||||||
this.aceEditor.setValue(text, -1);
|
this.aceEditor.setValue(text, -1);
|
||||||
|
|
||||||
this.options.onChange = originalOnChange;
|
this.onChangeDisabled = false;
|
||||||
}
|
}
|
||||||
// validate JSON schema
|
// validate JSON schema
|
||||||
this.validate();
|
this.validate();
|
||||||
|
@ -834,18 +837,27 @@ textmode.setTextSelection = function (startPos, endPos) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function load () {
|
||||||
|
try {
|
||||||
|
this.format()
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// in case of an error, just move on, failing formatting is not a big deal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// define modes
|
// define modes
|
||||||
module.exports = [
|
module.exports = [
|
||||||
{
|
{
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
mixin: textmode,
|
mixin: textmode,
|
||||||
data: 'text',
|
data: 'text',
|
||||||
load: textmode.format
|
load: load
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mode: 'code',
|
mode: 'code',
|
||||||
mixin: textmode,
|
mixin: textmode,
|
||||||
data: 'text',
|
data: 'text',
|
||||||
load: textmode.format
|
load: load
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue