diff --git a/src/actions.js b/src/actions.js
index cc3813f..be419a4 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -92,17 +92,18 @@ export function changeType (data, path, type) {
* and object property
*
* @param {ESON} data
- * @param {ESONSelection} selection
+ * @param {Selection} selection
* @return {Array}
*/
export function duplicate (data, selection) {
// console.log('duplicate', path)
+ if (!selection.start || !selection.end) {
+ return []
+ }
const rootPath = findRootPath(selection)
- const start = selection.start.path[rootPath.length]
- const end = selection.end.path[rootPath.length]
const root = getIn(data, toEsonPath(data, rootPath))
- const { maxIndex } = findSelectionIndices(root, start, end)
+ const { maxIndex } = findSelectionIndices(root, rootPath, selection)
const paths = pathsFromSelection(data, selection)
if (root.type === 'Array') {
@@ -113,7 +114,6 @@ export function duplicate (data, selection) {
}))
}
else { // object.type === 'Object'
- const { maxIndex } = findSelectionIndices(root, start, end)
const nextProp = root.props && root.props[maxIndex]
const before = nextProp ? nextProp.name : null
@@ -133,53 +133,6 @@ export function duplicate (data, selection) {
}
}
-/**
- * Create a JSONPatch for an insert action.
- *
- * This function needs the current data in order to be able to determine
- * a unique property name for the inserted node in case of duplicating
- * and object property
- *
- * @param {ESON} data
- * @param {Path} path
- * @param {ESONType} type
- * @return {Array}
- */
-export function insert (data, path, type) {
- // console.log('insert', path, type)
-
- const parentPath = path.slice(0, path.length - 1)
- const esonPath = toEsonPath(data, parentPath)
- const parent = getIn(data, esonPath)
- const value = createEntry(type)
-
- if (parent.type === 'Array') {
- const index = parseInt(path[path.length - 1]) + 1
- return [{
- op: 'add',
- path: compileJSONPointer(parentPath.concat(index)),
- value,
- jsoneditor: {
- type
- }
- }]
- }
- else { // object.type === 'Object'
- const prop = path[path.length - 1]
- const newProp = findUniqueName('', parent.props.map(p => p.name))
-
- return [{
- op: 'add',
- path: compileJSONPointer(parentPath.concat(newProp)),
- value,
- jsoneditor: {
- type,
- before: findNextProp(parent, prop)
- }
- }]
- }
-}
-
/**
* Create a JSONPatch for an insert action.
*
@@ -233,17 +186,14 @@ export function insertBefore (data, path, values) { // TODO: find a better name
* and object property
*
* @param {ESON} data
- * @param {ESONSelection} selection
+ * @param {Selection} selection
* @param {Array.<{name?: string, value: JSONType, type?: ESONType}>} values
* @return {Array}
*/
export function replace (data, selection, values) { // TODO: find a better name and define datastructure for values
-
const rootPath = findRootPath(selection)
- const start = selection.start.path[rootPath.length]
- const end = selection.end.path[rootPath.length]
const root = getIn(data, toEsonPath(data, rootPath))
- const { minIndex, maxIndex } = findSelectionIndices(root, start, end)
+ const { minIndex, maxIndex } = findSelectionIndices(root, rootPath, selection)
if (root.type === 'Array') {
const removeActions = removeAll(pathsFromSelection(data, selection))
diff --git a/src/components/JSONNode.js b/src/components/JSONNode.js
index a825ba3..c2389fb 100644
--- a/src/components/JSONNode.js
+++ b/src/components/JSONNode.js
@@ -16,15 +16,15 @@ import type { ESONObjectProperty, ESON, SearchResultStatus, Path } from '../type
const SELECTED_CLASS_NAMES = {
[SELECTED]: ' jsoneditor-selected',
[SELECTED_END]: ' jsoneditor-selected jsoneditor-selected-end',
- [SELECTED_AFTER]: ' jsoneditor-selected jsoneditor-selected-after',
- [SELECTED_BEFORE]: ' jsoneditor-selected jsoneditor-selected-before',
+ [SELECTED_AFTER]: ' jsoneditor-selected jsoneditor-selected-insert-area',
+ [SELECTED_BEFORE]: ' jsoneditor-selected jsoneditor-selected-insert-area',
}
const HOVERED_CLASS_NAMES = {
[SELECTED]: ' jsoneditor-hover',
[SELECTED_END]: ' jsoneditor-hover jsoneditor-hover-end',
- [SELECTED_AFTER]: ' jsoneditor-hover jsoneditor-hover-after',
- [SELECTED_BEFORE]: ' jsoneditor-hover jsoneditor-hover-before',
+ [SELECTED_AFTER]: ' jsoneditor-hover jsoneditor-hover-insert-area',
+ [SELECTED_BEFORE]: ' jsoneditor-hover jsoneditor-hover-insert-area',
}
export default class JSONNode extends PureComponent {
@@ -196,7 +196,7 @@ export default class JSONNode extends PureComponent {
])
: null
- const insertArea = this.renderInsertArea()
+ const insertArea = this.renderInsertBeforeArea()
return h('div', {
'data-path': compileJSONPointer(this.props.path),
@@ -206,8 +206,8 @@ export default class JSONNode extends PureComponent {
}, [node, floatingMenu, insertArea])
}
- renderInsertArea () {
- const floatingMenu = (this.props.data.selected === SELECTED_AFTER)
+ renderInsertBeforeArea () {
+ const floatingMenu = (this.props.data.selected === SELECTED_BEFORE)
? this.renderFloatingMenu([
{type: 'insertStructure'},
{type: 'insertValue'},
@@ -220,7 +220,7 @@ export default class JSONNode extends PureComponent {
return h('div', {
key: 'menu',
className: 'jsoneditor-insert-area',
- 'data-area': 'after'
+ 'data-area': 'before'
}, [floatingMenu])
}
diff --git a/src/components/TreeMode.js b/src/components/TreeMode.js
index 3e2ee21..1170428 100644
--- a/src/components/TreeMode.js
+++ b/src/components/TreeMode.js
@@ -37,7 +37,7 @@ import {
import { createFindKeyBinding } from '../utils/keyBindings'
import { KEY_BINDINGS } from '../constants'
-import type { ESON, ESONPatch, JSONPath, ESONSelection, ESONPointer } from '../types'
+import type { ESON, ESONPatch, JSONPath, Selection, ESONPointer } from '../types'
const AJV_OPTIONS = {
allErrors: true,
@@ -348,17 +348,21 @@ export default class TreeMode extends Component {
}
handleInsert = (path, type) => {
- this.handlePatch(insert(this.state.data, path, createEntry(type), type))
+ this.handlePatch(insertBefore(this.state.data, path, [{
+ type,
+ name: '',
+ value: createEntry(type)
+ }]))
this.setState({ selection : null }) // TODO: select the inserted entry
// apply focus to new node
- this.focusToNext(path)
+ this.focusToPrevious(path)
}
handleInsertStructure = (path) => {
// TODO: implement handleInsertStructure
- console.log('handleInsertStructure', path)
+ console.log('TODO: handleInsertStructure', path)
alert('not yet implemented...')
}
@@ -456,7 +460,7 @@ export default class TreeMode extends Component {
handleKeyDownDuplicate = (event) => {
const path = this.findDataPathFromElement(event.target)
if (path) {
- const selection = { start: {path}, end: {path} }
+ const selection = { start: path, end: path }
this.handlePatch(duplicate(this.state.data, selection))
// apply focus to the duplicated node
@@ -510,11 +514,10 @@ export default class TreeMode extends Component {
}
/**
- * Move focus to the next search result
+ * Move focus to the next node
* @param {Path} path
*/
focusToNext (path) {
- // apply focus to new element
setTimeout(() => {
const element = findNode(this.refs.contents, path)
if (element) {
@@ -523,12 +526,24 @@ export default class TreeMode extends Component {
})
}
+ /**
+ * Move focus to the previous node
+ * @param {Path} path
+ */
+ focusToPrevious (path) {
+ setTimeout(() => {
+ const element = findNode(this.refs.contents, path)
+ if (element) {
+ moveUp(element, 'property')
+ }
+ })
+ }
+
handleSort = (path, order = null) => {
this.handlePatch(sort(this.state.data, path, order))
}
- handleSelect = (selection: ESONSelection) => {
- console.log('handleSelect', selection)
+ handleSelect = (selection: Selection) => {
this.setState({ selection })
}
@@ -664,7 +679,7 @@ export default class TreeMode extends Component {
(event.target.contentEditable !== 'true')
if (clickedOnEmptySpace && pointer) {
- this.setState({ selection: {start: pointer, end: pointer}})
+ this.setState({ selection: this.selectionFromESONPointer(pointer)})
}
else {
this.setState({ selection: null })
@@ -672,12 +687,13 @@ export default class TreeMode extends Component {
}
handlePan = (event) => {
+ const selection = this.state.selection
const path = this.findDataPathFromElement(event.target.firstChild)
- if (path && this.state.selection && !isEqual(path, this.state.selection.end.path)) {
+ if (path && selection && !isEqual(path, selection.end)) {
this.setState({
selection: {
- start: this.state.selection.start,
- end: {path}
+ start: selection.start || selection.before || selection.after,
+ end: path
}
})
}
@@ -711,6 +727,18 @@ export default class TreeMode extends Component {
return path ? { path, area } : null
}
+ selectionFromESONPointer (pointer: ESONPointer) : Selection {
+ if (pointer.area === 'after') {
+ return {after: pointer.path}
+ }
+ else if (pointer.area === 'before') {
+ return {before: pointer.path}
+ }
+ else {
+ return {start: pointer.path, end: pointer.path}
+ }
+ }
+
/**
* Scroll the window vertically to the node with given path
* @param {Path} path
@@ -770,7 +798,6 @@ export default class TreeMode extends Component {
}
undo = () => {
- console.log('undo')
if (this.canUndo()) {
const history = this.state.history
const historyIndex = this.state.historyIndex
diff --git a/src/develop.html b/src/develop.html
index 8f1abbc..dc3a1da 100644
--- a/src/develop.html
+++ b/src/develop.html
@@ -12,6 +12,10 @@