Created context menu button. Some refactoring
This commit is contained in:
parent
fda4f94655
commit
37ae2111ee
|
@ -38,6 +38,7 @@
|
||||||
"gulp-shell": "0.5.2",
|
"gulp-shell": "0.5.2",
|
||||||
"gulp-util": "3.0.7",
|
"gulp-util": "3.0.7",
|
||||||
"json-loader": "0.5.4",
|
"json-loader": "0.5.4",
|
||||||
|
"json-pointer": "0.5.0",
|
||||||
"mithril": "0.2.5",
|
"mithril": "0.2.5",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "2.4.5",
|
"mocha": "2.4.5",
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { h, Component } from 'preact'
|
||||||
|
|
||||||
|
export default class ContextMenu extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return h('div', {class: 'jsoneditor-contextmenu'}, 'context menu...')
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
import { h, Component } from 'preact'
|
import { h, Component } from 'preact'
|
||||||
|
|
||||||
|
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'
|
||||||
|
@ -13,6 +15,7 @@ export default class JSONNode extends Component {
|
||||||
this.handleClickValue = this.handleClickValue.bind(this)
|
this.handleClickValue = this.handleClickValue.bind(this)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
render (props) {
|
render (props) {
|
||||||
|
@ -27,13 +30,14 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJSONObject ({data, index, options, onChangeValue, onChangeProperty, onExpand}) {
|
renderJSONObject ({data, index, options, events}) {
|
||||||
const childCount = data.childs.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.renderContextMenuButton(),
|
||||||
this.renderProperty(data, index, options),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(), // TODO: remove separator for Object and Array (gives an issue in Preact)
|
||||||
this.renderReadonly(`{${childCount}}`, `Array containing ${childCount} items`)
|
this.renderReadonly(`{${childCount}}`, `Array containing ${childCount} items`)
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
@ -43,9 +47,7 @@ export default class JSONNode extends Component {
|
||||||
return h(JSONNode, {
|
return h(JSONNode, {
|
||||||
data: child,
|
data: child,
|
||||||
options,
|
options,
|
||||||
onChangeValue,
|
events
|
||||||
onChangeProperty,
|
|
||||||
onExpand
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -55,13 +57,14 @@ export default class JSONNode extends Component {
|
||||||
return h('li', {}, contents)
|
return h('li', {}, contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJSONArray ({data, index, options, onChangeValue, onChangeProperty, onExpand}) {
|
renderJSONArray ({data, index, options, events}) {
|
||||||
const childCount = data.childs.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.renderContextMenuButton(),
|
||||||
this.renderProperty(data, index, options),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(), // TODO: remove separator for Object and Array (gives an issue in Preact)
|
||||||
this.renderReadonly(`[${childCount}]`, `Array containing ${childCount} items`)
|
this.renderReadonly(`[${childCount}]`, `Array containing ${childCount} items`)
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
@ -72,9 +75,7 @@ export default class JSONNode extends Component {
|
||||||
data: child,
|
data: child,
|
||||||
index,
|
index,
|
||||||
options,
|
options,
|
||||||
onChangeValue,
|
events
|
||||||
onChangeProperty,
|
|
||||||
onExpand
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ export default class JSONNode extends Component {
|
||||||
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.renderContextMenuButton(),
|
||||||
this.renderProperty(data, index, options),
|
this.renderProperty(data, index, options),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
this.renderValue(data.value)
|
this.renderValue(data.value)
|
||||||
|
@ -116,14 +118,6 @@ export default class JSONNode extends Component {
|
||||||
}, 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'}, ':')
|
||||||
}
|
}
|
||||||
|
@ -151,22 +145,41 @@ export default class JSONNode extends Component {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderContextMenuButton () {
|
||||||
|
const childs = this.props.data.menu ? [
|
||||||
|
h(ContextMenu)
|
||||||
|
] : null
|
||||||
|
|
||||||
|
const className = `jsoneditor-button jsoneditor-contextmenu`
|
||||||
|
return h('div', {class: 'jsoneditor-button-container'},
|
||||||
|
h('button', {class: className, onClick: this.handleContextMenu}, childs)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
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])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _rootName (data, options) {
|
||||||
|
return typeof options.name === 'string'
|
||||||
|
? options.name
|
||||||
|
: (data.type === 'object' || data.type === 'array')
|
||||||
|
? data.type
|
||||||
|
: valueType(data.value)
|
||||||
|
}
|
||||||
|
|
||||||
handleChangeProperty (event) {
|
handleChangeProperty (event) {
|
||||||
const property = unescapeHTML(getInnerText(event.target))
|
const property = unescapeHTML(getInnerText(event.target))
|
||||||
const oldPath = this.props.data.path
|
const oldPath = this.props.data.path
|
||||||
const newPath = oldPath.slice(0, oldPath.length - 1).concat(property)
|
const newPath = oldPath.slice(0, oldPath.length - 1).concat(property)
|
||||||
|
|
||||||
this.props.onChangeProperty(oldPath, newPath)
|
this.props.events.onChangeProperty(oldPath, newPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeValue (event) {
|
handleChangeValue (event) {
|
||||||
const value = this._getValueFromEvent(event)
|
const value = this._getValueFromEvent(event)
|
||||||
|
|
||||||
this.props.onChangeValue(this.props.data.path, value)
|
this.props.events.onChangeValue(this.props.data.path, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickValue (event) {
|
handleClickValue (event) {
|
||||||
|
@ -182,7 +195,11 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleExpand (event) {
|
handleExpand (event) {
|
||||||
this.props.onExpand(this.props.data.path, !this.props.data.expanded)
|
this.props.events.onExpand(this.props.data.path, !this.props.data.expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleContextMenu (event) {
|
||||||
|
this.props.events.onContextMenu(this.props.data.path, !this.props.data.menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
_openLinkIfUrl (event) {
|
_openLinkIfUrl (event) {
|
||||||
|
|
33
src/Main.js
33
src/Main.js
|
@ -20,24 +20,25 @@ export default class Main extends Component {
|
||||||
expanded: true,
|
expanded: true,
|
||||||
path: [],
|
path: [],
|
||||||
childs: []
|
childs: []
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
this._onExpand = this._onExpand.bind(this)
|
events: {
|
||||||
this._onChangeValue = this._onChangeValue.bind(this)
|
onChangeProperty: this._onChangeProperty.bind(this),
|
||||||
this._onChangeProperty = this._onChangeProperty.bind(this)
|
onChangeValue: this._onChangeValue.bind(this),
|
||||||
|
onExpand: this._onExpand.bind(this),
|
||||||
|
onContextMenu: this._onContextMenu.bind(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
menu: null,
|
||||||
|
|
||||||
|
search: null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return h('div', {class: 'jsoneditor'}, [
|
return h('div', {class: 'jsoneditor'}, [
|
||||||
h('ul', {class: 'jsoneditor-list'}, [
|
h('ul', {class: 'jsoneditor-list'}, [
|
||||||
h(JSONNode, {
|
h(JSONNode, this.state)
|
||||||
data: this.state.data,
|
|
||||||
options: this.state.options,
|
|
||||||
onChangeProperty: this._onChangeProperty,
|
|
||||||
onChangeValue: this._onChangeValue,
|
|
||||||
onExpand: this._onExpand
|
|
||||||
})
|
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -70,6 +71,14 @@ export default class Main extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onContextMenu(path, visible) {
|
||||||
|
const modelPath = Main._pathToModelPath(this.state.data, path).concat('menu')
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
data: setIn(this.state.data, modelPath, visible)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
get () {
|
get () {
|
||||||
return Main._modelToJson(this.state.data)
|
return Main._modelToJson(this.state.data)
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
ul.jsoneditor-list {
|
ul.jsoneditor-list {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding-left: 24px;
|
padding-left: 20px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,7 @@ div.jsoneditor-value.jsoneditor-url {
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-button {
|
button.jsoneditor-button {
|
||||||
|
position: relative;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -155,3 +156,24 @@ button.jsoneditor-button.jsoneditor-collapsed {
|
||||||
button.jsoneditor-button.jsoneditor-expanded {
|
button.jsoneditor-button.jsoneditor-expanded {
|
||||||
background-position: -2px -74px;
|
background-position: -2px -74px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.jsoneditor-button.jsoneditor-contextmenu {
|
||||||
|
background-position: -50px -74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.jsoneditor-button.jsoneditor-contextmenu:hover,
|
||||||
|
button.jsoneditor-button.jsoneditor-contextmenu:focus,
|
||||||
|
button.jsoneditor-button.jsoneditor-contextmenu.jsoneditor-selected {
|
||||||
|
background-position: -50px -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.jsoneditor-contextmenu {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
background: white;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* type: string,
|
* type: string,
|
||||||
* expanded: boolean?,
|
* expanded: boolean?,
|
||||||
|
* menu: boolean?,
|
||||||
* path: Array.<string | number>,
|
* path: Array.<string | number>,
|
||||||
* value: *?,
|
* value: *?,
|
||||||
* childs: Model[]?
|
* childs: Model[]?
|
||||||
|
|
Loading…
Reference in New Issue