Refactored path to be a JSON pointer
This commit is contained in:
parent
37ae2111ee
commit
cd08e16789
|
@ -4,7 +4,7 @@ import ContextMenu from './ContextMenu'
|
||||||
import { escapeHTML, unescapeHTML } from './utils/stringUtils'
|
import { escapeHTML, unescapeHTML } from './utils/stringUtils'
|
||||||
import { getInnerText } from './utils/domUtils'
|
import { getInnerText } from './utils/domUtils'
|
||||||
import {stringConvert, valueType, isUrl} from './utils/typeUtils'
|
import {stringConvert, valueType, isUrl} from './utils/typeUtils'
|
||||||
import { last } from './utils/arrayUtils'
|
import * as pointer from 'json-pointer'
|
||||||
|
|
||||||
export default class JSONNode extends Component {
|
export default class JSONNode extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -102,10 +102,9 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderProperty (data, index, options) {
|
renderProperty (data, index, options) {
|
||||||
const property = last(data.path)
|
const isProperty = typeof data.prop === 'string'
|
||||||
const isProperty = typeof property === 'string'
|
|
||||||
const content = isProperty
|
const content = isProperty
|
||||||
? escapeHTML(property) // render the property name
|
? escapeHTML(data.prop) // render the property name
|
||||||
: index !== undefined
|
: index !== undefined
|
||||||
? index // render the array index of the item
|
? index // render the array index of the item
|
||||||
: JSONNode._rootName(data, options)
|
: JSONNode._rootName(data, options)
|
||||||
|
@ -169,11 +168,11 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeProperty (event) {
|
handleChangeProperty (event) {
|
||||||
const property = unescapeHTML(getInnerText(event.target))
|
const oldProp = this.props.data.prop
|
||||||
const oldPath = this.props.data.path
|
const newProp = unescapeHTML(getInnerText(event.target))
|
||||||
const newPath = oldPath.slice(0, oldPath.length - 1).concat(property)
|
const path = this.props.data.path.replace(/\/.+$/, '') // remove last entry
|
||||||
|
|
||||||
this.props.events.onChangeProperty(oldPath, newPath)
|
this.props.events.onChangeProperty(path, oldProp, newProp)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeValue (event) {
|
handleChangeValue (event) {
|
||||||
|
|
73
src/Main.js
73
src/Main.js
|
@ -1,7 +1,7 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
|
import * as pointer from 'json-pointer'
|
||||||
|
|
||||||
import { setIn } from './utils/objectUtils'
|
import { setIn, getIn } from './utils/objectUtils'
|
||||||
import { last } from './utils/arrayUtils'
|
|
||||||
import { isObject } from './utils/typeUtils'
|
import { isObject } from './utils/typeUtils'
|
||||||
import JSONNode from './JSONNode'
|
import JSONNode from './JSONNode'
|
||||||
|
|
||||||
|
@ -46,25 +46,34 @@ export default class Main extends Component {
|
||||||
_onChangeValue (path, value) {
|
_onChangeValue (path, value) {
|
||||||
console.log('_onChangeValue', path, value)
|
console.log('_onChangeValue', path, value)
|
||||||
|
|
||||||
const modelPath = Main._pathToModelPath(this.state.data, path).concat('value')
|
const modelPath = Main._pathToModelPath(this.state.data, Main._parsePath(path)).concat('value')
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: setIn(this.state.data, modelPath, value)
|
data: setIn(this.state.data, modelPath, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChangeProperty (oldPath, newPath) {
|
_onChangeProperty (path, oldProp, newProp) {
|
||||||
console.log('_onChangeProperty', oldPath, newPath)
|
console.log('_onChangeProperty', path, oldProp, newProp)
|
||||||
|
|
||||||
const modelPath = Main._pathToModelPath(this.state.data, oldPath).concat('path')
|
const array = pointer.parse(path)
|
||||||
|
const parent = getIn(this.state.data, array)
|
||||||
|
const index = parent.childs.findIndex(child => child.prop === oldProp)
|
||||||
|
|
||||||
this.setState({
|
const newPath = path + '/' + pointer.escape(newProp)
|
||||||
data: setIn(this.state.data, modelPath, newPath)
|
const modelPath = Main._pathToModelPath(this.state.data, array).concat(['childs', index])
|
||||||
})
|
|
||||||
|
let data = this.state.data
|
||||||
|
data = setIn(data, modelPath.concat('path'), newPath)
|
||||||
|
data = setIn(data, modelPath.concat('prop'), newProp)
|
||||||
|
|
||||||
|
this.setState({ data })
|
||||||
}
|
}
|
||||||
|
|
||||||
_onExpand(path, expand) {
|
_onExpand(path, expand) {
|
||||||
const modelPath = Main._pathToModelPath(this.state.data, path).concat('expanded')
|
const modelPath = Main._pathToModelPath(this.state.data, Main._parsePath(path)).concat('expanded')
|
||||||
|
|
||||||
|
console.log('_onExpand', path, modelPath)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: setIn(this.state.data, modelPath, expand)
|
data: setIn(this.state.data, modelPath, expand)
|
||||||
|
@ -72,7 +81,7 @@ export default class Main extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onContextMenu(path, visible) {
|
_onContextMenu(path, visible) {
|
||||||
const modelPath = Main._pathToModelPath(this.state.data, path).concat('menu')
|
const modelPath = Main._pathToModelPath(this.state.data, Main._parsePath(path)).concat('menu')
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: setIn(this.state.data, modelPath, visible)
|
data: setIn(this.state.data, modelPath, visible)
|
||||||
|
@ -87,17 +96,34 @@ export default class Main extends Component {
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
set (json) {
|
set (json) {
|
||||||
this.setState({
|
this.setState({
|
||||||
data: Main._jsonToModel([], json, this.state.options.expand)
|
data: Main._jsonToModel('', null, json, this.state.options.expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default function to determine whether or not to expand a node initially
|
* Default function to determine whether or not to expand a node initially
|
||||||
* @param {Array.<string | number>} path
|
*
|
||||||
|
* Rule: expand the root node only
|
||||||
|
*
|
||||||
|
* @param {string} path A JSON Pointer path
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
static expand (path) {
|
static expand (path) {
|
||||||
return path.length === 0
|
return path.indexOf('/') === -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse json pointer into an array, and replace strings containing a number
|
||||||
|
* with a number
|
||||||
|
* @param {string} path
|
||||||
|
* @return {Array.<string | number>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _parsePath (path) {
|
||||||
|
return pointer.parse(path).map(item => {
|
||||||
|
const num = Number(item)
|
||||||
|
return isNaN(num) ? item : num
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,7 +145,7 @@ export default class Main extends Component {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// object property. find the index of this property
|
// object property. find the index of this property
|
||||||
index = model.childs.findIndex(child => last(child.path) === path[0])
|
index = model.childs.findIndex(child => child.prop === path[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['childs', index]
|
return ['childs', index]
|
||||||
|
@ -128,19 +154,21 @@ export default class Main extends Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a JSON object into the internally used data model
|
* Convert a JSON object into the internally used data model
|
||||||
* @param {Array.<string | number>} path
|
* @param {string} path
|
||||||
|
* @param {string | null} prop
|
||||||
* @param {Object | Array | string | number | boolean | null} value
|
* @param {Object | Array | string | number | boolean | null} value
|
||||||
* @param {function(path: Array.<string>)} expand
|
* @param {function(path: string)} expand
|
||||||
* @return {Model}
|
* @return {Model}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
static _jsonToModel (path, value, expand) {
|
static _jsonToModel (path, prop, value, expand) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return {
|
return {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
expanded: expand(path),
|
expanded: expand(path),
|
||||||
path,
|
path,
|
||||||
childs: value.map((child, index) => Main._jsonToModel(path.concat(index), child, expand))
|
prop,
|
||||||
|
childs: value.map((child, index) => Main._jsonToModel(path + '/' + index, null, child, expand))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isObject(value)) {
|
else if (isObject(value)) {
|
||||||
|
@ -148,8 +176,9 @@ export default class Main extends Component {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
expanded: expand(path),
|
expanded: expand(path),
|
||||||
path,
|
path,
|
||||||
|
prop,
|
||||||
childs: Object.keys(value).map(prop => {
|
childs: Object.keys(value).map(prop => {
|
||||||
return Main._jsonToModel(path.concat(prop), value[prop], expand)
|
return Main._jsonToModel(path + '/' + pointer.escape(prop), prop, value[prop], expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +186,7 @@ export default class Main extends Component {
|
||||||
return {
|
return {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
path,
|
path,
|
||||||
|
prop,
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,8 +206,7 @@ export default class Main extends Component {
|
||||||
const object = {}
|
const object = {}
|
||||||
|
|
||||||
model.childs.forEach(child => {
|
model.childs.forEach(child => {
|
||||||
const prop = last(child.path)
|
object[child.prop] = Main._modelToJson(child)
|
||||||
object[prop] = Main._modelToJson(child)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return object
|
return object
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
* type: string,
|
* type: string,
|
||||||
* expanded: boolean?,
|
* expanded: boolean?,
|
||||||
* menu: boolean?,
|
* menu: boolean?,
|
||||||
* path: Array.<string | number>,
|
* path: string,
|
||||||
|
* prop: string?,
|
||||||
* value: *?,
|
* value: *?,
|
||||||
* childs: Model[]?
|
* childs: Model[]?
|
||||||
* }} Model
|
* }} Model
|
||||||
|
|
Loading…
Reference in New Issue