From 8f6ddf91bc9ea2746688dad321b5e0c64a3e1f12 Mon Sep 17 00:00:00 2001 From: jos Date: Fri, 28 Oct 2016 13:24:51 +0200 Subject: [PATCH] Implemented `isValueEditable` and `isPropertyEditable` --- ...=> 05_readonly_properties_and_values.html} | 39 ++++----- src/JSONNode.js | 83 +++++++++++-------- src/TreeMode.js | 12 +-- src/develop.html | 2 +- src/index.js | 6 ++ src/typedef.js | 6 +- 6 files changed, 79 insertions(+), 69 deletions(-) rename examples/{_05_custom_fields_editable.html => 05_readonly_properties_and_values.html} (55%) diff --git a/examples/_05_custom_fields_editable.html b/examples/05_readonly_properties_and_values.html similarity index 55% rename from examples/_05_custom_fields_editable.html rename to examples/05_readonly_properties_and_values.html index a245ce0..301a0a4 100644 --- a/examples/_05_custom_fields_editable.html +++ b/examples/05_readonly_properties_and_values.html @@ -1,7 +1,7 @@ - Custom editable fields | JSONEditor + Read-only properties and values | JSONEditor @@ -27,26 +27,22 @@ var container = document.getElementById('jsoneditor'); var options = { - onEditable: function (node) { - // node is an object like: - // { - // field: 'FIELD', - // value: 'VALUE', - // path: ['PATH', 'TO', 'NODE'] - // } - switch (node.field) { - case '_id': - return false; - - case 'name': - return { - field: false, - value: true - } - - default: - return true; + // all properties are editable except '_id' and 'name' + isPropertyEditable: function (path) { + if (path.length === 1 && path[0] === '_id' || path[0] === 'name') { + return false } + + return true + }, + + // all values are editable except '_id' + isValueEditable: function (path) { + if (path.length === 1 && path[0] === '_id') { + return false + } + + return true } } @@ -56,7 +52,8 @@ age: 32 } - var editor = jsoneditor(container, options, json) + var editor = jsoneditor(container, options) + editor.set(json) diff --git a/src/JSONNode.js b/src/JSONNode.js index 9eef634..b03dedd 100644 --- a/src/JSONNode.js +++ b/src/JSONNode.js @@ -114,7 +114,7 @@ export default class JSONNode extends Component { this.renderActionMenuButton(), this.renderProperty(prop, data, options), this.renderSeparator(), - this.renderValue(data.value) + this.renderValue(data.value, options) ]) ]) } @@ -143,35 +143,35 @@ export default class JSONNode extends Component { } renderProperty (prop, data, options) { - if (prop !== null) { - const isIndex = typeof prop === 'number' // FIXME: pass an explicit prop isIndex - - if (isIndex) { // array item - return h('div', { - class: 'jsoneditor-property jsoneditor-readonly', - spellCheck: 'false' - }, prop) - } - else { // object property - const escapedProp = escapeHTML(prop) - - return h('div', { - class: 'jsoneditor-property' + (prop.length === 0 ? ' jsoneditor-empty' : ''), - contentEditable: 'true', - spellCheck: 'false', - onBlur: this.handleChangeProperty - }, escapedProp) - } - } - else { + if (prop === null) { // root node - const content = JSONNode.getRootName(data, options) + const rootName = JSONNode.getRootName(data, options) return h('div', { class: 'jsoneditor-property jsoneditor-readonly', spellCheck: 'false', onBlur: this.handleChangeProperty - }, content) + }, rootName) + } + + const isIndex = typeof prop === 'number' // FIXME: pass an explicit prop isIndex or editable + const editable = !isIndex && (!options.isPropertyEditable || options.isPropertyEditable(this.getPath())) + + if (editable) { + const escapedProp = escapeHTML(prop) + + return h('div', { + class: 'jsoneditor-property' + (prop.length === 0 ? ' jsoneditor-empty' : ''), + contentEditable: 'true', + spellCheck: 'false', + onBlur: this.handleChangeProperty + }, escapedProp) + } + else { + return h('div', { + class: 'jsoneditor-property jsoneditor-readonly', + spellCheck: 'false' + }, prop) } } @@ -179,22 +179,31 @@ export default class JSONNode extends Component { return h('div', {class: 'jsoneditor-separator'}, ':') } - renderValue (value) { + renderValue (value, options) { const escapedValue = escapeHTML(value) const type = valueType (value) const itsAnUrl = isUrl(value) const isEmpty = escapedValue.length === 0 - return h('div', { - class: JSONNode.getValueClass(type, itsAnUrl, isEmpty), - contentEditable: 'true', - spellCheck: 'false', - onBlur: this.handleChangeValue, - onInput: this.updateValueStyling, - onClick: this.handleClickValue, - onKeyDown: this.handleKeyDownValue, - title: itsAnUrl ? JSONNode.URL_TITLE : null - }, escapedValue) + const editable = !options.isValueEditable || options.isValueEditable(this.getPath()) + if (editable) { + return h('div', { + class: JSONNode.getValueClass(type, itsAnUrl, isEmpty), + contentEditable: 'true', + spellCheck: 'false', + onBlur: this.handleChangeValue, + onInput: this.updateValueStyling, + onClick: this.handleClickValue, + onKeyDown: this.handleKeyDownValue, + title: itsAnUrl ? JSONNode.URL_TITLE : null + }, escapedValue) + } + else { + return h('div', { + class: 'jsoneditor-readonly', + title: itsAnUrl ? JSONNode.URL_TITLE : null + }, escapedValue) + } } /** @@ -431,6 +440,10 @@ export default class JSONNode extends Component { return path } + isFieldEditable () { + + } + /** * Get the value of the target of an event, and convert it to it's type * @param event diff --git a/src/TreeMode.js b/src/TreeMode.js index fd50c0b..2e34656 100644 --- a/src/TreeMode.js +++ b/src/TreeMode.js @@ -21,10 +21,6 @@ export default class TreeMode extends Component { const data = jsonToData(this.props.data || {}, expand, []) this.state = { - nodeOptions: { - name: null - }, - data, history: [data], @@ -65,7 +61,7 @@ export default class TreeMode extends Component { h(Node, { data: state.data, events: state.events, - options: state.nodeOptions, + options: props.options, parent: null, prop: null }) @@ -322,13 +318,9 @@ export default class TreeMode extends Component { * @param {SetOptions} [options] */ set (json, options = {}) { - const name = options && options.name || null // the root name - const data = jsonToData(json, options.expand || TreeMode.expand, []) - this.setState({ - nodeOptions: setIn(this.state.nodeOptions, ['name'], name), + data: jsonToData(json, options.expand || TreeMode.expand, []), - data, // TODO: do we want to keep history when .set(json) is called? history: [], historyIndex: 0 diff --git a/src/develop.html b/src/develop.html index 6207665..a1b5db9 100644 --- a/src/develop.html +++ b/src/develop.html @@ -41,6 +41,7 @@ const mode = document.getElementById('mode').value const container = document.getElementById('container') const options = { + name: 'myObject', onChange: function (patch, revert) { console.log('onChange patch=', patch, ', revert=', revert) window.patch = patch @@ -74,7 +75,6 @@ 'url': 'http://jsoneditoronline.org' } editor.set(json, { - name: 'myObject', expand: function (path) { return true } diff --git a/src/index.js b/src/index.js index f26d12c..91914f5 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import { h, render } from 'preact' import CodeMode from './CodeMode' import TextMode from './TextMode' import TreeMode from './TreeMode' +import { compileJSONPointer, parseJSONPointer } from './jsonData' import '!style!css!less!./jsoneditor.less' @@ -29,6 +30,11 @@ function jsoneditor (container, options = {}) { const editor = { isJSONEditor: true, + utils: { + compileJSONPointer, + parseJSONPointer + }, + _container: container, _options: options, _modes: modes, diff --git a/src/typedef.js b/src/typedef.js index 8a943f0..debd535 100644 --- a/src/typedef.js +++ b/src/typedef.js @@ -31,17 +31,19 @@ * }} JSONPatchResult * * @typedef {{ + * name: string?, * mode?: 'code' | 'form' | 'text' | 'tree' | 'view', * modes?: string[], * indentation?: number | string, * onChange?: function (patch: JSONPatch, revert: JSONPatch), * onChangeText?: function (), * onChangeMode?: function (mode: string, prevMode: string), - * onError?: function (err: Error) + * onError?: function (err: Error), + * isPropertyEditable?: function (Path) : boolean + * isValueEditable?: function (Path) : boolean * }} Options * * @typedef {{ - * name: string?, * expand: function (path: Path)? * }} SetOptions */