Rendering more like JSON

This commit is contained in:
jos 2018-01-01 19:32:30 +01:00
parent d53e5360a3
commit 9eb944d926
3 changed files with 162 additions and 145 deletions

View File

@ -52,7 +52,6 @@ export default class JSONNode extends PureComponent {
static propTypes = {
prop: PropTypes.string, // in case of an object property
index: PropTypes.number, // in case of an array item
value: PropTypes.oneOfType([ PropTypes.object, PropTypes.array ]).isRequired,
emit: PropTypes.func.isRequired,
@ -60,7 +59,6 @@ export default class JSONNode extends PureComponent {
// options
options: PropTypes.shape({
name: PropTypes.string, // name of the root item
isPropertyEditable: PropTypes.func,
isValueEditable: PropTypes.func,
escapeUnicode: PropTypes.bool
@ -96,14 +94,22 @@ export default class JSONNode extends PureComponent {
renderJSONObject () {
const meta = this.props.value[META]
const props = meta.props
const node = h('div', {
const nodeStart = h('div', {
key: 'node',
onKeyDown: this.handleKeyDown,
className: 'jsoneditor-node jsoneditor-object'
}, [
this.renderExpandButton(),
// this.renderDelimiter('\u2610'),
this.renderProperty(),
this.renderReadonly(`{${props.length}}`, `Object containing ${props.length} items`),
this.renderSeparator(),
this.renderDelimiter('{', 'jsoneditor-delimiter-start'),
!meta.expanded
? [
this.renderTag(`${props.length} props`, `Object containing ${props.length} properties`),
this.renderDelimiter('}', 'jsoneditor-delimiter-start'),
]
: null,
this.renderError(meta.error)
])
@ -130,34 +136,45 @@ export default class JSONNode extends PureComponent {
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_OBJECT, meta.selected)
const insertArea = this.renderInsertBeforeArea()
const nodeEnd = meta.expanded
? this.renderDelimiter('}', 'jsoneditor-delimiter-end')
: null
return h('div', {
'data-path': compileJSONPointer(meta.path),
className: this.getContainerClassName(meta.selected, this.state.hover),
onMouseOver: this.handleMouseOver,
onMouseLeave: this.handleMouseLeave
}, [node, floatingMenu, insertArea, childs])
}, [nodeStart, floatingMenu, insertArea, childs, nodeEnd])
}
renderJSONArray () {
const meta = this.props.value[META]
const node = h('div', {
const count = this.props.value.length
const nodeStart = h('div', {
key: 'node',
onKeyDown: this.handleKeyDown,
className: 'jsoneditor-node jsoneditor-array'
}, [
this.renderExpandButton(),
// this.renderDelimiter('\u2611'),
this.renderProperty(),
this.renderReadonly(`[${this.props.value.length}]`, `Array containing ${this.props.value.length} items`),
this.renderSeparator(),
this.renderDelimiter('[', 'jsoneditor-delimiter-start'),
!meta.expanded
? [
this.renderTag(`${count} items`, `Array containing ${count} items`),
this.renderDelimiter(']', 'jsoneditor-delimiter-start'),
]
: null,
this.renderError(meta.error)
])
let childs
if (meta.expanded) {
if (this.props.value.length > 0) {
const items = this.props.value.map((item, index) => h(this.constructor, {
if (count > 0) {
const items = this.props.value.map(item => h(this.constructor, {
key : item[META].id,
index,
value: item,
options: this.props.options,
emit: this.props.emit,
@ -175,13 +192,16 @@ export default class JSONNode extends PureComponent {
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_ARRAY, meta.selected)
const insertArea = this.renderInsertBeforeArea()
const nodeEnd = meta.expanded
? this.renderDelimiter(']', 'jsoneditor-delimiter-end')
: null
return h('div', {
'data-path': compileJSONPointer(meta.path),
className: this.getContainerClassName(meta.selected, this.state.hover),
onMouseOver: this.handleMouseOver,
onMouseLeave: this.handleMouseLeave
}, [node, floatingMenu, insertArea, childs])
}, [nodeStart, floatingMenu, insertArea, childs, nodeEnd])
}
renderJSONValue () {
@ -192,9 +212,12 @@ export default class JSONNode extends PureComponent {
className: 'jsoneditor-node'
}, [
this.renderPlaceholder(),
// this.renderDelimiter('\u2611'),
this.renderProperty(),
this.renderSeparator(),
this.renderValue(meta.value, meta.searchValue, this.props.options),
// this.renderDelimiter('\u21B2'),
// this.renderDelimiter('\u23CE'),
this.renderError(meta.error)
])
@ -247,54 +270,73 @@ export default class JSONNode extends PureComponent {
return h('div', {key: 'readonly', className: 'jsoneditor-readonly', title}, text)
}
renderTag (text, title = null) {
return h('div', {
key: 'readonly',
className: 'jsoneditor-tag',
onClick: this.handleExpand,
title
}, text)
}
// TODO: simplify the method renderProperty
/**
* Render a property field of a JSONNode
*/
renderProperty () {
const isIndex = typeof this.props.index === 'number'
const isProp = typeof this.props.prop === 'string'
if (!isProp && !isIndex) {
// root node
const rootName = JSONNode.getRootName(this.props.value, this.props.options)
return h('div', {
key: 'property',
className: 'jsoneditor-property jsoneditor-readonly',
spellCheck: 'false',
onBlur: this.handleChangeProperty
}, rootName)
if (!isProp) {
return null
}
const editable = !isIndex && (!this.props.options.isPropertyEditable || this.props.options.isPropertyEditable(this.props.value[META].path))
const editable = !this.props.options.isPropertyEditable ||
this.props.options.isPropertyEditable(this.props.value[META].path)
const emptyClassName = (this.props.prop != null && this.props.prop.length === 0) ? ' jsoneditor-empty' : ''
const searchClassName = this.props.prop != null ? JSONNode.getSearchResultClass(this.props.value[META].searchProperty) : ''
const escapedPropName = this.props.prop != null ? escapeHTML(this.props.prop, this.props.options.escapeUnicode) : null
if (editable) {
return h('div', {
key: 'property',
className: 'jsoneditor-property' + emptyClassName + searchClassName,
contentEditable: 'true',
suppressContentEditableWarning: true,
spellCheck: 'false',
onBlur: this.handleChangeProperty
}, escapedPropName)
return [
// this.renderDelimiter('"'),
h('div', {
key: 'property',
className: 'jsoneditor-property' + emptyClassName + searchClassName,
contentEditable: 'true',
suppressContentEditableWarning: true,
spellCheck: 'false',
onBlur: this.handleChangeProperty
}, escapedPropName),
// this.renderDelimiter('" '),
]
}
else {
return h('div', {
key: 'property',
className: 'jsoneditor-property jsoneditor-readonly' + searchClassName,
spellCheck: 'false'
}, isIndex ? this.props.index : escapedPropName)
}, escapedPropName)
}
}
renderSeparator() {
return h('div', {key: 'separator', className: 'jsoneditor-separator'}, ':')
const isProp = typeof this.props.prop === 'string'
if (!isProp) {
return null
}
return h('div', {key: 'separator', className: 'jsoneditor-delimiter'}, ':')
}
renderComma() {
// TODO: don't render when it's the last item/prop
return h('div', {key: 'comma', className: 'jsoneditor-delimiter'}, ',')
}
renderDelimiter (text, className = '') {
return h('div', {key: text, className: 'jsoneditor-delimiter ' + className}, text)
}
renderValue (value, searchResult, options) {

View File

@ -179,26 +179,28 @@ div.jsoneditor-list {
/* no left padding for the root div element */
.jsoneditor-contents > div.jsoneditor-list {
padding-left: 2px;
padding-bottom: 24px; }
padding-left: 2px; }
.jsoneditor-property,
.jsoneditor-value,
.jsoneditor-readonly,
.jsoneditor-separator {
line-height: 20px;
.jsoneditor-delimiter {
line-height: 18px;
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
font-size: 10pt; }
.jsoneditor-property,
.jsoneditor-value,
.jsoneditor-readonly {
min-width: 24px;
min-width: 16px;
word-break: normal;
padding: 0 5px;
color: #1A1A1A;
outline: none; }
.jsoneditor-readonly {
min-width: auto; }
.jsoneditor-button-container {
font-size: 0; }
@ -227,24 +229,39 @@ div.jsoneditor-list {
.jsoneditor-mode-view .jsoneditor-value:hover {
background-color: inherit; }
.jsoneditor-separator {
color: #808080; }
.jsoneditor-delimiter,
.jsoneditor-readonly {
color: #808080; }
color: #9d9d9d; }
.jsoneditor-delimiter-start {
margin-left: 5px; }
.jsoneditor-delimiter-end {
margin-left: 25px; }
.jsoneditor-readonly:focus,
.jsoneditor-readonly:hover {
border-color: transparent;
background-color: inherit; }
.jsoneditor-tag {
color: white;
background: #c0c0c0;
border-radius: 2px;
padding: 0 4px;
margin-left: 5px;
margin-top: 2px;
height: 14px;
line-height: 14px;
font-size: 80%; }
.jsoneditor-value.jsoneditor-string {
color: #008000; }
.jsoneditor-value.jsoneditor-object,
.jsoneditor-value.jsoneditor-array {
min-width: 16px;
color: #808080; }
color: #9d9d9d; }
.jsoneditor-value.jsoneditor-number {
color: #ee422e; }
@ -536,46 +553,25 @@ div.jsoneditor-node-container {
div.jsoneditor-node-container div.jsoneditor-insert-area:after {
content: '';
position: absolute;
top: -7px;
top: -6px;
right: 0;
width: 60px;
height: 20px;
height: 18px;
background: inherit; }
div.jsoneditor-node-container.jsoneditor-selected {
background-color: #ffed99; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover {
background-color: #ffdb80; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after {
background-color: #ffed99; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
border-color: #e5e5e5;
background-color: #e5e5e5; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area-after.jsoneditor-selected-insert-area-before > div.jsoneditor-insert-area {
border-color: #ffdb80;
background-color: #ffdb80; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before {
background-color: inherit; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before.jsoneditor-hover {
background-color: #e5e5e5; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before.jsoneditor-hover.jsoneditor-hover-insert-area-after {
background-color: inherit; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-before > div.jsoneditor-insert-area {
border-color: #ffed99;
background-color: #ffed99; }
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover {
background-color: #ffdb80; }
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area-after {
background-color: inherit; }
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
border-color: #ffdb80;
background-color: #ffdb80; }
div.jsoneditor-node-container.jsoneditor-hover {
background-color: #e5e5e5; }
background-color: #d3d3d3; }
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area-after {
background-color: inherit; }
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area-after > div.jsoneditor-insert-area {
border-color: #e5e5e5;
background-color: #e5e5e5; }
border-color: #d3d3d3;
background-color: #d3d3d3; }
div.jsoneditor-node-container.jsoneditor-selected {
background-color: #ffed99; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-after {
background-color: inherit; }
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area-after > div.jsoneditor-insert-area {
border-color: #ffed99;
background-color: #ffed99; }
div.jsoneditor-node-container div.jsoneditor-floating-menu {
position: absolute;
bottom: 100%;

View File

@ -7,15 +7,16 @@ $contentsMinHeight: 150px;
$theme-color: #3883fa; // TODO: create a central file with the theme colors
$floating-menu-background: #4d4d4d;
$floating-menu-color: #fff;
// $selectedColor: #e5e5e5;
$selectedColor: #ffed99;
//$hoverColor: #f2f2f2;
$hoverColor: #e5e5e5;
$hoverColor: #d3d3d3;
$hoverAndSelectedColor: #ffdb80;
$gray: #9d9d9d;
$light-gray: #c0c0c0;
$input-padding: 5px;
// TODO: split this scss file into separate files per React component
$line-height: 20px;
$line-height: 18px;
$insert-area-height: 6px;
.jsoneditor {
@ -136,13 +137,12 @@ div.jsoneditor-list {
/* no left padding for the root div element */
.jsoneditor-contents > div.jsoneditor-list {
padding-left: 2px;
padding-bottom: 24px;
}
.jsoneditor-property,
.jsoneditor-value,
.jsoneditor-readonly,
.jsoneditor-separator {
.jsoneditor-delimiter {
line-height: $line-height;
font-family: $fontFamily;
@ -152,15 +152,19 @@ div.jsoneditor-list {
.jsoneditor-property,
.jsoneditor-value,
.jsoneditor-readonly {
min-width: 24px;
min-width: 16px;
word-break: normal;
padding: 0 5px;
padding: 0 $input-padding;
color: $black;
outline: none;
}
.jsoneditor-readonly {
min-width: auto;
}
.jsoneditor-button-container {
font-size: 0;
}
@ -201,12 +205,17 @@ div.jsoneditor-list {
}
.jsoneditor-separator {
color: #808080;
.jsoneditor-delimiter,
.jsoneditor-readonly {
color: $gray;
}
.jsoneditor-readonly {
color: #808080;
.jsoneditor-delimiter-start {
margin-left: $input-padding;
}
.jsoneditor-delimiter-end {
margin-left: $line-height + $input-padding + 2px;
}
.jsoneditor-readonly:focus,
@ -215,6 +224,18 @@ div.jsoneditor-list {
background-color: inherit;
}
.jsoneditor-tag {
color: white;
background: $light-gray;
border-radius: 2px;
padding: 0 4px;
margin-left: $input-padding;
margin-top: 2px;
height: 14px;
line-height: 14px;
font-size: 80%;
}
.jsoneditor-value.jsoneditor-string {
color: #008000;
@ -223,7 +244,7 @@ div.jsoneditor-list {
.jsoneditor-value.jsoneditor-object,
.jsoneditor-value.jsoneditor-array {
min-width: 16px;
color: #808080;
color: $gray;
}
.jsoneditor-value.jsoneditor-number {
@ -250,7 +271,7 @@ div.jsoneditor-value.jsoneditor-url {
div.jsoneditor-empty {
border: 1px dotted lightgray;
border-radius: 2px;
padding: 0 5px;
padding: 0 $input-padding;
line-height: 17px;
}
@ -609,61 +630,6 @@ div.jsoneditor-node-container {
}
}
&.jsoneditor-selected {
background-color: $selectedColor;
&.jsoneditor-hover {
background-color: $hoverAndSelectedColor;
&.jsoneditor-hover-insert-area-after {
background-color: $selectedColor;
> div.jsoneditor-insert-area {
border-color: $hoverColor;
background-color: $hoverColor;
}
&.jsoneditor-selected-insert-area-before {
> div.jsoneditor-insert-area {
border-color: $hoverAndSelectedColor;
background-color: $hoverAndSelectedColor;
}
}
}
}
&.jsoneditor-selected-insert-area-before {
background-color: inherit;
&.jsoneditor-hover {
background-color: $hoverColor;
&.jsoneditor-hover-insert-area-after {
background-color: inherit;
}
}
> div.jsoneditor-insert-area {
border-color: $selectedColor;
background-color: $selectedColor;
}
}
// hovering nested elements
div.jsoneditor-hover {
background-color: $hoverAndSelectedColor;
&.jsoneditor-hover-insert-area-after {
background-color: inherit;
> div.jsoneditor-insert-area {
border-color: $hoverAndSelectedColor;
background-color: $hoverAndSelectedColor;
}
}
}
}
&.jsoneditor-hover {
background-color: $hoverColor;
@ -677,6 +643,19 @@ div.jsoneditor-node-container {
}
}
&.jsoneditor-selected {
background-color: $selectedColor;
&.jsoneditor-selected-insert-area-after {
background-color: inherit;
> div.jsoneditor-insert-area {
border-color: $selectedColor;
background-color: $selectedColor;
}
}
}
div.jsoneditor-floating-menu {
position: absolute;
bottom: 100%;