Created context menu button. Some refactoring

This commit is contained in:
jos 2016-07-16 13:48:20 +02:00
parent fda4f94655
commit 37ae2111ee
6 changed files with 95 additions and 34 deletions

View File

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

11
src/ContextMenu.js Normal file
View File

@ -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...')
}
}

View File

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

View File

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

View File

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

View File

@ -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[]?