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 { getInnerText } from './utils/domUtils'
|
||||
import {stringConvert, valueType, isUrl} from './utils/typeUtils'
|
||||
import { last } from './utils/arrayUtils'
|
||||
import * as pointer from 'json-pointer'
|
||||
|
||||
export default class JSONNode extends Component {
|
||||
constructor (props) {
|
||||
|
@ -102,10 +102,9 @@ export default class JSONNode extends Component {
|
|||
}
|
||||
|
||||
renderProperty (data, index, options) {
|
||||
const property = last(data.path)
|
||||
const isProperty = typeof property === 'string'
|
||||
const isProperty = typeof data.prop === 'string'
|
||||
const content = isProperty
|
||||
? escapeHTML(property) // render the property name
|
||||
? escapeHTML(data.prop) // render the property name
|
||||
: index !== undefined
|
||||
? index // render the array index of the item
|
||||
: JSONNode._rootName(data, options)
|
||||
|
@ -169,11 +168,11 @@ export default class JSONNode extends Component {
|
|||
}
|
||||
|
||||
handleChangeProperty (event) {
|
||||
const property = unescapeHTML(getInnerText(event.target))
|
||||
const oldPath = this.props.data.path
|
||||
const newPath = oldPath.slice(0, oldPath.length - 1).concat(property)
|
||||
const oldProp = this.props.data.prop
|
||||
const newProp = unescapeHTML(getInnerText(event.target))
|
||||
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) {
|
||||
|
|
73
src/Main.js
73
src/Main.js
|
@ -1,7 +1,7 @@
|
|||
import { h, Component } from 'preact'
|
||||
import * as pointer from 'json-pointer'
|
||||
|
||||
import { setIn } from './utils/objectUtils'
|
||||
import { last } from './utils/arrayUtils'
|
||||
import { setIn, getIn } from './utils/objectUtils'
|
||||
import { isObject } from './utils/typeUtils'
|
||||
import JSONNode from './JSONNode'
|
||||
|
||||
|
@ -46,25 +46,34 @@ export default class Main extends Component {
|
|||
_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({
|
||||
data: setIn(this.state.data, modelPath, value)
|
||||
})
|
||||
}
|
||||
|
||||
_onChangeProperty (oldPath, newPath) {
|
||||
console.log('_onChangeProperty', oldPath, newPath)
|
||||
_onChangeProperty (path, oldProp, newProp) {
|
||||
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({
|
||||
data: setIn(this.state.data, modelPath, newPath)
|
||||
})
|
||||
const newPath = path + '/' + pointer.escape(newProp)
|
||||
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) {
|
||||
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({
|
||||
data: setIn(this.state.data, modelPath, expand)
|
||||
|
@ -72,7 +81,7 @@ export default class Main extends Component {
|
|||
}
|
||||
|
||||
_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({
|
||||
data: setIn(this.state.data, modelPath, visible)
|
||||
|
@ -87,17 +96,34 @@ export default class Main extends Component {
|
|||
// TODO: comment
|
||||
set (json) {
|
||||
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
|
||||
* @param {Array.<string | number>} path
|
||||
*
|
||||
* Rule: expand the root node only
|
||||
*
|
||||
* @param {string} path A JSON Pointer path
|
||||
* @return {boolean}
|
||||
*/
|
||||
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 {
|
||||
// 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]
|
||||
|
@ -128,19 +154,21 @@ export default class Main extends Component {
|
|||
|
||||
/**
|
||||
* 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 {function(path: Array.<string>)} expand
|
||||
* @param {function(path: string)} expand
|
||||
* @return {Model}
|
||||
* @private
|
||||
*/
|
||||
static _jsonToModel (path, value, expand) {
|
||||
static _jsonToModel (path, prop, value, expand) {
|
||||
if (Array.isArray(value)) {
|
||||
return {
|
||||
type: 'array',
|
||||
expanded: expand(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)) {
|
||||
|
@ -148,8 +176,9 @@ export default class Main extends Component {
|
|||
type: 'object',
|
||||
expanded: expand(path),
|
||||
path,
|
||||
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 {
|
||||
type: 'auto',
|
||||
path,
|
||||
prop,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +206,7 @@ export default class Main extends Component {
|
|||
const object = {}
|
||||
|
||||
model.childs.forEach(child => {
|
||||
const prop = last(child.path)
|
||||
object[prop] = Main._modelToJson(child)
|
||||
object[child.prop] = Main._modelToJson(child)
|
||||
})
|
||||
|
||||
return object
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* type: string,
|
||||
* expanded: boolean?,
|
||||
* menu: boolean?,
|
||||
* path: Array.<string | number>,
|
||||
* path: string,
|
||||
* prop: string?,
|
||||
* value: *?,
|
||||
* childs: Model[]?
|
||||
* }} Model
|
||||
|
|
Loading…
Reference in New Issue