diff --git a/src/TextMode.js b/src/TextMode.js new file mode 100644 index 0000000..77b7645 --- /dev/null +++ b/src/TextMode.js @@ -0,0 +1,101 @@ +import { h, Component } from 'preact' +import { parseJSON } from './utils/jsonUtils' + +export default class TextMode extends Component { + // TODO: define propTypes + + constructor (props) { + super(props) + + this.state = { + text: '{}' + } + } + + 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.format + }), + h('button', { + class: 'jsoneditor-compact', + title: 'Compact the JSON document', + onClick: this.compact + }) + // TODO: implement a button "Fix JSON" + ]), + + h('div', {class: 'jsoneditor-contents'}, [ + h('textarea', {class: 'jsoneditor-text', value: this.state.text}) + ]) + ]) + } + + /** + * Get the configured indentation + * @return {number} + * @private + */ + getIndentation () { + return this.props.options && this.props.options.indentation || 2 + } + + /** + * Format the json + */ + format = () => { + var json = this.get() + var text = JSON.stringify(json, null, this.getIndentation()) + this.setText(text) + } + + /** + * Compact the json + */ + compact = () => { + var json = this.get() + var text = JSON.stringify(json) + this.setText(text) + } + + /** + * Apply a JSONPatch to the current JSON document + * @param {JSONPatch} actions JSONPatch actions + * @return {JSONPatch} Returns a JSONPatch to revert the applied patch + */ + patch (actions) { + // TODO: implement patch + throw new Error('Patch not yet implemented') + } + + /** + * Set JSON object in editor + * @param {Object | Array | string | number | boolean | null} json JSON data + */ + set (json) { + this.setState({ + text: JSON.stringify(json, null, this.getIndentation()) + }) + } + + /** + * Get JSON from the editor + * @returns {Object | Array | string | number | boolean | null} json + */ + get () { + return parseJSON(this.state.text) + } + + // TODO: comment + setText (text) { + this.setState({ text }) + } + + // TODO: comment + getText () { + return this.state.text + } +} \ No newline at end of file diff --git a/src/TreeMode.js b/src/TreeMode.js index ab0594c..100ec6d 100644 --- a/src/TreeMode.js +++ b/src/TreeMode.js @@ -48,7 +48,8 @@ export default class TreeMode extends Component { } render (props, state) { - return h('div', {class: 'jsoneditor'}, [ + // TODO: make mode tree dynamic + return h('div', {class: 'jsoneditor jsoneditor-mode-tree'}, [ h('div', {class: 'jsoneditor-menu'}, [ h('button', { class: 'jsoneditor-expand-all', @@ -75,8 +76,8 @@ export default class TreeMode extends Component { }) ]), - h('div', {class: 'jsoneditor-treemode', contentEditable: 'false', onClick: JSONNode.hideContextMenu}, [ - h('ul', {class: 'jsoneditor-list', contentEditable: 'false'}, [ + h('div', {class: 'jsoneditor-contents jsoneditor-tree-contents', onClick: JSONNode.hideContextMenu}, [ + h('ul', {class: 'jsoneditor-list'}, [ h(JSONNode, { data: state.data, events: state.events, diff --git a/src/develop.html b/src/develop.html index ea501d7..e59da97 100644 --- a/src/develop.html +++ b/src/develop.html @@ -29,7 +29,9 @@ console.log('onChange patch=', patch, ', revert=', revert) window.patch = patch window.revert = revert - } + }, + mode: 'text', + indentation: 4 }; const editor = jsoneditor(container, options); const json = { diff --git a/src/index.js b/src/index.js index 271a02f..117597d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,16 @@ import { h, render } from 'preact' import TreeMode from './TreeMode' +import TextMode from './TextMode' import '!style!css!less!./jsoneditor.less' +// TODO: allow adding new modes +const modes = { + tree: TreeMode, + text: TextMode, + default: TreeMode +} + /** * Create a new json editor * @param {HTMLElement} container @@ -11,7 +19,10 @@ import '!style!css!less!./jsoneditor.less' * @constructor */ function jsoneditor (container, options) { - const elem = render(h(TreeMode, {options}), container) + const mode = options && options.mode + const constructor = modes[mode] || modes['default'] + + const elem = render(h(constructor, {options}), container) const component = elem._component return { @@ -20,6 +31,7 @@ function jsoneditor (container, options) { _container: container, _options: options, _component: component, + _modes: modes, // TODO: implement setMode diff --git a/src/jsoneditor.less b/src/jsoneditor.less index 430c90b..1759d98 100644 --- a/src/jsoneditor.less +++ b/src/jsoneditor.less @@ -1,8 +1,11 @@ +@fontFamily: droid sans mono, consolas, monospace, courier new, courier, sans-serif; +@fontSize: 10pt; +@black: #1A1A1A; + .jsoneditor { border: 1px solid #3883fa; width: 100%; height: 100%; - min-height: 150px; display: inline-flex; flex-direction: column; @@ -69,16 +72,30 @@ background-position: -48px -120px; } + button.jsoneditor-compact { + background-position: -72px -96px; + } + button.jsoneditor-format { + background-position: -72px -120px; + } } -.jsoneditor-treemode { +.jsoneditor-contents { width: 100%; height: 100%; - overflow: auto; - padding: 2px 0; + min-height: 150px; + + overflow: hidden; + padding: 0; + margin: 0; flex: 1 1 auto; } +.jsoneditor-tree-contents { + padding: 2px 0; + overflow: auto; +} + .jsoneditor-node { position: relative; @@ -110,8 +127,8 @@ ul.jsoneditor-list { .jsoneditor-separator { line-height: 20px; - font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif; - font-size: 10pt; + font-family: @fontFamily; + font-size: @fontSize; } .jsoneditor-property, @@ -122,7 +139,7 @@ ul.jsoneditor-list { padding: 0 5px; - color: #1A1A1A; + color: @black; outline: none; } @@ -315,7 +332,7 @@ button.jsoneditor-menu-button { button.jsoneditor-menu-button:hover, button.jsoneditor-menu-button:focus { - color: #1a1a1a; + color: @black; background-color: #f5f5f5; outline: none; } @@ -481,3 +498,21 @@ button.jsoneditor-type-Array:focus span.jsoneditor-icon, button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon { background-position: -96px 0; } + + +textarea.jsoneditor-text { + width: 100%; + height: 100%; + min-height: 150px; + + margin: 0; + box-sizing: border-box; + outline-width: 0; + border: none; + background-color: #fff; + resize: none; + + font-family: @fontFamily; + font-size: @fontSize; + color: @black; +} diff --git a/src/typedef.js b/src/typedef.js index 3516258..9b1b275 100644 --- a/src/typedef.js +++ b/src/typedef.js @@ -25,7 +25,7 @@ * @typedef {Array.<{op: string, path?: string, from?: string, value?: *}>} JSONPatch * * @typedef {{ - * + * mode: 'tree' | 'text' * }} Options * * @typedef {{