Halfway implementing AppendContextMenu. Upgraded to preact v5.6.0
This commit is contained in:
parent
7f6e7459df
commit
9d61ce001a
|
@ -42,8 +42,7 @@
|
||||||
"mithril": "0.2.5",
|
"mithril": "0.2.5",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "2.4.5",
|
"mocha": "2.4.5",
|
||||||
"preact": "4.8.0",
|
"preact": "5.6.0",
|
||||||
"react-dev-server": "0.6.2",
|
|
||||||
"reify": "0.3.6",
|
"reify": "0.3.6",
|
||||||
"rollup": "0.34.1",
|
"rollup": "0.34.1",
|
||||||
"rollup-plugin-buble": "0.12.1",
|
"rollup-plugin-buble": "0.12.1",
|
||||||
|
|
104
src/JSONNode.js
104
src/JSONNode.js
|
@ -32,6 +32,7 @@ export default class JSONNode extends Component {
|
||||||
this.handleKeyDownValue = this.handleKeyDownValue.bind(this)
|
this.handleKeyDownValue = this.handleKeyDownValue.bind(this)
|
||||||
this.handleExpand = this.handleExpand.bind(this)
|
this.handleExpand = this.handleExpand.bind(this)
|
||||||
this.handleContextMenu = this.handleContextMenu.bind(this)
|
this.handleContextMenu = this.handleContextMenu.bind(this)
|
||||||
|
this.handleAppendContextMenu = this.handleAppendContextMenu.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
render (props) {
|
render (props) {
|
||||||
|
@ -67,6 +68,10 @@ export default class JSONNode extends Component {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (props.length === 0) {
|
||||||
|
props.push(this.renderAppend('(empty object)'))
|
||||||
|
}
|
||||||
|
|
||||||
contents.push(h('ul', {class: 'jsoneditor-list'}, props))
|
contents.push(h('ul', {class: 'jsoneditor-list'}, props))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +99,10 @@ export default class JSONNode extends Component {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (items.length === 0) {
|
||||||
|
items.push(this.renderAppend('(empty array)'))
|
||||||
|
}
|
||||||
|
|
||||||
contents.push(h('ul', {class: 'jsoneditor-list'}, items))
|
contents.push(h('ul', {class: 'jsoneditor-list'}, items))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +112,7 @@ export default class JSONNode extends Component {
|
||||||
renderJSONValue ({path, data, options}) {
|
renderJSONValue ({path, data, options}) {
|
||||||
return h('li', {}, [
|
return h('li', {}, [
|
||||||
h('div', {class: 'jsoneditor-node'}, [
|
h('div', {class: 'jsoneditor-node'}, [
|
||||||
h('div', {class: 'jsoneditor-button-placeholder', contentEditable: 'false'}),
|
this.renderPlaceholder(),
|
||||||
this.renderContextMenuButton(),
|
this.renderContextMenuButton(),
|
||||||
this.renderProperty(path, data, options),
|
this.renderProperty(path, data, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
|
@ -112,8 +121,27 @@ export default class JSONNode extends Component {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render contents for an empty object or array
|
||||||
|
* @param {string} text
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
renderAppend (text) {
|
||||||
|
return h('li', {}, [
|
||||||
|
h('div', {class: 'jsoneditor-node'}, [
|
||||||
|
this.renderPlaceholder(),
|
||||||
|
this.renderAppendContextMenuButton(),
|
||||||
|
this.renderReadonly(text)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlaceholder () {
|
||||||
|
return h('div', {class: 'jsoneditor-button-placeholder'})
|
||||||
|
}
|
||||||
|
|
||||||
renderReadonly (text, title = null) {
|
renderReadonly (text, title = null) {
|
||||||
return h('div', {class: 'jsoneditor-readonly', contentEditable: 'false', title}, text)
|
return h('div', {class: 'jsoneditor-readonly', title}, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderProperty (path, data, options) {
|
renderProperty (path, data, options) {
|
||||||
|
@ -124,7 +152,6 @@ export default class JSONNode extends Component {
|
||||||
if (isIndex) { // array item
|
if (isIndex) { // array item
|
||||||
return h('div', {
|
return h('div', {
|
||||||
class: 'jsoneditor-property jsoneditor-readonly',
|
class: 'jsoneditor-property jsoneditor-readonly',
|
||||||
contentEditable: 'false',
|
|
||||||
spellCheck: 'false'
|
spellCheck: 'false'
|
||||||
}, prop)
|
}, prop)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +170,6 @@ export default class JSONNode extends Component {
|
||||||
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
class: 'jsoneditor-property jsoneditor-readonly',
|
class: 'jsoneditor-property jsoneditor-readonly',
|
||||||
contentEditable: 'false',
|
|
||||||
spellCheck: 'false',
|
spellCheck: 'false',
|
||||||
onInput: this.handleChangeProperty
|
onInput: this.handleChangeProperty
|
||||||
}, content)
|
}, content)
|
||||||
|
@ -151,7 +177,7 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeparator() {
|
renderSeparator() {
|
||||||
return h('div', {class: 'jsoneditor-separator', contentEditable: 'false'}, ':')
|
return h('div', {class: 'jsoneditor-separator'}, ':')
|
||||||
}
|
}
|
||||||
|
|
||||||
renderValue (value) {
|
renderValue (value) {
|
||||||
|
@ -172,7 +198,7 @@ export default class JSONNode extends Component {
|
||||||
|
|
||||||
renderExpandButton () {
|
renderExpandButton () {
|
||||||
const className = `jsoneditor-button jsoneditor-${this.props.data.expanded ? 'expanded' : 'collapsed'}`
|
const className = `jsoneditor-button jsoneditor-${this.props.data.expanded ? 'expanded' : 'collapsed'}`
|
||||||
return h('div', {class: 'jsoneditor-button-container', contentEditable: 'false'},
|
return h('div', {class: 'jsoneditor-button-container'},
|
||||||
h('button', {class: className, onClick: this.handleExpand})
|
h('button', {class: className, onClick: this.handleExpand})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +207,7 @@ export default class JSONNode extends Component {
|
||||||
const className = 'jsoneditor-button jsoneditor-contextmenu' +
|
const className = 'jsoneditor-button jsoneditor-contextmenu' +
|
||||||
(this.props.data.contextMenu ? ' jsoneditor-visible' : '')
|
(this.props.data.contextMenu ? ' jsoneditor-visible' : '')
|
||||||
|
|
||||||
return h('div', {class: 'jsoneditor-button-container', contentEditable: 'false'},
|
return h('div', {class: 'jsoneditor-button-container'},
|
||||||
this.props.data.contextMenu
|
this.props.data.contextMenu
|
||||||
? this.renderContextMenu(this.props.data.contextMenu)
|
? this.renderContextMenu(this.props.data.contextMenu)
|
||||||
: null,
|
: null,
|
||||||
|
@ -319,6 +345,64 @@ export default class JSONNode extends Component {
|
||||||
return h(ContextMenu, {anchor, root, items})
|
return h(ContextMenu, {anchor, root, items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderAppendContextMenuButton () {
|
||||||
|
const className = 'jsoneditor-button jsoneditor-contextmenu' +
|
||||||
|
(this.props.data.contextMenu ? ' jsoneditor-visible' : '')
|
||||||
|
|
||||||
|
// FIXME: show context menu, add right handlers
|
||||||
|
return h('div', {class: 'jsoneditor-button-container'},
|
||||||
|
this.props.data.contextMenu
|
||||||
|
? this.renderAppendContextMenu(this.props.data.contextMenu)
|
||||||
|
: null,
|
||||||
|
h('button', {class: className, onClick: this.handleAppendContextMenu})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAppendContextMenu ({anchor, root}) {
|
||||||
|
const path = this.props.path
|
||||||
|
const events = this.props.events
|
||||||
|
const items = [] // array with menu items
|
||||||
|
|
||||||
|
// create insert button
|
||||||
|
items.push({
|
||||||
|
text: 'Insert',
|
||||||
|
title: 'Insert a new item with type \'value\' after this item (Ctrl+Ins)',
|
||||||
|
submenuTitle: 'Select the type of the item to be inserted',
|
||||||
|
className: 'jsoneditor-insert',
|
||||||
|
click: () => events.onAppend(path, 'value'),
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
text: 'Value',
|
||||||
|
className: 'jsoneditor-type-value',
|
||||||
|
title: TYPE_TITLES.value,
|
||||||
|
click: () => events.onAppend(path, 'value')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Array',
|
||||||
|
className: 'jsoneditor-type-array',
|
||||||
|
title: TYPE_TITLES.array,
|
||||||
|
click: () => events.onAppend(path, 'array')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Object',
|
||||||
|
className: 'jsoneditor-type-object',
|
||||||
|
title: TYPE_TITLES.object,
|
||||||
|
click: () => events.onAppend(path, 'object')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'String',
|
||||||
|
className: 'jsoneditor-type-string',
|
||||||
|
title: TYPE_TITLES.string,
|
||||||
|
click: () => events.onAppend(path, 'string')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: implement a hook to adjust the context menu
|
||||||
|
|
||||||
|
return h(ContextMenu, {anchor, root, items})
|
||||||
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
// WARNING: we suppose that JSONNode is stateless, we don't check changes in the state, only in props
|
// WARNING: we suppose that JSONNode is stateless, we don't check changes in the state, only in props
|
||||||
return Object.keys(nextProps).some(prop => this.props[prop] !== nextProps[prop])
|
return Object.keys(nextProps).some(prop => this.props[prop] !== nextProps[prop])
|
||||||
|
@ -379,6 +463,12 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAppendContextMenu(event) {
|
||||||
|
event.stopPropagation() // stop propagation, because else Main.js will hide the context menu again
|
||||||
|
|
||||||
|
this.props.events.onAppend(this.props.path, 'value')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this JSONNode holds an URL as value, open this URL in a new browser tab
|
* When this JSONNode holds an URL as value, open this URL in a new browser tab
|
||||||
* @param event
|
* @param event
|
||||||
|
|
36
src/Main.js
36
src/Main.js
|
@ -29,6 +29,7 @@ export default class Main extends Component {
|
||||||
onChangeValue: this.handleChangeValue,
|
onChangeValue: this.handleChangeValue,
|
||||||
onChangeType: this.handleChangeType,
|
onChangeType: this.handleChangeType,
|
||||||
onInsert: this.handleInsert,
|
onInsert: this.handleInsert,
|
||||||
|
onAppend: this.handleAppend,
|
||||||
onDuplicate: this.handleDuplicate,
|
onDuplicate: this.handleDuplicate,
|
||||||
onRemove: this.handleRemove,
|
onRemove: this.handleRemove,
|
||||||
onSort: this.handleSort,
|
onSort: this.handleSort,
|
||||||
|
@ -132,6 +133,41 @@ export default class Main extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAppend (path, type) {
|
||||||
|
console.log('handleAppend', path, type)
|
||||||
|
|
||||||
|
this.handleHideContextMenu() // TODO: should be handled by the contextmenu itself
|
||||||
|
|
||||||
|
const dataPath = toDataPath(this.state.data, path)
|
||||||
|
const object = getIn(this.state.data, dataPath)
|
||||||
|
|
||||||
|
if (object.type === 'array') {
|
||||||
|
this.setState({
|
||||||
|
data: updateIn(this.state.data, dataPath.concat(['items']), (items) => {
|
||||||
|
const updatedItems = items.slice(0)
|
||||||
|
|
||||||
|
updatedItems.push(createDataEntry(type))
|
||||||
|
|
||||||
|
return updatedItems
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else { // object.type === 'object'
|
||||||
|
this.setState({
|
||||||
|
data: updateIn(this.state.data, dataPath.concat(['props']), (props) => {
|
||||||
|
const updatedProps = props.slice(0)
|
||||||
|
|
||||||
|
updatedProps.push({
|
||||||
|
name: '',
|
||||||
|
value: createDataEntry(type)
|
||||||
|
})
|
||||||
|
|
||||||
|
return updatedProps
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleDuplicate (path) {
|
handleDuplicate (path) {
|
||||||
console.log('handleDuplicate', path)
|
console.log('handleDuplicate', path)
|
||||||
|
|
||||||
|
|
|
@ -30,15 +30,19 @@
|
||||||
};
|
};
|
||||||
editor.set(json, {
|
editor.set(json, {
|
||||||
name: 'myObject',
|
name: 'myObject',
|
||||||
// expand: function (path) {
|
expand: function (path) {
|
||||||
// return true
|
return true
|
||||||
// }
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// set json
|
// set json
|
||||||
document.getElementById('setJSON').onclick = function () {
|
document.getElementById('setJSON').onclick = function () {
|
||||||
console.time('set')
|
console.time('set')
|
||||||
editor.set(largeJSON);
|
editor.set(largeJSON, {
|
||||||
|
expand: function (path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
});
|
||||||
console.timeEnd('set')
|
console.timeEnd('set')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue