Refactored path to be a JSON pointer

This commit is contained in:
jos 2016-07-16 14:24:28 +02:00
parent 37ae2111ee
commit cd08e16789
3 changed files with 60 additions and 31 deletions

View File

@ -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) {

View File

@ -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

View File

@ -4,7 +4,8 @@
* type: string,
* expanded: boolean?,
* menu: boolean?,
* path: Array.<string | number>,
* path: string,
* prop: string?,
* value: *?,
* childs: Model[]?
* }} Model