Created insert buttons

This commit is contained in:
jos 2018-01-10 12:47:49 +01:00
parent 14e6315159
commit 7cdfb44345
7 changed files with 471 additions and 466 deletions

View File

@ -9,7 +9,8 @@ import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
import { import {
compileJSONPointer, compileJSONPointer,
META, META,
SELECTED, SELECTED_START, SELECTED_END, SELECTED_AFTER, SELECTED_BEFORE, SELECTED_FIRST, SELECTED_LAST SELECTED, SELECTED_START, SELECTED_END, SELECTED_AFTER, SELECTED_BEFORE,
SELECTED_FIRST, SELECTED_LAST
} from '../eson' } from '../eson'
const MENU_ITEMS_OBJECT = [ const MENU_ITEMS_OBJECT = [
@ -108,9 +109,12 @@ export default class JSONNode extends PureComponent {
? [ ? [
this.renderTag(`${props.length} ${props.length === 1 ? 'prop' : 'props'}`, this.renderTag(`${props.length} ${props.length === 1 ? 'prop' : 'props'}`,
`Object containing ${props.length} ${props.length === 1 ? 'property' : 'properties'}`), `Object containing ${props.length} ${props.length === 1 ? 'property' : 'properties'}`),
this.renderDelimiter('}', 'jsoneditor-delimiter-start'), this.renderDelimiter('}', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed'),
this.renderInsertAfter()
] ]
: null, : [
this.renderInsertBefore()
],
this.renderError(meta.error) this.renderError(meta.error)
]) ])
@ -129,24 +133,27 @@ export default class JSONNode extends PureComponent {
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, propsChilds) childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, propsChilds)
} }
else { else {
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'},
this.renderAppend('(empty object)') this.renderAppend('(empty object)')
) )
} }
} }
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_OBJECT, meta.selected) const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_OBJECT, meta.selected)
const insertArea = this.renderInsertBeforeArea()
const nodeEnd = meta.expanded const nodeEnd = meta.expanded
? this.renderDelimiter('}', 'jsoneditor-delimiter-end') ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
this.renderDelimiter('}', 'jsoneditor-delimiter-end'),
this.renderInsertAfter()
])
: null : null
return h('div', { return h('div', {
'data-path': compileJSONPointer(meta.path), 'data-path': compileJSONPointer(meta.path),
'data-area': 'empty',
className: this.getContainerClassName(meta.selected, this.state.hover), className: this.getContainerClassName(meta.selected, this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
}, [nodeStart, floatingMenu, insertArea, childs, nodeEnd]) }, [floatingMenu, nodeStart, childs, nodeEnd])
} }
renderJSONArray () { renderJSONArray () {
@ -158,7 +165,6 @@ export default class JSONNode extends PureComponent {
className: 'jsoneditor-node jsoneditor-array' className: 'jsoneditor-node jsoneditor-array'
}, [ }, [
this.renderExpandButton(), this.renderExpandButton(),
// this.renderDelimiter('\u2611'),
this.renderProperty(), this.renderProperty(),
this.renderSeparator(), this.renderSeparator(),
this.renderDelimiter('[', 'jsoneditor-delimiter-start'), this.renderDelimiter('[', 'jsoneditor-delimiter-start'),
@ -166,9 +172,12 @@ export default class JSONNode extends PureComponent {
? [ ? [
this.renderTag(`${count} ${count === 1 ? 'item' : 'items'}`, this.renderTag(`${count} ${count === 1 ? 'item' : 'items'}`,
`Array containing ${count} item${count === 1 ? 'item' : 'items'}`), `Array containing ${count} item${count === 1 ? 'item' : 'items'}`),
this.renderDelimiter(']', 'jsoneditor-delimiter-start'), this.renderDelimiter(']', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed'),
this.renderInsertAfter(),
] ]
: null, : [
this.renderInsertBefore()
],
this.renderError(meta.error) this.renderError(meta.error)
]) ])
@ -186,24 +195,27 @@ export default class JSONNode extends PureComponent {
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, items) childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, items)
} }
else { else {
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, childs = h('div', {key: 'childs', className: 'jsoneditor-list', 'data-area': 'emptyBefore'},
this.renderAppend('(empty array)') this.renderAppend('(empty array)')
) )
} }
} }
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_ARRAY, meta.selected) const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_ARRAY, meta.selected)
const insertArea = this.renderInsertBeforeArea()
const nodeEnd = meta.expanded const nodeEnd = meta.expanded
? this.renderDelimiter(']', 'jsoneditor-delimiter-end') ? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
this.renderDelimiter(']', 'jsoneditor-delimiter-end'),
this.renderInsertAfter()
])
: null : null
return h('div', { return h('div', {
'data-path': compileJSONPointer(meta.path), 'data-path': compileJSONPointer(meta.path),
'data-area': 'empty',
className: this.getContainerClassName(meta.selected, this.state.hover), className: this.getContainerClassName(meta.selected, this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
}, [nodeStart, floatingMenu, insertArea, childs, nodeEnd]) }, [floatingMenu, nodeStart, childs, nodeEnd])
} }
renderJSONValue () { renderJSONValue () {
@ -214,38 +226,42 @@ export default class JSONNode extends PureComponent {
className: 'jsoneditor-node' className: 'jsoneditor-node'
}, [ }, [
this.renderPlaceholder(), this.renderPlaceholder(),
// this.renderDelimiter('\u2611'),
this.renderProperty(), this.renderProperty(),
this.renderSeparator(), this.renderSeparator(),
this.renderValue(meta.value, meta.searchValue, this.props.options), this.renderValue(meta.value, meta.searchValue, this.props.options),
// this.renderDelimiter('\u21B2'), this.renderInsertAfter(),
// this.renderDelimiter('\u23CE'),
this.renderError(meta.error) this.renderError(meta.error)
]) ])
const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_VALUE, meta.selected) const floatingMenu = this.renderFloatingMenu(MENU_ITEMS_VALUE, meta.selected)
const insertArea = this.renderInsertBeforeArea() // const insertArea = this.renderInsertBeforeArea()
return h('div', { return h('div', {
'data-path': compileJSONPointer(meta.path), 'data-path': compileJSONPointer(meta.path),
'data-area': 'empty',
className: this.getContainerClassName(meta.selected, this.state.hover), className: this.getContainerClassName(meta.selected, this.state.hover),
// onMouseOver: this.handleMouseOver, // onMouseOver: this.handleMouseOver,
// onMouseLeave: this.handleMouseLeave // onMouseLeave: this.handleMouseLeave
}, [node, floatingMenu, insertArea]) }, [node, floatingMenu])
} }
renderInsertBeforeArea () { renderInsertBefore () {
const floatingMenu = ((this.props.value[META].selected & SELECTED_BEFORE) !== 0)
? this.renderFloatingMenu(MENU_ITEMS_INSERT_BEFORE,
SELECTED + SELECTED_END + SELECTED_FIRST)
: null
return h('div', { return h('div', {
key: 'menu', key: 'insert',
className: 'jsoneditor-insert-area', className: 'jsoneditor-insert jsoneditor-insert-before',
title: 'Insert a new item or paste clipboard',
'data-area': 'before' 'data-area': 'before'
}, [floatingMenu]) })
}
renderInsertAfter () {
return h('div', {
key: 'insert',
className: 'jsoneditor-insert jsoneditor-insert-after',
title: 'Insert a new item or paste clipboard after this line',
'data-area': 'after'
})
} }
/** /**
@ -256,20 +272,30 @@ export default class JSONNode extends PureComponent {
renderAppend (text) { renderAppend (text) {
return h('div', { return h('div', {
'data-path': compileJSONPointer(this.props.value[META].path) + '/-', 'data-path': compileJSONPointer(this.props.value[META].path) + '/-',
'data-area': 'empty',
className: 'jsoneditor-node', className: 'jsoneditor-node',
onKeyDown: this.handleKeyDownAppend onKeyDown: this.handleKeyDownAppend
}, [ }, [
this.renderPlaceholder(), this.renderPlaceholder('before'),
this.renderReadonly(text) this.renderReadonly(text)
]) ])
} }
renderPlaceholder () { renderPlaceholder (dataArea = 'value') {
return h('div', {key: 'placeholder', className: 'jsoneditor-button-placeholder'}) return h('div', {
key: 'placeholder',
'data-area': dataArea,
className: 'jsoneditor-button-placeholder'
})
} }
renderReadonly (text, title = null) { renderReadonly (text, title = null, dataArea = 'before') {
return h('div', {key: 'readonly', className: 'jsoneditor-readonly', title}, text) return h('div', {
key: 'readonly',
'data-area': dataArea,
className: 'jsoneditor-readonly',
title
}, text)
} }
renderTag (text, title = null) { renderTag (text, title = null) {
@ -302,7 +328,6 @@ export default class JSONNode extends PureComponent {
if (editable) { if (editable) {
return [ return [
// this.renderDelimiter('"'),
h('div', { h('div', {
key: 'property', key: 'property',
className: 'jsoneditor-property' + emptyClassName + searchClassName, className: 'jsoneditor-property' + emptyClassName + searchClassName,
@ -311,7 +336,6 @@ export default class JSONNode extends PureComponent {
spellCheck: 'false', spellCheck: 'false',
onBlur: this.handleChangeProperty onBlur: this.handleChangeProperty
}, escapedPropName), }, escapedPropName),
// this.renderDelimiter('" '),
] ]
} }
else { else {
@ -329,11 +353,19 @@ export default class JSONNode extends PureComponent {
return null return null
} }
return h('div', {key: 'separator', className: 'jsoneditor-delimiter'}, ':') return h('div', {
key: 'separator',
className: 'jsoneditor-delimiter',
'data-area': 'value'
}, ':')
} }
renderDelimiter (text, className = '') { renderDelimiter (text, className = '') {
return h('div', {key: text, className: 'jsoneditor-delimiter ' + className}, text) return h('div', {
key: text,
'data-area': 'value',
className: 'jsoneditor-delimiter ' + className
}, text)
} }
renderValue (value, searchResult, options) { renderValue (value, searchResult, options) {
@ -387,19 +419,31 @@ export default class JSONNode extends PureComponent {
getContainerClassName (selected, hover) { getContainerClassName (selected, hover) {
let classNames = ['jsoneditor-node-container'] let classNames = ['jsoneditor-node-container']
if ((selected & SELECTED) !== 0) { classNames.push('jsoneditor-selected') } if ((selected & SELECTED_BEFORE) !== 0) {
if ((selected & SELECTED_START) !== 0) { classNames.push('jsoneditor-selected-start') } classNames.push('jsoneditor-selected-insert-before')
if ((selected & SELECTED_END) !== 0) { classNames.push('jsoneditor-selected-end') } }
if ((selected & SELECTED_FIRST) !== 0) { classNames.push('jsoneditor-selected-first') } else if ((selected & SELECTED_AFTER) !== 0) {
if ((selected & SELECTED_LAST) !== 0) { classNames.push('jsoneditor-selected-last') } classNames.push('jsoneditor-selected-insert-after')
if ((selected & SELECTED_BEFORE) !== 0) { classNames.push('jsoneditor-selected-insert-area-before') } }
if ((selected & SELECTED_AFTER) !== 0) { classNames.push('jsoneditor-selected-insert-area-after') } else {
if ((selected & SELECTED) !== 0) { classNames.push('jsoneditor-selected') }
if ((selected & SELECTED_START) !== 0) { classNames.push('jsoneditor-selected-start') }
if ((selected & SELECTED_END) !== 0) { classNames.push('jsoneditor-selected-end') }
if ((selected & SELECTED_FIRST) !== 0) { classNames.push('jsoneditor-selected-first') }
if ((selected & SELECTED_LAST) !== 0) { classNames.push('jsoneditor-selected-last') }
}
if ((hover & SELECTED) !== 0) { classNames.push('jsoneditor-hover') } if ((hover & SELECTED_BEFORE) !== 0) {
if ((hover & SELECTED_START) !== 0) { classNames.push('jsoneditor-hover-start') } classNames.push('jsoneditor-hover-insert-before')
if ((hover & SELECTED_END) !== 0) { classNames.push('jsoneditor-hover-end') } }
if ((hover & SELECTED_BEFORE) !== 0) { classNames.push('jsoneditor-hover-insert-area-before') } else if ((hover & SELECTED_AFTER) !== 0) {
if ((hover & SELECTED_AFTER) !== 0) { classNames.push('jsoneditor-hover-insert-area-after') } classNames.push('jsoneditor-hover-insert-after')
}
else {
if ((hover & SELECTED) !== 0) { classNames.push('jsoneditor-hover') }
if ((hover & SELECTED_START) !== 0) { classNames.push('jsoneditor-hover-start') }
if ((hover & SELECTED_END) !== 0) { classNames.push('jsoneditor-hover-end') }
}
return classNames.join(' ') return classNames.join(' ')
} }

View File

@ -695,6 +695,9 @@ export default class TreeMode extends PureComponent {
const clickedOnEmptySpace = (event.target.nodeName === 'DIV') && const clickedOnEmptySpace = (event.target.nodeName === 'DIV') &&
(event.target.contentEditable !== 'true') (event.target.contentEditable !== 'true')
// TODO: cleanup
// console.log('handleTouchStart', clickedOnEmptySpace && pointer, pointer && this.selectionFromESONPointer(pointer))
if (clickedOnEmptySpace && pointer) { if (clickedOnEmptySpace && pointer) {
this.setState({ selection: this.selectionFromESONPointer(pointer)}) this.setState({ selection: this.selectionFromESONPointer(pointer)})
} }
@ -707,9 +710,17 @@ export default class TreeMode extends PureComponent {
const selection = this.state.selection const selection = this.state.selection
const path = this.findDataPathFromElement(event.target.firstChild) const path = this.findDataPathFromElement(event.target.firstChild)
if (path && selection && !isEqual(path, selection.end)) { if (path && selection && !isEqual(path, selection.end)) {
// TODO: cleanup
// console.log('handlePan', {
// start: selection.start || selection.before || selection.after || selection.empty || selection.emptyBefore,
// end: path
// })
// FIXME: when selection.empty, start should be set to the next node
this.setState({ this.setState({
selection: { selection: {
start: selection.start || selection.before || selection.after, start: selection.start || selection.before || selection.after || selection.empty || selection.emptyBefore,
end: path end: path
} }
}) })
@ -767,6 +778,12 @@ export default class TreeMode extends PureComponent {
else if (pointer.area === 'before') { else if (pointer.area === 'before') {
return {before: pointer.path} return {before: pointer.path}
} }
else if (pointer.area === 'empty') {
return {empty: pointer.path}
}
else if (pointer.area === 'emptyBefore') {
return {emptyBefore: pointer.path}
}
else { else {
return {start: pointer.path, end: pointer.path} return {start: pointer.path, end: pointer.path}
} }

View File

@ -11,7 +11,7 @@
height="144" height="144"
id="svg4136" id="svg4136"
version="1.1" version="1.1"
inkscape:version="0.91 r" inkscape:version="0.91 r13725"
sodipodi:docname="jsoneditor-icons.svg"> sodipodi:docname="jsoneditor-icons.svg">
<title <title
id="title6512">JSON Editor Icons</title> id="title6512">JSON Editor Icons</title>
@ -39,16 +39,16 @@
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:window-width="1920" inkscape:window-width="1920"
inkscape:window-height="1028" inkscape:window-height="1027"
id="namedview4144" id="namedview4144"
showgrid="true" showgrid="true"
inkscape:zoom="4" inkscape:zoom="5.6568542"
inkscape:cx="97.217248" inkscape:cx="113.02949"
inkscape:cy="59.950227" inkscape:cy="98.794192"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg4136" inkscape:current-layer="g4394"
showguides="false" showguides="false"
borderlayer="false" borderlayer="false"
inkscape:showpageshadow="true" inkscape:showpageshadow="true"
@ -67,7 +67,7 @@
width="16" width="16"
height="16" height="16"
id="svg_1" id="svg_1"
style="fill:#1aae1c;fill-opacity:1;stroke:none;stroke-width:0" /> style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
<rect <rect
style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0" style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0"
x="28.000006" x="28.000006"
@ -890,4 +890,34 @@
id="path4300-6" id="path4300-6"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" /> sodipodi:nodetypes="cccc" />
<path
inkscape:connector-curvature="0"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
d="m 202.49999,52 0,2 -2.49997,0 3.99997,5 3.99997,-5 -2.49998,0 0,-2 -2.99999,0 z"
id="path3055-0-77-3" />
<path
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.96599996;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 196.98509,60.015 14.0298,-0.03"
id="path5244-5-0-5-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
id="path6191-6"
d="m 202.49999,68 0,-2 -2.49997,0 3.99997,-5 3.99997,5 -2.49998,0 0,2 -2.99999,0 z"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.96599996;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<rect
x="196.00005"
y="51.999992"
width="15.999891"
height="16"
id="rect4432-3-2"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0" />
<rect
style="opacity:1;fill:none;fill-opacity:0.8;stroke:#ffffff;stroke-width:1.71429074;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4283-1"
width="10.285709"
height="10.285709"
x="198.85715"
y="54.857143" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -168,6 +168,15 @@
display: inline-flex; display: inline-flex;
flex-direction: row; } flex-direction: row; }
.jsoneditor-node-end {
display: flex;
height: 20px; }
.jsoneditor-node-end .jsoneditor-button-container:hover {
visibility: visible; }
.jsoneditor-root > .jsoneditor-node-container > .jsoneditor-node-end > .jsoneditor-button-container {
display: none; }
.jsoneditor-node > div { .jsoneditor-node > div {
flex: 0 0 auto; } flex: 0 0 auto; }
@ -202,7 +211,8 @@ div.jsoneditor-list {
min-width: auto; } min-width: auto; }
.jsoneditor-button-container { .jsoneditor-button-container {
font-size: 0; } font-size: 0;
display: inline-block; }
.jsoneditor-property, .jsoneditor-property,
.jsoneditor-value { .jsoneditor-value {
@ -240,6 +250,8 @@ div.jsoneditor-list {
.jsoneditor-delimiter-end { .jsoneditor-delimiter-end {
padding-left: 5px; padding-left: 5px;
border-left: 20px solid transparent; } border-left: 20px solid transparent; }
.jsoneditor-delimiter-end.jsoneditor-delimiter-collapsed {
border-left: none; }
.jsoneditor-readonly:focus, .jsoneditor-readonly:focus,
.jsoneditor-readonly:hover { .jsoneditor-readonly:hover {
@ -355,193 +367,13 @@ button.jsoneditor-button.jsoneditor-actionmenu:focus,
button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible { button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible {
background-position: -50px -50px; } background-position: -50px -50px; }
/******************************* Action Menu **********************************/ /*********************************** Menu *************************************/
div.jsoneditor-actionmenu {
position: absolute;
box-sizing: border-box;
z-index: 99999;
top: 20px;
left: 18px;
/* 20px - 2px where 2px half the difference between 24x24 icons of the menu and the 20x20 icons of the editor */
background: white;
border: 1px solid #d3d3d3;
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); }
div.jsoneditor-actionmenu.jsoneditor-actionmenu-top {
top: auto;
bottom: 20px; }
div.jsoneditor-modemenu.jsoneditor-modemenu {
top: 26px;
left: 0; }
div.jsoneditor-menu-item {
line-height: 0;
font-size: 0; }
button.jsoneditor-menu-button {
width: 136px;
height: 24px;
padding: 0;
margin: 0;
line-height: 24px;
background: transparent;
border: transparent;
display: inline-block;
box-sizing: border-box;
cursor: pointer;
color: #4d4d4d;
font-size: 10pt;
font-family: arial, sans-serif;
text-align: left; }
button.jsoneditor-menu-button:hover,
button.jsoneditor-menu-button:focus {
color: #1A1A1A;
background-color: #f5f5f5;
outline: none; }
button.jsoneditor-menu-button.jsoneditor-selected {
color: white;
background-color: #ee422e; }
button.jsoneditor-menu-default {
width: 104px;
/* 136px - 32px */ }
button.jsoneditor-menu-expand {
width: 32px;
float: right;
border-left: 1px solid #e5e5e5; }
span.jsoneditor-icon {
float: left;
width: 24px;
height: 24px;
border: none;
padding: 0;
margin: 0;
background-image: url("img/jsoneditor-icons.svg"); }
span.jsoneditor-icon.jsoneditor-icon-expand {
float: right;
width: 24px;
margin: 0 4px;
background-position: 0 -72px !important;
opacity: 0.4; }
div.jsoneditor-menu-item button.jsoneditor-menu-button:hover span.jsoneditor-icon-expand,
div.jsoneditor-menu-item button:focus span.jsoneditor-icon-expand {
opacity: 1; }
span.jsoneditor-text {
display: inline-block;
line-height: 24px; }
div.jsoneditor-menu-separator {
height: 0;
border-top: 1px solid #e5e5e5;
padding-top: 5px;
margin-top: 5px; }
div.jsoneditor-menu-panel-right { div.jsoneditor-menu-panel-right {
float: right; float: right;
max-width: 100%; } max-width: 100%; }
button.jsoneditor-remove span.jsoneditor-icon { /******************************* Action Menu **********************************/
background-position: -24px -24px; } /******************************* Floating Menu **********************************/
button.jsoneditor-remove:hover span.jsoneditor-icon,
button.jsoneditor-remove:focus span.jsoneditor-icon {
background-position: -24px 0; }
button.jsoneditor-insert span.jsoneditor-icon {
background-position: 0 -24px; }
button.jsoneditor-insert:hover span.jsoneditor-icon,
button.jsoneditor-insert:focus span.jsoneditor-icon {
background-position: 0 0; }
button.jsoneditor-duplicate span.jsoneditor-icon {
background-position: -48px -24px; }
button.jsoneditor-duplicate:hover span.jsoneditor-icon,
button.jsoneditor-duplicate:focus span.jsoneditor-icon {
background-position: -48px 0; }
button.jsoneditor-sort-asc span.jsoneditor-icon {
background-position: -168px -24px; }
button.jsoneditor-sort-asc:hover span.jsoneditor-icon,
button.jsoneditor-sort-asc:focus span.jsoneditor-icon {
background-position: -168px 0; }
button.jsoneditor-sort-desc span.jsoneditor-icon {
background-position: -192px -24px; }
button.jsoneditor-sort-desc:hover span.jsoneditor-icon,
button.jsoneditor-sort-desc:focus span.jsoneditor-icon {
background-position: -192px 0; }
div.jsoneditor-submenu {
visibility: hidden;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
box-shadow: inset 0 10px 10px -10px rgba(128, 128, 128, 0.5), inset 0 -10px 10px -10px rgba(128, 128, 128, 0.5); }
div.jsoneditor-submenu.jsoneditor-expanded {
visibility: visible;
max-height: 104px;
/* 4 * 24px + 2 * 5px */
/* FIXME: shouldn't rely on max-height equal to 4 items, should be flexible */ }
div.jsoneditor-submenu.jsoneditor-collapsing {
visibility: visible;
max-height: 0; }
div.jsoneditor-submenu button {
padding-left: 24px; }
div.jsoneditor-submenu div.jsoneditor-menu-item:first-child {
margin-top: 5px; }
div.jsoneditor-submenu div.jsoneditor-menu-item:last-child {
margin-bottom: 5px; }
button.jsoneditor-type-string span.jsoneditor-icon {
background-position: -144px -24px; }
button.jsoneditor-type-string:hover span.jsoneditor-icon,
button.jsoneditor-type-string:focus span.jsoneditor-icon,
button.jsoneditor-type-string.jsoneditor-selected span.jsoneditor-icon {
background-position: -144px 0; }
button.jsoneditor-type-value span.jsoneditor-icon {
background-position: -120px -24px; }
button.jsoneditor-type-value:hover span.jsoneditor-icon,
button.jsoneditor-type-value:focus span.jsoneditor-icon,
button.jsoneditor-type-value.jsoneditor-selected span.jsoneditor-icon {
background-position: -120px 0; }
button.jsoneditor-type-Object span.jsoneditor-icon {
background-position: -72px -24px; }
button.jsoneditor-type-Object:hover span.jsoneditor-icon,
button.jsoneditor-type-Object:focus span.jsoneditor-icon,
button.jsoneditor-type-Object.jsoneditor-selected span.jsoneditor-icon {
background-position: -72px 0; }
button.jsoneditor-type-Array span.jsoneditor-icon {
background-position: -96px -24px; }
button.jsoneditor-type-Array:hover span.jsoneditor-icon,
button.jsoneditor-type-Array:focus span.jsoneditor-icon,
button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon {
background-position: -96px 0; }
/******************************* Floatting Menu **********************************/
div.jsoneditor-node-container { div.jsoneditor-node-container {
position: relative; position: relative;
transition: background-color 100ms ease-in; } transition: background-color 100ms ease-in; }
@ -568,6 +400,22 @@ div.jsoneditor-node-container {
border-left-color: #ffed99; } border-left-color: #ffed99; }
div.jsoneditor-node-container.jsoneditor-selected .jsoneditor-list { div.jsoneditor-node-container.jsoneditor-selected .jsoneditor-list {
border-left-color: #ffed99; } border-left-color: #ffed99; }
div.jsoneditor-node-container div.jsoneditor-insert {
width: 20px;
height: 20px; }
div.jsoneditor-node-container div.jsoneditor-insert:hover {
background: url("img/jsoneditor-icons.svg") -2px -26px; }
div.jsoneditor-node-container.jsoneditor-selected-insert-after {
border-bottom: 1px dashed #c0c0c0;
margin-bottom: -1px; }
div.jsoneditor-node-container.jsoneditor-selected-insert-after > .jsoneditor-node > .jsoneditor-insert-after,
div.jsoneditor-node-container.jsoneditor-selected-insert-after > .jsoneditor-node-end > .jsoneditor-insert-after {
background-image: url("img/jsoneditor-icons.svg");
background-position: -2px -2px !important; }
div.jsoneditor-node-container.jsoneditor-selected-insert-before > .jsoneditor-node > .jsoneditor-insert-before,
div.jsoneditor-node-container.jsoneditor-selected-insert-before > .jsoneditor-node-end > .jsoneditor-insert-before {
background-image: url("img/jsoneditor-icons.svg");
background-position: -2px -2px !important; }
div.jsoneditor-node-container.jsoneditor-hover > .jsoneditor-node > .jsoneditor-button-container, div.jsoneditor-node-container.jsoneditor-hover > .jsoneditor-node > .jsoneditor-button-container,
div.jsoneditor-node-container.jsoneditor-hover > .jsoneditor-node > .jsoneditor-button-placeholder { div.jsoneditor-node-container.jsoneditor-hover > .jsoneditor-node > .jsoneditor-button-placeholder {
background-color: #d3d3d3; } background-color: #d3d3d3; }

View File

@ -123,6 +123,23 @@ $insert-area-height: 6px;
flex-direction: row; flex-direction: row;
} }
.jsoneditor-node-end {
display: flex;
height: $line-height;
.jsoneditor-button-container {
//visibility: hidden; // FIXME
&:hover {
visibility: visible;
}
}
}
.jsoneditor-root > .jsoneditor-node-container > .jsoneditor-node-end > .jsoneditor-button-container {
display: none;
}
.jsoneditor-node > div { .jsoneditor-node > div {
flex: 0 0 auto; flex: 0 0 auto;
} }
@ -167,6 +184,7 @@ div.jsoneditor-list {
.jsoneditor-button-container { .jsoneditor-button-container {
font-size: 0; font-size: 0;
display: inline-block;
} }
.jsoneditor-property, .jsoneditor-property,
@ -218,6 +236,10 @@ div.jsoneditor-list {
.jsoneditor-delimiter-end { .jsoneditor-delimiter-end {
padding-left: $input-padding; padding-left: $input-padding;
border-left: $line-height solid transparent; border-left: $line-height solid transparent;
&.jsoneditor-delimiter-collapsed {
border-left: none;
}
} }
.jsoneditor-readonly:focus, .jsoneditor-readonly:focus,
@ -362,241 +384,239 @@ button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible {
background-position: -50px -50px; background-position: -50px -50px;
} }
/*********************************** Menu *************************************/
/******************************* Action Menu **********************************/
// TODO: move into a separate file like menu/Menu.less
div.jsoneditor-actionmenu {
position: absolute;
box-sizing: border-box;
z-index: 99999;
top: 20px;
left: 18px; /* 20px - 2px where 2px half the difference between 24x24 icons of the menu and the 20x20 icons of the editor */
background: white;
border: 1px solid #d3d3d3;
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
}
div.jsoneditor-actionmenu.jsoneditor-actionmenu-top {
top: auto;
bottom: 20px;
}
div.jsoneditor-modemenu.jsoneditor-modemenu {
top: 26px;
left: 0;
}
div.jsoneditor-menu-item {
line-height: 0;
font-size: 0;
}
button.jsoneditor-menu-button {
width: 136px;
height: 24px;
padding: 0;
margin: 0;
line-height: 24px;
background: transparent;
border: transparent;
display: inline-block;
box-sizing: border-box;
cursor: pointer;
color: #4d4d4d;
font-size: 10pt;
font-family: arial, sans-serif;
text-align: left;
}
button.jsoneditor-menu-button:hover,
button.jsoneditor-menu-button:focus {
color: $black;
background-color: #f5f5f5;
outline: none;
}
button.jsoneditor-menu-button.jsoneditor-selected {
color: white;
background-color: #ee422e;
}
button.jsoneditor-menu-default {
width: 104px; /* 136px - 32px */
}
button.jsoneditor-menu-expand {
width: 32px;
float: right;
border-left: 1px solid #e5e5e5;
}
span.jsoneditor-icon {
float: left;
width: 24px;
height: 24px;
border: none;
padding: 0;
margin: 0;
background-image: url('img/jsoneditor-icons.svg');
}
span.jsoneditor-icon.jsoneditor-icon-expand {
float: right;
width: 24px;
margin: 0 4px;
background-position: 0 -72px !important;
opacity: 0.4;
}
div.jsoneditor-menu-item button.jsoneditor-menu-button:hover span.jsoneditor-icon-expand,
div.jsoneditor-menu-item button:focus span.jsoneditor-icon-expand {
opacity: 1;
}
span.jsoneditor-text {
display: inline-block;
line-height: 24px;
}
div.jsoneditor-menu-separator {
height: 0;
border-top: 1px solid #e5e5e5;
padding-top: 5px;
margin-top: 5px;
}
div.jsoneditor-menu-panel-right { div.jsoneditor-menu-panel-right {
float: right; float: right;
max-width: 100%; max-width: 100%;
} }
button.jsoneditor-remove span.jsoneditor-icon { /******************************* Action Menu **********************************/
background-position: -24px -24px;
}
button.jsoneditor-remove:hover span.jsoneditor-icon,
button.jsoneditor-remove:focus span.jsoneditor-icon {
background-position: -24px 0;
}
button.jsoneditor-insert span.jsoneditor-icon { // TODO: cleanup old ActionMenu css
background-position: 0 -24px; //div.jsoneditor-actionmenu {
} // position: absolute;
button.jsoneditor-insert:hover span.jsoneditor-icon, // box-sizing: border-box;
button.jsoneditor-insert:focus span.jsoneditor-icon { // z-index: 99999;
background-position: 0 0; // top: 20px;
} // left: 18px; /* 20px - 2px where 2px half the difference between 24x24 icons of the menu and the 20x20 icons of the editor */
// background: white;
//
// border: 1px solid #d3d3d3;
// box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
//}
//
//div.jsoneditor-actionmenu.jsoneditor-actionmenu-top {
// top: auto;
// bottom: 20px;
//}
//
//div.jsoneditor-modemenu.jsoneditor-modemenu {
// top: 26px;
// left: 0;
//}
//
//div.jsoneditor-menu-item {
// line-height: 0;
// font-size: 0;
//}
//
//button.jsoneditor-menu-button {
// width: 136px;
// height: 24px;
// padding: 0;
// margin: 0;
// line-height: 24px;
//
// background: transparent;
// border: transparent;
// display: inline-block;
// box-sizing: border-box;
//
// cursor: pointer;
// color: #4d4d4d;
//
// font-size: 10pt;
// font-family: arial, sans-serif;
// text-align: left;
//}
//
//button.jsoneditor-menu-button:hover,
//button.jsoneditor-menu-button:focus {
// color: $black;
// background-color: #f5f5f5;
// outline: none;
//}
//
//button.jsoneditor-menu-button.jsoneditor-selected {
// color: white;
// background-color: #ee422e;
//}
//
//button.jsoneditor-menu-default {
// width: 104px; /* 136px - 32px */
//}
//
//button.jsoneditor-menu-expand {
// width: 32px;
// float: right;
// border-left: 1px solid #e5e5e5;
//}
//
//span.jsoneditor-icon {
// float: left;
// width: 24px;
// height: 24px;
// border: none;
// padding: 0;
// margin: 0;
// background-image: url('img/jsoneditor-icons.svg');
//}
//
//span.jsoneditor-icon.jsoneditor-icon-expand {
// float: right;
// width: 24px;
// margin: 0 4px;
//
// background-position: 0 -72px !important;
// opacity: 0.4;
//}
//
//div.jsoneditor-menu-item button.jsoneditor-menu-button:hover span.jsoneditor-icon-expand,
//div.jsoneditor-menu-item button:focus span.jsoneditor-icon-expand {
// opacity: 1;
//}
//
//span.jsoneditor-text {
// display: inline-block;
// line-height: 24px;
//}
//
//div.jsoneditor-menu-separator {
// height: 0;
// border-top: 1px solid #e5e5e5;
// padding-top: 5px;
// margin-top: 5px;
//}
//
//button.jsoneditor-remove span.jsoneditor-icon {
// background-position: -24px -24px;
//}
//button.jsoneditor-remove:hover span.jsoneditor-icon,
//button.jsoneditor-remove:focus span.jsoneditor-icon {
// background-position: -24px 0;
//}
//
//button.jsoneditor-insert span.jsoneditor-icon {
// background-position: 0 -24px;
//}
//button.jsoneditor-insert:hover span.jsoneditor-icon,
//button.jsoneditor-insert:focus span.jsoneditor-icon {
// background-position: 0 0;
//}
//
//button.jsoneditor-duplicate span.jsoneditor-icon {
// background-position: -48px -24px;
//}
//button.jsoneditor-duplicate:hover span.jsoneditor-icon,
//button.jsoneditor-duplicate:focus span.jsoneditor-icon {
// background-position: -48px 0;
//}
//
//button.jsoneditor-sort-asc span.jsoneditor-icon {
// background-position: -168px -24px;
//}
//button.jsoneditor-sort-asc:hover span.jsoneditor-icon,
//button.jsoneditor-sort-asc:focus span.jsoneditor-icon {
// background-position: -168px 0;
//}
//
//button.jsoneditor-sort-desc span.jsoneditor-icon {
// background-position: -192px -24px;
//}
//button.jsoneditor-sort-desc:hover span.jsoneditor-icon,
//button.jsoneditor-sort-desc:focus span.jsoneditor-icon {
// background-position: -192px 0;
//}
//
//div.jsoneditor-submenu {
// visibility: hidden;
// max-height: 0;
//
// overflow: hidden;
//
// transition: max-height 0.3s ease-out;
//
// box-shadow: inset 0 10px 10px -10px rgba(128, 128, 128, 0.5),
// inset 0 -10px 10px -10px rgba(128, 128, 128, 0.5)
//}
//
//div.jsoneditor-submenu.jsoneditor-expanded {
// visibility: visible;
// max-height: 104px; /* 4 * 24px + 2 * 5px */
// /* FIXME: shouldn't rely on max-height equal to 4 items, should be flexible */
//}
//
//div.jsoneditor-submenu.jsoneditor-collapsing {
// visibility: visible;
// max-height: 0;
//}
//
//div.jsoneditor-submenu button {
// padding-left: 24px;
//}
//
//div.jsoneditor-submenu div.jsoneditor-menu-item:first-child {
// margin-top: 5px;
//}
//
//div.jsoneditor-submenu div.jsoneditor-menu-item:last-child {
// margin-bottom: 5px;
//}
//
//button.jsoneditor-type-string span.jsoneditor-icon {
// background-position: -144px -24px;
//}
//button.jsoneditor-type-string:hover span.jsoneditor-icon,
//button.jsoneditor-type-string:focus span.jsoneditor-icon,
//button.jsoneditor-type-string.jsoneditor-selected span.jsoneditor-icon {
// background-position: -144px 0;
//}
//
//button.jsoneditor-type-value span.jsoneditor-icon {
// background-position: -120px -24px;
//}
//button.jsoneditor-type-value:hover span.jsoneditor-icon,
//button.jsoneditor-type-value:focus span.jsoneditor-icon,
//button.jsoneditor-type-value.jsoneditor-selected span.jsoneditor-icon {
// background-position: -120px 0;
//}
//
//button.jsoneditor-type-Object span.jsoneditor-icon {
// background-position: -72px -24px;
//}
//button.jsoneditor-type-Object:hover span.jsoneditor-icon,
//button.jsoneditor-type-Object:focus span.jsoneditor-icon,
//button.jsoneditor-type-Object.jsoneditor-selected span.jsoneditor-icon {
// background-position: -72px 0;
//}
//
//button.jsoneditor-type-Array span.jsoneditor-icon {
// background-position: -96px -24px;
//}
//button.jsoneditor-type-Array:hover span.jsoneditor-icon,
//button.jsoneditor-type-Array:focus span.jsoneditor-icon,
//button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon {
// background-position: -96px 0;
//}
button.jsoneditor-duplicate span.jsoneditor-icon { /******************************* Floating Menu **********************************/
background-position: -48px -24px;
}
button.jsoneditor-duplicate:hover span.jsoneditor-icon,
button.jsoneditor-duplicate:focus span.jsoneditor-icon {
background-position: -48px 0;
}
button.jsoneditor-sort-asc span.jsoneditor-icon {
background-position: -168px -24px;
}
button.jsoneditor-sort-asc:hover span.jsoneditor-icon,
button.jsoneditor-sort-asc:focus span.jsoneditor-icon {
background-position: -168px 0;
}
button.jsoneditor-sort-desc span.jsoneditor-icon {
background-position: -192px -24px;
}
button.jsoneditor-sort-desc:hover span.jsoneditor-icon,
button.jsoneditor-sort-desc:focus span.jsoneditor-icon {
background-position: -192px 0;
}
div.jsoneditor-submenu {
visibility: hidden;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
box-shadow: inset 0 10px 10px -10px rgba(128, 128, 128, 0.5),
inset 0 -10px 10px -10px rgba(128, 128, 128, 0.5)
}
div.jsoneditor-submenu.jsoneditor-expanded {
visibility: visible;
max-height: 104px; /* 4 * 24px + 2 * 5px */
/* FIXME: shouldn't rely on max-height equal to 4 items, should be flexible */
}
div.jsoneditor-submenu.jsoneditor-collapsing {
visibility: visible;
max-height: 0;
}
div.jsoneditor-submenu button {
padding-left: 24px;
}
div.jsoneditor-submenu div.jsoneditor-menu-item:first-child {
margin-top: 5px;
}
div.jsoneditor-submenu div.jsoneditor-menu-item:last-child {
margin-bottom: 5px;
}
button.jsoneditor-type-string span.jsoneditor-icon {
background-position: -144px -24px;
}
button.jsoneditor-type-string:hover span.jsoneditor-icon,
button.jsoneditor-type-string:focus span.jsoneditor-icon,
button.jsoneditor-type-string.jsoneditor-selected span.jsoneditor-icon {
background-position: -144px 0;
}
button.jsoneditor-type-value span.jsoneditor-icon {
background-position: -120px -24px;
}
button.jsoneditor-type-value:hover span.jsoneditor-icon,
button.jsoneditor-type-value:focus span.jsoneditor-icon,
button.jsoneditor-type-value.jsoneditor-selected span.jsoneditor-icon {
background-position: -120px 0;
}
button.jsoneditor-type-Object span.jsoneditor-icon {
background-position: -72px -24px;
}
button.jsoneditor-type-Object:hover span.jsoneditor-icon,
button.jsoneditor-type-Object:focus span.jsoneditor-icon,
button.jsoneditor-type-Object.jsoneditor-selected span.jsoneditor-icon {
background-position: -72px 0;
}
button.jsoneditor-type-Array span.jsoneditor-icon {
background-position: -96px -24px;
}
button.jsoneditor-type-Array:hover span.jsoneditor-icon,
button.jsoneditor-type-Array:focus span.jsoneditor-icon,
button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon {
background-position: -96px 0;
}
/******************************* Floatting Menu **********************************/
div.jsoneditor-node-container { div.jsoneditor-node-container {
position: relative; position: relative;
transition: background-color 100ms ease-in; transition: background-color 100ms ease-in;
// TODO: can the hover/select css be simplified? // TODO: cleanup insert-area css?
div.jsoneditor-insert-area { div.jsoneditor-insert-area {
//background: gray; //background: gray;
position: absolute; position: absolute;
@ -656,6 +676,34 @@ div.jsoneditor-node-container {
} }
} }
div.jsoneditor-insert {
width: $line-height;
height: $line-height;
&:hover {
background: url('img/jsoneditor-icons.svg') -2px -26px;
}
}
&.jsoneditor-selected-insert-after {
border-bottom: 1px dashed $light-gray;
margin-bottom: -1px;
> .jsoneditor-node > .jsoneditor-insert-after,
> .jsoneditor-node-end > .jsoneditor-insert-after {
background-image: url('img/jsoneditor-icons.svg');
background-position: -2px -2px !important;
}
}
&.jsoneditor-selected-insert-before {
> .jsoneditor-node > .jsoneditor-insert-before,
> .jsoneditor-node-end > .jsoneditor-insert-before {
background-image: url('img/jsoneditor-icons.svg');
background-position: -2px -2px !important;
}
}
&.jsoneditor-hover { &.jsoneditor-hover {
> .jsoneditor-node > .jsoneditor-button-container, > .jsoneditor-node > .jsoneditor-button-container,
> .jsoneditor-node > .jsoneditor-button-placeholder { > .jsoneditor-node > .jsoneditor-button-placeholder {

View File

@ -19,6 +19,8 @@ export const SELECTED_FIRST = 8
export const SELECTED_LAST = 16 export const SELECTED_LAST = 16
export const SELECTED_BEFORE = 32 export const SELECTED_BEFORE = 32
export const SELECTED_AFTER = 64 export const SELECTED_AFTER = 64
export const SELECTED_EMPTY = 128
export const SELECTED_EMPTY_BEFORE = 256
export const META = Symbol('meta') export const META = Symbol('meta')
@ -361,14 +363,24 @@ export function applySelection (eson, selection) {
} }
else if (selection.before) { else if (selection.before) {
const updatedEson = setIn(eson, selection.before.concat([META, 'selected']), const updatedEson = setIn(eson, selection.before.concat([META, 'selected']),
SELECTED + SELECTED_BEFORE) SELECTED_BEFORE)
return cleanupMetaData(updatedEson, 'selected', [selection.before]) return cleanupMetaData(updatedEson, 'selected', [selection.before])
} }
else if (selection.after) { else if (selection.after) {
const updatedEson = setIn(eson, selection.after.concat([META, 'selected']), const updatedEson = setIn(eson, selection.after.concat([META, 'selected']),
SELECTED + SELECTED_AFTER) SELECTED_AFTER)
return cleanupMetaData(updatedEson, 'selected', [selection.after]) return cleanupMetaData(updatedEson, 'selected', [selection.after])
} }
else if (selection.empty) {
const updatedEson = setIn(eson, selection.empty.concat([META, 'selected']),
SELECTED_EMPTY)
return cleanupMetaData(updatedEson, 'selected', [selection.empty])
}
else if (selection.emptyBefore) {
const updatedEson = setIn(eson, selection.emptyBefore.concat([META, 'selected']),
SELECTED_EMPTY_BEFORE)
return cleanupMetaData(updatedEson, 'selected', [selection.emptyBefore])
}
else { // selection.start and selection.end else { // selection.start and selection.end
// find the parent node shared by both start and end of the selection // find the parent node shared by both start and end of the selection
const rootPath = findRootPath(selection) const rootPath = findRootPath(selection)
@ -556,6 +568,12 @@ export function findRootPath(selection) {
else if (selection.after) { else if (selection.after) {
return initial(selection.after) return initial(selection.after)
} }
else if (selection.empty) {
return initial(selection.empty)
}
else if (selection.emptyBefore) {
return initial(selection.emptyBefore)
}
else { // selection.start and selection.end else { // selection.start and selection.end
const sharedPath = findSharedPath(selection.start, selection.end) const sharedPath = findSharedPath(selection.start, selection.end)

View File

@ -42,7 +42,7 @@
*/ */
/** /**
* @typedef {'value' | 'property'} ESONPointerArea * @typedef {'value' | 'property' | 'before' | 'after' | 'empty'} ESONPointerArea
*/ */
/** /**