Implemented mode `code` (using ace editor)
This commit is contained in:
parent
a607d2c2f4
commit
5ff41f2d9d
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSONEditor | Custom Ace Editor</title>
|
||||
|
||||
<!-- we use the minimalist jsoneditor, which doesn't have Ace Editor included -->
|
||||
<script src="../dist/jsoneditor-minimalist.js"></script>
|
||||
|
||||
<!-- load your own instance of Ace Editor and all plugins that you need -->
|
||||
<!-- jsoneditor requires ext-searchbox and mode-json -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ext-searchbox.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/mode-json.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/theme-twilight.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>
|
||||
In this example, the we use the minimalist version of jsoneditor and load
|
||||
and configure Ace editor our selves.
|
||||
</p>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
// create the editor, set mode to 'code' (powered by ace editor)
|
||||
var container = document.getElementById('jsoneditor')
|
||||
var options = {
|
||||
mode: 'code',
|
||||
onLoadAce: function (aceEditor, container, options) {
|
||||
// we can adjust configuration of the ace editor,
|
||||
// or create a completely new instance of ace editor.
|
||||
|
||||
// let's set a custom theme and font size
|
||||
aceEditor.setTheme('ace/theme/twilight')
|
||||
aceEditor.setFontSize(16)
|
||||
|
||||
return aceEditor
|
||||
}
|
||||
}
|
||||
var editor = jsoneditor(container, options)
|
||||
|
||||
var json = {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
}
|
||||
editor.set(json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -81,8 +81,8 @@ var compilerMinimalist = webpack({
|
|||
},
|
||||
plugins: [
|
||||
bannerPlugin,
|
||||
new webpack.NormalModuleReplacementPlugin(new RegExp('^brace$'), EMPTY),
|
||||
new webpack.NormalModuleReplacementPlugin(new RegExp('^ajv'), EMPTY),
|
||||
new webpack.NormalModuleReplacementPlugin(new RegExp('^./assets/ace$'), EMPTY),
|
||||
new webpack.NormalModuleReplacementPlugin(new RegExp('^ajv$'), EMPTY),
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
],
|
||||
module: {
|
||||
|
@ -165,4 +165,4 @@ gulp.task(WATCH, ['bundle'], function() {
|
|||
})
|
||||
|
||||
// The default task (called when you run `gulp`)
|
||||
gulp.task('default', [ 'bundle', 'bundle-minimalist' ])
|
||||
gulp.task('default', [ 'bundle', 'bundle-minimalist', 'copy' ])
|
||||
|
|
12
package.json
12
package.json
|
@ -23,18 +23,18 @@
|
|||
"test": "ava test/*.test.js test/**/*.test.js --verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "4.7.5",
|
||||
"ajv": "4.7.7",
|
||||
"brace": "0.8.0",
|
||||
"javascript-natural-sort": "0.7.1",
|
||||
"lodash": "4.16.2",
|
||||
"preact": "6.1.0"
|
||||
"lodash": "4.16.4",
|
||||
"preact": "6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "0.16.0",
|
||||
"babel-core": "6.16.0",
|
||||
"babel-core": "6.17.0",
|
||||
"babel-loader": "6.2.5",
|
||||
"babel-preset-stage-2": "6.16.0",
|
||||
"babel-preset-stage-3": "6.16.0",
|
||||
"babel-preset-stage-2": "6.17.0",
|
||||
"babel-preset-stage-3": "6.17.0",
|
||||
"browser-sync": "2.17.3",
|
||||
"css-loader": "0.25.0",
|
||||
"gulp": "3.9.1",
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
import { h } from 'preact'
|
||||
import TextMode from './TextMode'
|
||||
import ace from './assets/ace'
|
||||
|
||||
/**
|
||||
* CodeMode (powered by Ace editor)
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <CodeMode
|
||||
* options={Object}
|
||||
* onChange={function(text: string)}
|
||||
* onChangeMode={function(mode: string)}
|
||||
* onLoadAce={function(aceEditor: Object, container: Element, options: Object) : Object}
|
||||
* />
|
||||
*
|
||||
* Methods:
|
||||
*
|
||||
* setText(text)
|
||||
* getText() : text
|
||||
* set(json : JSON)
|
||||
* get() : JSON
|
||||
* patch(actions: JSONPatch)
|
||||
* format()
|
||||
* compact()
|
||||
* destroy()
|
||||
*
|
||||
*/
|
||||
export default class CodeMode extends TextMode {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {}
|
||||
|
||||
this.id = 'id' + Math.round(Math.random() * 1e6) // unique enough id within the JSONEditor
|
||||
this.aceEditor = null
|
||||
}
|
||||
|
||||
render (props, state) {
|
||||
return h('div', {class: 'jsoneditor jsoneditor-mode-code'}, [
|
||||
this.renderMenu(),
|
||||
|
||||
h('div', {class: 'jsoneditor-contents', id: this.id})
|
||||
])
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const options = this.props.options || {}
|
||||
|
||||
const container = this.base.querySelector('#' + this.id)
|
||||
|
||||
// use ace from bundle, and if not available try to use from global
|
||||
const _ace = ace || window['ace']
|
||||
|
||||
let aceEditor = null
|
||||
if (_ace && _ace.edit) {
|
||||
// create ace editor
|
||||
aceEditor = _ace.edit(container)
|
||||
|
||||
// bundle and load jsoneditor theme for ace editor
|
||||
require('./assets/ace/theme-jsoneditor')
|
||||
|
||||
// configure ace editor
|
||||
aceEditor.$blockScrolling = Infinity
|
||||
aceEditor.setTheme('ace/theme/jsoneditor')
|
||||
aceEditor.setShowPrintMargin(false)
|
||||
aceEditor.setFontSize(13)
|
||||
aceEditor.getSession().setMode('ace/mode/json')
|
||||
aceEditor.getSession().setTabSize(options.indentation)
|
||||
aceEditor.getSession().setUseSoftTabs(true)
|
||||
aceEditor.getSession().setUseWrapMode(true)
|
||||
aceEditor.commands.bindKey('Ctrl-L', null) // disable Ctrl+L (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)
|
||||
}
|
||||
else {
|
||||
// ace is excluded from the bundle.
|
||||
}
|
||||
|
||||
// allow changing the config or completely replacing aceEditor
|
||||
this.aceEditor = options.onLoadAce
|
||||
? options.onLoadAce(aceEditor, container, options) || aceEditor
|
||||
: aceEditor
|
||||
|
||||
// register onchange event
|
||||
this.aceEditor.on('change', this.handleChange)
|
||||
|
||||
// set initial text
|
||||
this.setText('{}')
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.destroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the editor
|
||||
*/
|
||||
destroy () {
|
||||
// neatly destroy ace editor
|
||||
this.aceEditor.destroy()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
// TODO: handle changes in props
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
// TODO: handle changes
|
||||
// console.log('ace editor changed')
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a string containing a JSON document
|
||||
* @param {string} text
|
||||
*/
|
||||
setText (text) {
|
||||
this.aceEditor.setValue(text, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON document as text
|
||||
* @return {string} text
|
||||
*/
|
||||
getText () {
|
||||
return this.aceEditor.getValue()
|
||||
}
|
||||
}
|
102
src/TextMode.js
102
src/TextMode.js
|
@ -3,8 +3,30 @@ import { parseJSON } from './utils/jsonUtils'
|
|||
import { jsonToData, dataToJson, patchData } from './jsonData'
|
||||
import ModeButton from './menu/ModeButton'
|
||||
|
||||
/**
|
||||
* TextMode
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <TextMode
|
||||
* options={Object}
|
||||
* onChange={function(text: string)}
|
||||
* onChangeMode={function(mode: string)}
|
||||
* />
|
||||
*
|
||||
* Methods:
|
||||
*
|
||||
* setText(text)
|
||||
* getText() : text
|
||||
* set(json : JSON)
|
||||
* get() : JSON
|
||||
* patch(actions: JSONPatch)
|
||||
* format()
|
||||
* compact()
|
||||
* destroy()
|
||||
*
|
||||
*/
|
||||
export default class TextMode extends Component {
|
||||
// TODO: define propTypes
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
@ -16,29 +38,7 @@ export default class TextMode extends Component {
|
|||
|
||||
render (props, state) {
|
||||
return h('div', {class: 'jsoneditor jsoneditor-mode-text'}, [
|
||||
h('div', {class: 'jsoneditor-menu'}, [
|
||||
h('button', {
|
||||
class: 'jsoneditor-format',
|
||||
title: 'Format the JSON document',
|
||||
onClick: this.handleFormat
|
||||
}),
|
||||
h('button', {
|
||||
class: 'jsoneditor-compact',
|
||||
title: 'Compact the JSON document',
|
||||
onClick: this.handleCompact
|
||||
}),
|
||||
|
||||
// TODO: implement a button "Fix JSON"
|
||||
|
||||
h('div', {class: 'jsoneditor-vertical-menu-separator'}),
|
||||
|
||||
this.props.options.modes && h(ModeButton, {
|
||||
modes: this.props.options.modes,
|
||||
mode: this.props.mode,
|
||||
onMode: this.props.onMode,
|
||||
onError: this.handleError
|
||||
})
|
||||
]),
|
||||
this.renderMenu(),
|
||||
|
||||
h('div', {class: 'jsoneditor-contents'}, [
|
||||
h('textarea', {
|
||||
|
@ -50,10 +50,37 @@ export default class TextMode extends Component {
|
|||
])
|
||||
}
|
||||
|
||||
/** @protected */
|
||||
renderMenu () {
|
||||
return h('div', {class: 'jsoneditor-menu'}, [
|
||||
h('button', {
|
||||
class: 'jsoneditor-format',
|
||||
title: 'Format the JSON document',
|
||||
onClick: this.handleFormat
|
||||
}),
|
||||
h('button', {
|
||||
class: 'jsoneditor-compact',
|
||||
title: 'Compact the JSON document',
|
||||
onClick: this.handleCompact
|
||||
}),
|
||||
|
||||
// TODO: implement a button "Repair"
|
||||
|
||||
h('div', {class: 'jsoneditor-vertical-menu-separator'}),
|
||||
|
||||
this.props.options.modes && h(ModeButton, {
|
||||
modes: this.props.options.modes,
|
||||
mode: this.props.mode,
|
||||
onChangeMode: this.props.onChangeMode,
|
||||
onError: this.handleError
|
||||
})
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured indentation
|
||||
* @return {number}
|
||||
* @private
|
||||
* @protected
|
||||
*/
|
||||
getIndentation () {
|
||||
return this.props.options && this.props.options.indentation || 2
|
||||
|
@ -62,15 +89,13 @@ export default class TextMode extends Component {
|
|||
/**
|
||||
* handle changed text input in the textarea
|
||||
* @param {Event} event
|
||||
* @private
|
||||
* @protected
|
||||
*/
|
||||
handleChange = (event) => {
|
||||
this.setState({
|
||||
text: event.target.value
|
||||
})
|
||||
this.setText(event.target.value)
|
||||
}
|
||||
|
||||
/** @private */
|
||||
/** @protected */
|
||||
handleFormat = () => {
|
||||
try {
|
||||
this.format()
|
||||
|
@ -80,7 +105,7 @@ export default class TextMode extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
/** @protected */
|
||||
handleCompact = () => {
|
||||
try {
|
||||
this.compact()
|
||||
|
@ -90,7 +115,7 @@ export default class TextMode extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
/** @protected */
|
||||
handleError = (err) => {
|
||||
if (this.props.options && this.props.options.onError) {
|
||||
this.props.options.onError(err)
|
||||
|
@ -145,9 +170,7 @@ export default class TextMode extends Component {
|
|||
* @param {Object | Array | string | number | boolean | null} json JSON data
|
||||
*/
|
||||
set (json) {
|
||||
this.setState({
|
||||
text: JSON.stringify(json, null, this.getIndentation())
|
||||
})
|
||||
this.setText(JSON.stringify(json, null, this.getIndentation()))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +178,7 @@ export default class TextMode extends Component {
|
|||
* @returns {Object | Array | string | number | boolean | null} json
|
||||
*/
|
||||
get () {
|
||||
return parseJSON(this.state.text)
|
||||
return parseJSON(this.getText())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,4 +196,11 @@ export default class TextMode extends Component {
|
|||
getText () {
|
||||
return this.state.text
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the editor
|
||||
*/
|
||||
destroy () {
|
||||
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ export default class TreeMode extends Component {
|
|||
}
|
||||
|
||||
render (props, state) {
|
||||
// TODO: make mode tree dynamic
|
||||
// TODO: make mode tree dynamic: can be 'tree', 'form', 'view'
|
||||
return h('div', {
|
||||
class: 'jsoneditor jsoneditor-mode-tree',
|
||||
'data-jsoneditor': 'true'
|
||||
|
@ -104,7 +104,7 @@ export default class TreeMode extends Component {
|
|||
this.props.options.modes && h(ModeButton, {
|
||||
modes: this.props.options.modes,
|
||||
mode: this.props.mode,
|
||||
onMode: this.props.onMode,
|
||||
onChangeMode: this.props.onChangeMode,
|
||||
onError: this.handleError
|
||||
})
|
||||
])
|
||||
|
@ -365,6 +365,13 @@ export default class TreeMode extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the editor
|
||||
*/
|
||||
destroy () {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Default function to determine whether or not to expand a node initially
|
||||
*
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// load brace
|
||||
import ace from 'brace'
|
||||
|
||||
// load required ace plugins
|
||||
import 'brace/mode/json'
|
||||
import 'brace/ext/searchbox'
|
||||
|
||||
export default ace
|
|
@ -0,0 +1,144 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function(acequire, exports, module) {
|
||||
|
||||
exports.isDark = false;
|
||||
exports.cssClass = "ace-jsoneditor";
|
||||
exports.cssText = ".ace-jsoneditor .ace_gutter {\
|
||||
background: #ebebeb;\
|
||||
color: #333\
|
||||
}\
|
||||
\
|
||||
.ace-jsoneditor.ace_editor {\
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;\
|
||||
line-height: 1.3;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_print-margin {\
|
||||
width: 1px;\
|
||||
background: #e8e8e8\
|
||||
}\
|
||||
.ace-jsoneditor .ace_scroller {\
|
||||
background-color: #FFFFFF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_text-layer {\
|
||||
color: gray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_variable {\
|
||||
color: #1a1a1a\
|
||||
}\
|
||||
.ace-jsoneditor .ace_cursor {\
|
||||
border-left: 2px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selection {\
|
||||
background: lightgray\
|
||||
}\
|
||||
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\
|
||||
box-shadow: 0 0 3px 0px #FFFFFF;\
|
||||
border-radius: 2px\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_step {\
|
||||
background: rgb(255, 255, 0)\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_bracket {\
|
||||
margin: -1px 0 0 -1px;\
|
||||
border: 1px solid #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_active-line {\
|
||||
background: #FFFBD1\
|
||||
}\
|
||||
.ace-jsoneditor .ace_gutter-active-line {\
|
||||
background-color : #dcdcdc\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selected-word {\
|
||||
border: 1px solid lightgray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invisible {\
|
||||
color: #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword,\
|
||||
.ace-jsoneditor .ace_meta,\
|
||||
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\
|
||||
color: #AF956F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_operator {\
|
||||
color: #484848\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\
|
||||
color: #96DC5F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_language {\
|
||||
color: darkorange\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_numeric {\
|
||||
color: red\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_character.ace_entity {\
|
||||
color: #BF78CC\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invalid {\
|
||||
color: #FFFFFF;\
|
||||
background-color: #FF002A;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_fold {\
|
||||
background-color: #AF956F;\
|
||||
border-color: #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_storage,\
|
||||
.ace-jsoneditor .ace_support.ace_class,\
|
||||
.ace-jsoneditor .ace_support.ace_function,\
|
||||
.ace-jsoneditor .ace_support.ace_other,\
|
||||
.ace-jsoneditor .ace_support.ace_type {\
|
||||
color: #C52727\
|
||||
}\
|
||||
.ace-jsoneditor .ace_string {\
|
||||
color: green\
|
||||
}\
|
||||
.ace-jsoneditor .ace_comment {\
|
||||
color: #BCC8BA\
|
||||
}\
|
||||
.ace-jsoneditor .ace_entity.ace_name.ace_tag,\
|
||||
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\
|
||||
color: #606060\
|
||||
}\
|
||||
.ace-jsoneditor .ace_markup.ace_underline {\
|
||||
text-decoration: underline\
|
||||
}\
|
||||
.ace-jsoneditor .ace_indent-guide {\
|
||||
background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\
|
||||
}";
|
||||
|
||||
var dom = acequire("../lib/dom");
|
||||
dom.importCssString(exports.cssText, exports.cssClass);
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
<!-- For IE and Edge -->
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.min.js"></script>-->
|
||||
|
||||
<script src="../dist/jsoneditor-minimalist.js"></script>
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
<style>
|
||||
#container {
|
||||
height: 300px;
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
<label for="mode">mode:
|
||||
<select id="mode">
|
||||
<option value="code">code</option>
|
||||
<option value="text">text</option>
|
||||
<option value="tree" selected>tree</option>
|
||||
</select>
|
||||
|
@ -30,6 +31,7 @@
|
|||
|
||||
<script>
|
||||
// create the editor
|
||||
const mode = document.getElementById('mode').value
|
||||
const container = document.getElementById('container')
|
||||
const options = {
|
||||
onChange: function (patch, revert) {
|
||||
|
@ -39,12 +41,14 @@
|
|||
},
|
||||
onChangeMode: function (mode, prevMode) {
|
||||
console.log('switched mode from', prevMode, 'to', mode)
|
||||
document.getElementById('mode').value = mode
|
||||
},
|
||||
onError: function (err) {
|
||||
console.error(err)
|
||||
alert(err)
|
||||
},
|
||||
modes: ['text', 'tree'],
|
||||
mode: mode,
|
||||
modes: ['text', 'code', 'tree'],
|
||||
indentation: 4
|
||||
}
|
||||
const editor = jsoneditor(container, options)
|
||||
|
|
37
src/index.js
37
src/index.js
|
@ -1,13 +1,15 @@
|
|||
import { h, render } from 'preact'
|
||||
import TreeMode from './TreeMode'
|
||||
import CodeMode from './CodeMode'
|
||||
import TextMode from './TextMode'
|
||||
import TreeMode from './TreeMode'
|
||||
|
||||
import '!style!css!less!./jsoneditor.less'
|
||||
|
||||
// TODO: allow adding new modes
|
||||
const modes = {
|
||||
tree: TreeMode,
|
||||
text: TextMode
|
||||
code: CodeMode,
|
||||
text: TextMode,
|
||||
tree: TreeMode
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,6 +123,7 @@ function jsoneditor (container, options = {}) {
|
|||
}
|
||||
|
||||
let success = false
|
||||
let initialChildCount = editor._container.children.length
|
||||
let element
|
||||
try {
|
||||
// find the constructor for the selected mode
|
||||
|
@ -130,12 +133,22 @@ function jsoneditor (container, options = {}) {
|
|||
'Choose from: ' + Object.keys(modes).join(', '))
|
||||
}
|
||||
|
||||
function handleChangeMode (mode) {
|
||||
const prevMode = editor._mode
|
||||
|
||||
editor.setMode(mode)
|
||||
|
||||
if (editor._options.onChangeMode) {
|
||||
editor._options.onChangeMode(mode, prevMode)
|
||||
}
|
||||
}
|
||||
|
||||
// create new component
|
||||
element = render(
|
||||
h(constructor, {
|
||||
mode,
|
||||
options: editor._options,
|
||||
onMode: editor.setMode
|
||||
onChangeMode: handleChangeMode
|
||||
}),
|
||||
editor._container)
|
||||
|
||||
|
@ -150,22 +163,22 @@ function jsoneditor (container, options = {}) {
|
|||
if (success) {
|
||||
// destroy previous component
|
||||
if (editor._element) {
|
||||
// TODO: call editor._component.destroy() instead
|
||||
editor._element._component.destroy()
|
||||
editor._element.parentNode.removeChild(editor._element)
|
||||
}
|
||||
|
||||
const prevMode = editor._mode
|
||||
editor._mode = mode
|
||||
editor._element = element
|
||||
editor._component = element._component
|
||||
|
||||
if (editor._options.onChangeMode && prevMode) {
|
||||
editor._options.onChangeMode(mode, prevMode)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// remove the just created component (where setText failed)
|
||||
element.parentNode.removeChild(element)
|
||||
// TODO: fall back to text mode when loading code mode failed?
|
||||
|
||||
// remove the just created component if any (where construction or setText failed)
|
||||
const childCount = editor._container.children.length
|
||||
if (childCount !== initialChildCount) {
|
||||
editor._container.removeChild(editor._container.lastChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export default class ModeButton extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {{modes: string[], mode: string, onMode: function, onError: function}} props
|
||||
* @param {{modes: string[], mode: string, onChangeMode: function, onError: function}} props
|
||||
* @param state
|
||||
* @return {*}
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@ import { findParentNode } from '../utils/domUtils'
|
|||
|
||||
export default class ModeMenu extends Component {
|
||||
/**
|
||||
* @param {{open, modes, mode, onMode, onRequestClose, onError}} props
|
||||
* @param {{open, modes, mode, onChangeMode, onRequestClose, onError}} props
|
||||
* @param {Object} state
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
|
@ -17,7 +17,7 @@ export default class ModeMenu extends Component {
|
|||
((mode === props.mode) ? ' jsoneditor-selected' : ''),
|
||||
onClick: () => {
|
||||
try {
|
||||
props.onMode(mode)
|
||||
props.onChangeMode(mode)
|
||||
props.onRequestClose()
|
||||
}
|
||||
catch (err) {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* }} JSONPatchResult
|
||||
*
|
||||
* @typedef {{
|
||||
* mode: 'tree' | 'text',
|
||||
* mode: 'tree' | 'text' | 'code',
|
||||
* modes: string[],
|
||||
* indentation: number | string,
|
||||
* onChange: function (patch: JSONPatch, revert: JSONPatch),
|
||||
|
|
|
@ -19,7 +19,6 @@ export function parseJSON(jsonString) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a string containing a JSON object
|
||||
* This method uses JSONLint to validate the String. If JSONLint is not
|
||||
|
|
Loading…
Reference in New Issue