diff --git a/src/eson.js b/src/eson.js index 19f56c2..998f765 100644 --- a/src/eson.js +++ b/src/eson.js @@ -324,42 +324,43 @@ export function applySelection (eson: ESON, selection: ESONSelection) { const rootEsonPath = toEsonPath(eson, rootPath) if (rootPath.length === selection.start.path.length || rootPath.length === selection.end.path.length) { - // select the root itself + // select a single node return setIn(eson, rootEsonPath.concat(['selected']), true) } else { // select multiple childs of an object or array return updateIn(eson, rootEsonPath, (root) => { - if (root.type === 'Object') { - const startIndex = findPropertyIndex(root, selection.start.path[rootPath.length]) - const endIndex = findPropertyIndex(root, selection.end.path[rootPath.length]) - const minIndex = Math.min(startIndex, endIndex) - const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself + const start = selection.start.path[rootPath.length] + const end = selection.end.path[rootPath.length] + const { minIndex, maxIndex } = findSelectionIndices(root, start, end) - const propsBefore = root.props.slice(0, minIndex) - const propsUpdated = root.props.slice(minIndex, maxIndex) - .map((prop, index) => setIn(prop, ['value', 'selected'], true)) - const propsAfter = root.props.slice(maxIndex) + const childsKey = (root.type === 'Object') ? 'props' : 'items' // property name of the array with props/items + const childsBefore = root[childsKey].slice(0, minIndex) + const childsUpdated = root[childsKey].slice(minIndex, maxIndex) + .map((child, index) => setIn(child, ['value', 'selected'], true)) + const childsAfter = root[childsKey].slice(maxIndex) - return setIn(root, ['props'], propsBefore.concat(propsUpdated, propsAfter)) - } - else if (root.type === 'Array') { - const startIndex = parseInt(selection.start.path[rootPath.length]) - const endIndex = parseInt(selection.end.path[rootPath.length]) - const minIndex = Math.min(startIndex, endIndex) - const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself - - const itemsBefore = root.items.slice(0, minIndex) - const itemsUpdated = root.items.slice(minIndex, maxIndex) - .map((item, index) => setIn(item, ['value', 'selected'], true)) - const itemsAfter = root.items.slice(maxIndex) - - return setIn(root, ['items'], itemsBefore.concat(itemsUpdated, itemsAfter)) - } + return setIn(root, [childsKey], childsBefore.concat(childsUpdated, childsAfter)) }) } } +/** + * 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. + */ +export function findSelectionIndices (root: ESON, start: string, end: string) : { minIndex: number, maxIndex: number } { + // if no object we assume it's an Array + const startIndex = root.type === 'Object' ? findPropertyIndex(root, start) : parseInt(start) + const endIndex = root.type === 'Object' ? findPropertyIndex(root, end) : parseInt(end) + + const minIndex = Math.min(startIndex, endIndex) + const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself + + return { minIndex, maxIndex } +} + /** * Find the common path of two paths. * For example findCommonRoot(['arr', '1', 'name'], ['arr', '1', 'address', 'contact']) returns ['arr', '1'] diff --git a/test/eson.test.js b/test/eson.test.js index 68bb7b1..1ae063e 100644 --- a/test/eson.test.js +++ b/test/eson.test.js @@ -1,11 +1,11 @@ import { readFileSync } from 'fs' import test from 'ava'; -import { setIn } from '../src/utils/immutabilityHelpers' +import { setIn, getIn } from '../src/utils/immutabilityHelpers' import { jsonToEson, esonToJson, toEsonPath, pathExists, transform, traverse, parseJSONPointer, compileJSONPointer, expand, addErrors, search, applySearchResults, nextSearchResult, previousSearchResult, - applySelection + applySelection, getSelection } from '../src/eson' const JSON1 = loadJSON('./resources/json1.json') @@ -288,22 +288,18 @@ test('selection (value)', t => { } const actual = applySelection(ESON1, selection) - const expected = setIn(ESON1, toEsonPath(ESON1, ['obj', 'arr', '2', 'first']).concat(['selected']), true) - t.deepEqual(actual, expected) }) -test('selection (single parent)', t => { +test('selection (node)', t => { const selection = { start: {path: ['obj', 'arr']}, end: {path: ['obj', 'arr']} } const actual = applySelection(ESON1, selection) - const expected = setIn(ESON1, toEsonPath(ESON1, ['obj', 'arr']).concat(['selected']), true) - t.deepEqual(actual, expected) })