Keep expanded state with copy/paste

This commit is contained in:
jos 2017-12-29 21:36:55 +01:00
parent 9a37fe0451
commit 419bdc6307
5 changed files with 122 additions and 12 deletions

View File

@ -182,7 +182,7 @@ export function insertBefore (eson, path, values) { // TODO: find a better name
*
* @param {ESON} eson
* @param {Selection} selection
* @param {Array.<{name?: string, value: JSONType, type?: ESONType}>} values
* @param {Array.<{name?: string, value: JSON, state: Object}>} values
* @return {Array}
*/
export function replace (eson, selection, values) { // TODO: find a better name and define datastructure for values
@ -197,7 +197,7 @@ export function replace (eson, selection, values) { // TODO: find a better name
path: compileJSONPointer(rootPath.concat(minIndex + offset)),
value: entry.value,
meta: {
type: entry.type
state: entry.state
}
}))
@ -214,8 +214,8 @@ export function replace (eson, selection, values) { // TODO: find a better name
path: compileJSONPointer(rootPath.concat(newProp)),
value: entry.value,
meta: {
type: entry.type,
before
before,
state: entry.state
}
}
})

View File

@ -467,18 +467,67 @@ export function pathsFromSelection (eson, selection) {
* Get the contents of a list with paths
* @param {ESON} data
* @param {Path[]} paths
* @return {Array.<{name: string, value: JSON}>}
* @return {Array.<{name: string, value: JSON, state: Object}>}
*/
export function contentsFromPaths (data, paths) {
return paths.map(path => {
const esonValue = getIn(data, path)
return {
name: last(path),
value: esonToJson(getIn(data, path))
// FIXME: also store the type and expanded state
value: esonToJson(esonValue),
state: getEsonState(esonValue)
}
})
}
/**
* Get an object with paths and state (expanded, type) of an eson object
* @param {ESON} eson
* @return {Object.<key, Object>} An object with compiled JSON paths as key,
* And a META object as state
*/
export function getEsonState (eson) {
let state = {}
transform(eson, function (eson, path) {
let meta = {}
if (eson[META].expanded === true) {
meta.expanded = true
}
if (eson[META].type === 'string') {
meta.type = 'string'
}
if (!isEmpty(meta)) {
state[compileJSONPointer(path)] = meta
}
return eson
})
return state
}
/**
* Merge ESON meta data to an ESON object: expanded state, type
* @param {ESON} data
* @param {Object.<String, Object>} state
* @return {ESON}
*/
export function applyEsonState(data, state) {
let updatedData = data
for (let path in state) {
if (state.hasOwnProperty(path)) {
const metaPath = parseJSONPointer(path).concat(META)
updatedData = updateIn(updatedData, metaPath, function (meta) {
return Object.assign({}, meta, state[path])
})
}
}
return updatedData
}
/**
* Find the root path of a selection: the parent node shared by both start
* and end of the selection

View File

@ -10,7 +10,7 @@ import {
expand, expandOne, expandPath, applyErrors, search, nextSearchResult,
previousSearchResult,
applySelection, pathsFromSelection,
SELECTED, SELECTED_END
SELECTED, SELECTED_END, getEsonState
} from './eson'
import 'console.table'
import repeat from 'lodash/repeat'
@ -552,6 +552,32 @@ test('pathsFromSelection (after)', () => {
expect(pathsFromSelection(eson, selection)).toEqual([])
})
test('getEsonState', () => {
const eson = jsonToEson({
"obj": {
"arr": ["1",2, {"first":3,"last":4}]
},
"str": "hello world",
"nill": null,
"bool": false
})
eson.obj[META].expanded = true
eson.obj.arr[META].expanded = false
eson.obj.arr[0][META].type = 'string'
eson.obj.arr[2][META].expanded = true
const state = getEsonState(eson)
expect(state).toEqual({
'/obj': { expanded: true },
'/obj/arr/0': { type: 'string' },
'/obj/arr/2': { expanded: true },
})
})
// TODO: test applyEsonState
// helper function to print JSON in the console
function printJSON (json, message = null) {
if (message) {

View File

@ -10,7 +10,7 @@ import {
META,
jsonToEson, esonToJson, updatePaths,
parseJSONPointer, compileJSONPointer,
expandAll, pathExists, resolvePathIndex, createId
expandAll, pathExists, resolvePathIndex, createId, applyEsonState
} from './eson'
/**
@ -35,8 +35,10 @@ export function patchEson (eson, patch, expand = expandAll) {
switch (action.op) {
case 'add': {
const newValue = jsonToEson(action.value, path)
// FIXME: apply expanded state
let newValue = jsonToEson(action.value, path)
if (options && options.state) {
newValue = applyEsonState(newValue, options.state)
}
// FIXME: apply options.type
const result = add(updatedEson, path, newValue, options)
updatedEson = result.data

View File

@ -1,7 +1,7 @@
'use strict'
import { readFileSync } from 'fs'
import { META, jsonToEson, esonToJson } from './eson'
import { META, jsonToEson, esonToJson, expandOne } from './eson'
import { patchEson } from './patchEson'
import { assertDeepEqualEson } from './utils/assertDeepEqualEson'
@ -77,6 +77,39 @@ test('jsonpatch add: append to matrix', () => {
])
})
test('jsonpatch add: pass eson state', () => {
const json = {
a: 2
}
const patch = [
{
op: 'add',
path: '/b',
value: {c: {d: 3}},
meta: {
state: {
'': { expanded: true },
'/c/d': { expanded: true }
}
}
}
]
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
let expected = jsonToEson({
a: 2,
b: {c: {d: 3}}
})
expected = expandOne(expected, ['b'], true)
expected = expandOne(expected, ['b', 'c', 'd'], true)
assertDeepEqualEson(patchedData, expected)
})
test('jsonpatch remove', () => {
const json = {
arr: [1,2,3],