Implemented a data model, fixed ordering of object properties, implemented options `name` and `expand`
This commit is contained in:
parent
fd631cd34c
commit
fda4f94655
156
src/JSONNode.js
156
src/JSONNode.js
|
@ -1,19 +1,14 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
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, isObject} from './utils/typeUtils'
|
import {stringConvert, valueType, isUrl} from './utils/typeUtils'
|
||||||
|
import { last } from './utils/arrayUtils'
|
||||||
|
|
||||||
export default class JSONNode extends Component {
|
export default class JSONNode extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.handleChangeProperty = this.handleChangeProperty.bind(this)
|
||||||
expanded: false,
|
|
||||||
value: props.value
|
|
||||||
}
|
|
||||||
|
|
||||||
this.handleChangeField = this.handleChangeField.bind(this)
|
|
||||||
this.handleBlurValue = this.handleBlurValue.bind(this)
|
|
||||||
this.handleChangeValue = this.handleChangeValue.bind(this)
|
this.handleChangeValue = this.handleChangeValue.bind(this)
|
||||||
this.handleClickValue = this.handleClickValue.bind(this)
|
this.handleClickValue = this.handleClickValue.bind(this)
|
||||||
this.handleKeyDownValue = this.handleKeyDownValue.bind(this)
|
this.handleKeyDownValue = this.handleKeyDownValue.bind(this)
|
||||||
|
@ -21,10 +16,10 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render (props) {
|
render (props) {
|
||||||
if (Array.isArray(props.value)) {
|
if (props.data.type === 'array') {
|
||||||
return this.renderJSONArray(props)
|
return this.renderJSONArray(props)
|
||||||
}
|
}
|
||||||
else if (isObject(props.value)) {
|
else if (props.data.type === 'object') {
|
||||||
return this.renderJSONObject(props)
|
return this.renderJSONObject(props)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -32,27 +27,27 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJSONObject ({parent, index, field, value, onChangeValue, onChangeField}) {
|
renderJSONObject ({data, index, options, onChangeValue, onChangeProperty, onExpand}) {
|
||||||
const childCount = Object.keys(value).length
|
const childCount = data.childs.length
|
||||||
const contents = [
|
const contents = [
|
||||||
h('div', {class: 'jsoneditor-node jsoneditor-object'}, [
|
h('div', {class: 'jsoneditor-node jsoneditor-object'}, [
|
||||||
this.renderExpandButton(),
|
this.renderExpandButton(),
|
||||||
this.renderField(parent, index, field, value),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
this.renderReadonly(`{${childCount}}`, `Array containing ${childCount} items`)
|
this.renderReadonly(`{${childCount}}`, `Array containing ${childCount} items`)
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
|
||||||
if (this.state.expanded) {
|
if (data.expanded) {
|
||||||
const childs = this.state.expanded && Object.keys(value).map(f => {
|
const childs = data.childs.map(child => {
|
||||||
return h(JSONNode, {
|
return h(JSONNode, {
|
||||||
parent: this,
|
data: child,
|
||||||
field: f,
|
options,
|
||||||
value: value[f],
|
onChangeValue,
|
||||||
onChangeValue,
|
onChangeProperty,
|
||||||
onChangeField
|
onExpand
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
contents.push(h('ul', {class: 'jsoneditor-list'}, childs))
|
contents.push(h('ul', {class: 'jsoneditor-list'}, childs))
|
||||||
}
|
}
|
||||||
|
@ -60,27 +55,28 @@ export default class JSONNode extends Component {
|
||||||
return h('li', {}, contents)
|
return h('li', {}, contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJSONArray ({parent, index, field, value, onChangeValue, onChangeField}) {
|
renderJSONArray ({data, index, options, onChangeValue, onChangeProperty, onExpand}) {
|
||||||
const childCount = value.length
|
const childCount = data.childs.length
|
||||||
const contents = [
|
const contents = [
|
||||||
h('div', {class: 'jsoneditor-node jsoneditor-array'}, [
|
h('div', {class: 'jsoneditor-node jsoneditor-array'}, [
|
||||||
this.renderExpandButton(),
|
this.renderExpandButton(),
|
||||||
this.renderField(parent, index, field, value),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
this.renderReadonly(`[${childCount}]`, `Array containing ${childCount} items`)
|
this.renderReadonly(`[${childCount}]`, `Array containing ${childCount} items`)
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
|
||||||
if (this.state.expanded) {
|
if (data.expanded) {
|
||||||
const childs = this.state.expanded && value.map((v, i) => {
|
const childs = data.childs.map((child, index) => {
|
||||||
return h(JSONNode, {
|
return h(JSONNode, {
|
||||||
parent: this,
|
data: child,
|
||||||
index: i,
|
index,
|
||||||
value: v,
|
options,
|
||||||
onChangeValue,
|
onChangeValue,
|
||||||
onChangeField
|
onChangeProperty,
|
||||||
})
|
onExpand
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
contents.push(h('ul', {class: 'jsoneditor-list'}, childs))
|
contents.push(h('ul', {class: 'jsoneditor-list'}, childs))
|
||||||
}
|
}
|
||||||
|
@ -88,13 +84,13 @@ export default class JSONNode extends Component {
|
||||||
return h('li', {}, contents)
|
return h('li', {}, contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJSONValue ({parent, index, field, value}) {
|
renderJSONValue ({data, index, options}) {
|
||||||
return h('li', {}, [
|
return h('li', {}, [
|
||||||
h('div', {class: 'jsoneditor-node'}, [
|
h('div', {class: 'jsoneditor-node'}, [
|
||||||
h('div', {class: 'jsoneditor-button-placeholder'}),
|
h('div', {class: 'jsoneditor-button-placeholder'}),
|
||||||
this.renderField(parent, index, field, value),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
this.renderValue(this.state.value)
|
this.renderValue(data.value)
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -103,22 +99,31 @@ export default class JSONNode extends Component {
|
||||||
return h('div', {class: 'jsoneditor-readonly', contentEditable: false, title}, text)
|
return h('div', {class: 'jsoneditor-readonly', contentEditable: false, title}, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderField (parent, index, field, value) {
|
renderProperty (data, index, options) {
|
||||||
const readonly = !parent || index !== undefined
|
const property = last(data.path)
|
||||||
const content = !parent
|
const isProperty = typeof property === 'string'
|
||||||
? valueType(value) // render 'object' or 'array', or 'number' as field
|
const content = isProperty
|
||||||
|
? escapeHTML(property) // render the property name
|
||||||
: index !== undefined
|
: index !== undefined
|
||||||
? index // render the array index of the item
|
? index // render the array index of the item
|
||||||
: escapeHTML(field) // render the property name
|
: JSONNode._rootName(data, options)
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
class: 'jsoneditor-field' + (readonly ? ' jsoneditor-readonly' : ''),
|
class: 'jsoneditor-property' + (isProperty ? '' : ' jsoneditor-readonly'),
|
||||||
contentEditable: !readonly,
|
contentEditable: isProperty,
|
||||||
spellCheck: 'false',
|
spellCheck: 'false',
|
||||||
onBlur: this.handleChangeField
|
onInput: this.handleChangeProperty
|
||||||
}, content)
|
}, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _rootName (data, options) {
|
||||||
|
return typeof options.name === 'string'
|
||||||
|
? options.name
|
||||||
|
: (data.type === 'object' || data.type === 'array')
|
||||||
|
? data.type
|
||||||
|
: valueType(data.value)
|
||||||
|
}
|
||||||
|
|
||||||
renderSeparator() {
|
renderSeparator() {
|
||||||
return h('div', {class: 'jsoneditor-separator'}, ':')
|
return h('div', {class: 'jsoneditor-separator'}, ':')
|
||||||
}
|
}
|
||||||
|
@ -133,7 +138,6 @@ export default class JSONNode extends Component {
|
||||||
contentEditable: true,
|
contentEditable: true,
|
||||||
spellCheck: 'false',
|
spellCheck: 'false',
|
||||||
onInput: this.handleChangeValue,
|
onInput: this.handleChangeValue,
|
||||||
onBlur: this.handleBlurValue,
|
|
||||||
onClick: this.handleClickValue,
|
onClick: this.handleClickValue,
|
||||||
onKeyDown: this.handleKeyDownValue,
|
onKeyDown: this.handleKeyDownValue,
|
||||||
title: _isUrl ? 'Ctrl+Click or ctrl+Enter to open url' : null
|
title: _isUrl ? 'Ctrl+Click or ctrl+Enter to open url' : null
|
||||||
|
@ -141,43 +145,28 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderExpandButton () {
|
renderExpandButton () {
|
||||||
const className = `jsoneditor-button jsoneditor-${this.state.expanded ? 'expanded' : 'collapsed'}`
|
const className = `jsoneditor-button jsoneditor-${this.props.data.expanded ? 'expanded' : 'collapsed'}`
|
||||||
return h('div', {class: 'jsoneditor-button-container'},
|
return h('div', {class: 'jsoneditor-button-container'},
|
||||||
h('button', {class: className, onClick: this.handleExpand})
|
h('button', {class: className, onClick: this.handleExpand})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
return Object.keys(nextProps).some(prop => this.props[prop] !== nextProps[prop]) ||
|
return Object.keys(nextProps).some(prop => this.props[prop] !== nextProps[prop])
|
||||||
(this.state && Object.keys(nextState).some(prop => this.state[prop] !== nextState[prop]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
handleChangeProperty (event) {
|
||||||
this.setState({
|
const property = unescapeHTML(getInnerText(event.target))
|
||||||
value: nextProps.value
|
const oldPath = this.props.data.path
|
||||||
})
|
const newPath = oldPath.slice(0, oldPath.length - 1).concat(property)
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeField (event) {
|
this.props.onChangeProperty(oldPath, newPath)
|
||||||
const path = this.props.parent.getPath()
|
|
||||||
const newField = unescapeHTML(getInnerText(event.target))
|
|
||||||
const oldField = this.props.field
|
|
||||||
if (newField !== oldField) {
|
|
||||||
this.props.onChangeField(path, oldField, newField)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBlurValue (event) {
|
|
||||||
const path = this.getPath()
|
|
||||||
if (this.state.value !== this.props.value) {
|
|
||||||
this.props.onChangeValue(path, this.state.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeValue (event) {
|
handleChangeValue (event) {
|
||||||
this.setState({
|
const value = this._getValueFromEvent(event)
|
||||||
value: this._getValueFromEvent(event)
|
|
||||||
})
|
this.props.onChangeValue(this.props.data.path, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickValue (event) {
|
handleClickValue (event) {
|
||||||
|
@ -193,9 +182,7 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleExpand (event) {
|
handleExpand (event) {
|
||||||
this.setState({
|
this.props.onExpand(this.props.data.path, !this.props.data.expanded)
|
||||||
expanded: !this.state.expanded
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_openLinkIfUrl (event) {
|
_openLinkIfUrl (event) {
|
||||||
|
@ -212,19 +199,4 @@ export default class JSONNode extends Component {
|
||||||
_getValueFromEvent (event) {
|
_getValueFromEvent (event) {
|
||||||
return stringConvert(unescapeHTML(getInnerText(event.target)))
|
return stringConvert(unescapeHTML(getInnerText(event.target)))
|
||||||
}
|
}
|
||||||
|
|
||||||
getPath () {
|
|
||||||
const path = []
|
|
||||||
|
|
||||||
let node = this
|
|
||||||
while (node) {
|
|
||||||
path.unshift(node.props.field || node.props.index)
|
|
||||||
|
|
||||||
node = node.props.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
path.shift() // remove the root node again (null)
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
169
src/Main.js
169
src/Main.js
|
@ -1,6 +1,8 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
|
|
||||||
import { getIn, setIn, renameField } from './utils/objectUtils'
|
import { setIn } from './utils/objectUtils'
|
||||||
|
import { last } from './utils/arrayUtils'
|
||||||
|
import { isObject } from './utils/typeUtils'
|
||||||
import JSONNode from './JSONNode'
|
import JSONNode from './JSONNode'
|
||||||
|
|
||||||
export default class Main extends Component {
|
export default class Main extends Component {
|
||||||
|
@ -8,50 +10,173 @@ export default class Main extends Component {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
json: props.json || {}
|
options: Object.assign({
|
||||||
|
name: null,
|
||||||
|
expand: Main.expand
|
||||||
|
}, props.options || {}),
|
||||||
|
|
||||||
|
data: {
|
||||||
|
type: 'object',
|
||||||
|
expanded: true,
|
||||||
|
path: [],
|
||||||
|
childs: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onChangeValue = this.onChangeValue.bind(this)
|
this._onExpand = this._onExpand.bind(this)
|
||||||
this.onChangeField = this.onChangeField.bind(this)
|
this._onChangeValue = this._onChangeValue.bind(this)
|
||||||
|
this._onChangeProperty = this._onChangeProperty.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
render(props, state) {
|
render() {
|
||||||
return h('div', {class: 'jsoneditor', onInput: this.onInput}, [
|
return h('div', {class: 'jsoneditor'}, [
|
||||||
h('ul', {class: 'jsoneditor-list'}, [
|
h('ul', {class: 'jsoneditor-list'}, [
|
||||||
h(JSONNode, {
|
h(JSONNode, {
|
||||||
parent: null,
|
data: this.state.data,
|
||||||
field: null,
|
options: this.state.options,
|
||||||
value: state.json,
|
onChangeProperty: this._onChangeProperty,
|
||||||
onChangeField: this.onChangeField,
|
onChangeValue: this._onChangeValue,
|
||||||
onChangeValue: this.onChangeValue
|
onExpand: this._onExpand
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
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')
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
json: setIn(this.state.json, path, value)
|
data: setIn(this.state.data, modelPath, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeField (path, oldField, newField) {
|
_onChangeProperty (oldPath, newPath) {
|
||||||
console.log('onChangeField', path, newField, oldField)
|
console.log('_onChangeProperty', oldPath, newPath)
|
||||||
|
|
||||||
|
const modelPath = Main._pathToModelPath(this.state.data, oldPath).concat('path')
|
||||||
|
|
||||||
const oldObject = getIn(this.state.json, path)
|
|
||||||
const newObject = renameField(oldObject, oldField, newField)
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
json: setIn(this.state.json, path, newObject)
|
data: setIn(this.state.data, modelPath, newPath)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onExpand(path, expand) {
|
||||||
|
const modelPath = Main._pathToModelPath(this.state.data, path).concat('expanded')
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
data: setIn(this.state.data, modelPath, expand)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
get () {
|
get () {
|
||||||
return this.state.json
|
return Main._modelToJson(this.state.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
set (json) {
|
set (json) {
|
||||||
this.setState({json})
|
this.setState({
|
||||||
|
data: Main._jsonToModel([], json, this.state.options.expand)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default function to determine whether or not to expand a node initially
|
||||||
|
* @param {Array.<string | number>} path
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
static expand (path) {
|
||||||
|
return path.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a path of a JSON object into a path in the corresponding data model
|
||||||
|
* @param {Model} model
|
||||||
|
* @param {Array.<string | number>} path
|
||||||
|
* @return {Array.<string | number>} modelPath
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _pathToModelPath (model, path) {
|
||||||
|
if (path.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
let index
|
||||||
|
if (typeof path[0] === 'number') {
|
||||||
|
// index of an array
|
||||||
|
index = path[0]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// object property. find the index of this property
|
||||||
|
index = model.childs.findIndex(child => last(child.path) === path[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['childs', index]
|
||||||
|
.concat(Main._pathToModelPath(model.childs[index], path.slice(1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a JSON object into the internally used data model
|
||||||
|
* @param {Array.<string | number>} path
|
||||||
|
* @param {Object | Array | string | number | boolean | null} value
|
||||||
|
* @param {function(path: Array.<string>)} expand
|
||||||
|
* @return {Model}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _jsonToModel (path, 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isObject(value)) {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
expanded: expand(path),
|
||||||
|
path,
|
||||||
|
childs: Object.keys(value).map(prop => {
|
||||||
|
return Main._jsonToModel(path.concat(prop), value[prop], expand)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
type: 'auto',
|
||||||
|
path,
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the internal data model to a regular JSON object
|
||||||
|
* @param {Model} model
|
||||||
|
* @return {Object | Array | string | number | boolean | null} json
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _modelToJson (model) {
|
||||||
|
if (model.type === 'array') {
|
||||||
|
return model.childs.map(Main._modelToJson)
|
||||||
|
}
|
||||||
|
else if (model.type === 'object') {
|
||||||
|
const object = {}
|
||||||
|
|
||||||
|
model.childs.forEach(child => {
|
||||||
|
const prop = last(child.path)
|
||||||
|
object[prop] = Main._modelToJson(child)
|
||||||
|
})
|
||||||
|
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// type 'auto' or 'string'
|
||||||
|
return model.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
<script>
|
<script>
|
||||||
// create the editor
|
// create the editor
|
||||||
const container = document.getElementById('container');
|
const container = document.getElementById('container');
|
||||||
const options = {};
|
const options = {
|
||||||
|
name: 'myObject'
|
||||||
|
};
|
||||||
const editor = jsoneditor(container, options);
|
const editor = jsoneditor(container, options);
|
||||||
const json = {
|
const json = {
|
||||||
'array': [1, 2, 3],
|
'array': [1, 2, 3],
|
||||||
|
|
|
@ -4,11 +4,12 @@ import Main from './Main'
|
||||||
/**
|
/**
|
||||||
* Factory function to create a new JSONEditor
|
* Factory function to create a new JSONEditor
|
||||||
* @param container
|
* @param container
|
||||||
|
* @param {Options} options
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export default function jsoneditor (container) {
|
export default function jsoneditor (container, options) {
|
||||||
const elem = render(h(Main), container)
|
const elem = render(h(Main, {options}), container)
|
||||||
return elem._component
|
return elem._component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ ul.jsoneditor-list {
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-field,
|
.jsoneditor-property,
|
||||||
.jsoneditor-value,
|
.jsoneditor-value,
|
||||||
.jsoneditor-readonly,
|
.jsoneditor-readonly,
|
||||||
.jsoneditor-separator {
|
.jsoneditor-separator {
|
||||||
|
@ -42,7 +42,7 @@ ul.jsoneditor-list {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-field,
|
.jsoneditor-property,
|
||||||
.jsoneditor-value,
|
.jsoneditor-value,
|
||||||
.jsoneditor-readonly {
|
.jsoneditor-readonly {
|
||||||
min-width: 24px;
|
min-width: 24px;
|
||||||
|
@ -58,17 +58,17 @@ ul.jsoneditor-list {
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-field,
|
.jsoneditor-property,
|
||||||
.jsoneditor-value {
|
.jsoneditor-value {
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-field:focus,
|
.jsoneditor-property:focus,
|
||||||
.jsoneditor-value:focus {
|
.jsoneditor-value:focus {
|
||||||
box-shadow: 0 0 3px 1px #008fd5;
|
box-shadow: 0 0 3px 1px #008fd5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-field:hover,
|
.jsoneditor-property:hover,
|
||||||
.jsoneditor-value:hover {
|
.jsoneditor-value:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* type: string,
|
||||||
|
* expanded: boolean?,
|
||||||
|
* path: Array.<string | number>,
|
||||||
|
* value: *?,
|
||||||
|
* childs: Model[]?
|
||||||
|
* }} Model
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* name: string?
|
||||||
|
* expand: function?
|
||||||
|
* }} Options
|
||||||
|
*/
|
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Returns the last item of an array
|
||||||
|
* @param {Array} array
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export function last (array) {
|
||||||
|
return array[array.length - 1]
|
||||||
|
}
|
|
@ -79,30 +79,3 @@ export function setIn (object, path, value) {
|
||||||
|
|
||||||
return updated
|
return updated
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rename a field in an object without mutating the object itself.
|
|
||||||
* The order of the fields in the object is maintained.
|
|
||||||
* @param {Object} object
|
|
||||||
* @param {string} oldField
|
|
||||||
* @param {string} newField
|
|
||||||
* @return {Object} Returns a clone of the object where property `oldField` is
|
|
||||||
* renamed to `newField`
|
|
||||||
*/
|
|
||||||
export function renameField(object, oldField, newField) {
|
|
||||||
const renamed = {}
|
|
||||||
|
|
||||||
// important: maintain the order in which we add the properties to newValue,
|
|
||||||
// else the field will "jump" to another place
|
|
||||||
Object.keys(object).forEach(field => {
|
|
||||||
if (field === oldField) {
|
|
||||||
renamed[newField] = object[oldField]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
renamed[field] = object[field]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return renamed
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue