diff --git a/src/jsoneditor/actions.js b/src/jsoneditor/actions.js index 6bb5b36..7912946 100644 --- a/src/jsoneditor/actions.js +++ b/src/jsoneditor/actions.js @@ -1,7 +1,8 @@ import last from 'lodash/last' import initial from 'lodash/initial' import isEmpty from 'lodash/isEmpty' -import { findRootPath, findSelectionIndices, pathsFromSelection } from './eson' +import first from 'lodash/first' +import { findRootPath, pathsFromSelection } from './eson' import { getIn } from './utils/immutabilityHelpers' import { findUniqueName } from './utils/stringUtils' import { isObject, stringConvert } from './utils/typeUtils' @@ -86,14 +87,16 @@ export function duplicate (json, selection) { const rootPath = findRootPath(selection) const root = getIn(json, rootPath) - const { maxIndex } = findSelectionIndices(root, rootPath, selection) const paths = pathsFromSelection(json, selection) if (Array.isArray(root)) { - return paths.map((path, offset) => ({ + const lastPath = last(paths) + const offset = lastPath ? (parseInt(last(lastPath), 10) + 1) : 0 + + return paths.map((path, index) => ({ op: 'copy', from: compileJSONPointer(path), - path: compileJSONPointer(rootPath.concat(maxIndex + offset)) + path: compileJSONPointer(rootPath.concat(index + offset)) })) } else { // 'object' @@ -221,13 +224,16 @@ export function insertInside (json, parentPath, values) { export function replace (json, selection, values) { // TODO: find a better name and define datastructure for values const rootPath = findRootPath(selection) const root = getIn(json, rootPath) - const { minIndex, maxIndex } = findSelectionIndices(root, rootPath, selection) if (Array.isArray(root)) { - const removeActions = removeAll(pathsFromSelection(json, selection)) - const insertActions = values.map((entry, offset) => ({ + const paths = pathsFromSelection(json, selection) + const firstPath = first(paths) + const offset = firstPath ? parseInt(last(firstPath), 10) : 0 + + const removeActions = removeAll(paths) + const insertActions = values.map((entry, index) => ({ op: 'add', - path: compileJSONPointer(rootPath.concat(minIndex + offset)), + path: compileJSONPointer(rootPath.concat(index + offset)), value: entry.value })) diff --git a/src/jsoneditor/eson.js b/src/jsoneditor/eson.js index 86169f7..fd722fb 100644 --- a/src/jsoneditor/eson.js +++ b/src/jsoneditor/eson.js @@ -413,33 +413,6 @@ export function applySelection (eson, selection) { } } -/** - * Find the min and max index of a start and end child. - * Start and end can be a property name in case of an Object, - * or a matrix index (string with a number) in case of an Array. - * - * @param {ESON} root - * @param {Path} rootPath - * @param {Selection} selection - * @return {{minIndex: number, maxIndex: number}} - */ -export function findSelectionIndices (root, rootPath, selection) { - const start = (selection.after || selection.inside || selection.start)[rootPath.length] - const end = (selection.after || selection.inside || selection.end)[rootPath.length] - - // if no object we assume it's an Array - // TODO: create a util function getSortedProps, cache results? - const rootIsObject = getType(root) === 'object' - const props = rootIsObject ? Object.keys(root).sort(naturalSort) : undefined - const startIndex = rootIsObject ? props.indexOf(start) : parseInt(start, 10) - const endIndex = rootIsObject ? props.indexOf(end) : parseInt(end, 10) - - const minIndex = Math.min(startIndex, endIndex) - const maxIndex = Math.max(startIndex, endIndex) + ((selection.after || selection.inside) ? 0 : 1) // include max index itself - - return { minIndex, maxIndex } -} - /** * Get the contents of a list with paths * @param {ESON} eson @@ -518,14 +491,27 @@ export function pathsFromSelection (eson, selection) { const rootPath = findRootPath(selection) const root = getIn(eson, rootPath) - const { minIndex, maxIndex } = findSelectionIndices(root, rootPath, selection) + const start = (selection.after || selection.inside || selection.start)[rootPath.length] + const end = (selection.after || selection.inside || selection.end)[rootPath.length] if (getType(root) === 'object') { - const props = Object.keys(root).sort(naturalSort) // TODO: create a util function getSortedProps + // TODO: create a util function getSortedProps, cache results? + const props = Object.keys(root).sort(naturalSort) + const startIndex = props.indexOf(start) + const endIndex = props.indexOf(end) + + const minIndex = Math.min(startIndex, endIndex) + const maxIndex = Math.max(startIndex, endIndex) + ((selection.after || selection.inside) ? 0 : 1) // include max index itself return times(maxIndex - minIndex, i => rootPath.concat(props[i + minIndex])) } else { // root[TYPE] === 'array' + const startIndex = parseInt(start, 10) + const endIndex = parseInt(end, 10) + + const minIndex = Math.min(startIndex, endIndex) + const maxIndex = Math.max(startIndex, endIndex) + ((selection.after || selection.inside) ? 0 : 1) // include max index itself + return times(maxIndex - minIndex, i => rootPath.concat(String(i + minIndex))) } } @@ -541,7 +527,7 @@ export function pathsFromSelection (eson, selection) { export function immutableESONPatch (eson, operations) { return immutableJSONPatch(eson, operations, { fromJSON: (value, previousEson) => syncEson(value, previousEson), - toJSON: (eson) => eson[VALUE], + toJSON: (eson) => eson.valueOf(), clone: (value) => setIn(value, [ID], createId()) }) }