Implemented duplicate for multiple nodes

This commit is contained in:
jos 2017-11-08 15:41:40 +01:00
parent dd989f9a64
commit cb354f2331
3 changed files with 51 additions and 34 deletions

View File

@ -92,37 +92,44 @@ export function changeType (data, path, type) {
* and object property * and object property
* *
* @param {ESON} data * @param {ESON} data
* @param {Path} path * @param {ESONSelection} selection
* @return {Array} * @return {Array}
*/ */
export function duplicate (data, path) { export function duplicate (data, selection) {
// console.log('duplicate', path) // console.log('duplicate', path)
const parentPath = path.slice(0, path.length - 1) 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 paths = pathsFromSelection(data, selection)
const esonPath = toEsonPath(data, parentPath) if (root.type === 'Array') {
const parent = getIn(data, esonPath) return paths.map((path, offset) => ({
if (parent.type === 'Array') {
const index = parseInt(path[path.length - 1]) + 1
return [{
op: 'copy', op: 'copy',
from: compileJSONPointer(path), from: compileJSONPointer(path),
path: compileJSONPointer(parentPath.concat(index)) path: compileJSONPointer(rootPath.concat(maxIndex + offset))
}] }))
} }
else { // object.type === 'Object' else { // object.type === 'Object'
const prop = path[path.length - 1] const { maxIndex } = findSelectionIndices(root, start, end)
const newProp = findUniqueName(prop, parent.props.map(p => p.name)) const nextProp = root.props && root.props[maxIndex]
const before = nextProp ? nextProp.name : null
return [{ return paths.map(path => {
const prop = last(path)
const newProp = findUniqueName(prop, root.props.map(p => p.name))
return {
op: 'copy', op: 'copy',
from: compileJSONPointer(path), from: compileJSONPointer(path),
path: compileJSONPointer(parentPath.concat(newProp)), path: compileJSONPointer(rootPath.concat(newProp)),
jsoneditor: { jsoneditor: {
before: findNextProp(parent, prop) before
} }
}] }
})
} }
} }
@ -226,7 +233,7 @@ export function insertBefore (data, path, values) { // TODO: find a better name
* and object property * and object property
* *
* @param {ESON} data * @param {ESON} data
* @param {Selection} selection * @param {ESONSelection} selection
* @param {Array.<{name?: string, value: JSONType, type?: ESONType}>} values * @param {Array.<{name?: string, value: JSONType, type?: ESONType}>} values
* @return {Array} * @return {Array}
*/ */
@ -235,10 +242,8 @@ export function replace (data, selection, values) { // TODO: find a better name
const rootPath = findRootPath(selection) const rootPath = findRootPath(selection)
const start = selection.start.path[rootPath.length] const start = selection.start.path[rootPath.length]
const end = selection.end.path[rootPath.length] const end = selection.end.path[rootPath.length]
console.log('rootPath', rootPath, start, end)
const root = getIn(data, toEsonPath(data, rootPath)) const root = getIn(data, toEsonPath(data, rootPath))
const { minIndex, maxIndex } = findSelectionIndices(root, start, end) const { minIndex, maxIndex } = findSelectionIndices(root, start, end)
console.log('selection', minIndex, maxIndex)
if (root.type === 'Array') { if (root.type === 'Array') {
const removeActions = removeAll(pathsFromSelection(data, selection)) const removeActions = removeAll(pathsFromSelection(data, selection))

View File

@ -72,6 +72,7 @@ export default class TreeMode extends Component {
'cut': this.handleKeyDownCut, 'cut': this.handleKeyDownCut,
'copy': this.handleKeyDownCopy, 'copy': this.handleKeyDownCopy,
'paste': this.handleKeyDownPaste, 'paste': this.handleKeyDownPaste,
'duplicate': this.handleKeyDownDuplicate,
'undo': this.handleUndo, 'undo': this.handleUndo,
'redo': this.handleRedo, 'redo': this.handleRedo,
'find': this.handleFocusFind, 'find': this.handleFocusFind,
@ -372,11 +373,11 @@ export default class TreeMode extends Component {
this.focusToNext(parentPath) this.focusToNext(parentPath)
} }
handleDuplicate = (path) => { handleDuplicate = () => {
this.handlePatch(duplicate(this.state.data, path)) if (this.state.selection) {
this.handlePatch(duplicate(this.state.data, this.state.selection))
// apply focus to the duplicated node // TODO: focus to duplicated selection
this.focusToNext(path) }
} }
handleRemove = (path) => { handleRemove = (path) => {
@ -455,6 +456,17 @@ export default class TreeMode extends Component {
} }
} }
handleKeyDownDuplicate = (event) => {
const path = this.findDataPathFromElement(event.target)
if (path) {
const selection = { start: {path}, end: {path} }
this.handlePatch(duplicate(this.state.data, selection))
// apply focus to the duplicated node
this.focusToNext(path)
}
}
handleCut = () => { handleCut = () => {
const selection = this.state.selection const selection = this.state.selection
if (selection && selection.start && selection.end) { if (selection && selection.start && selection.end) {

View File

@ -53,42 +53,42 @@ const CREATE_TYPE = {
duplicate: (path, events) => h('button', { duplicate: (path, events) => h('button', {
key: 'duplicate', key: 'duplicate',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onDuplicate(path), onClick: () => events.onDuplicate(),
title: 'Duplicate' title: 'Duplicate'
}, 'Duplicate'), }, 'Duplicate'),
cut: (path, events) => h('button', { cut: (path, events) => h('button', {
key: 'cut', key: 'cut',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onCut(path), onClick: () => events.onCut(),
title: 'Cut' title: 'Cut'
}, 'Cut'), }, 'Cut'),
copy: (path, events) => h('button', { copy: (path, events) => h('button', {
key: 'copy', key: 'copy',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onCopy(path), onClick: () => events.onCopy(),
title: 'Copy' title: 'Copy'
}, 'Copy'), }, 'Copy'),
paste: (path, events) => h('button', { paste: (path, events) => h('button', {
key: 'paste', key: 'paste',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onPaste(path), onClick: () => events.onPaste(),
title: 'Paste' title: 'Paste'
}, 'Paste'), }, 'Paste'),
remove: (path, events) => h('button', { remove: (path, events) => h('button', {
key: 'remove', key: 'remove',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onRemove(null), // do not pass path: we want to remove selection onClick: () => events.onRemove(),
title: 'Remove' title: 'Remove'
}, 'Remove'), }, 'Remove'),
insertStructure: (path, events) => h('button', { insertStructure: (path, events) => h('button', {
key: 'insertStructure', key: 'insertStructure',
className: MENU_ITEM_CLASS_NAME, className: MENU_ITEM_CLASS_NAME,
onClick: () => events.onInsertStructure(path), onClick: () => events.onInsertStructure(),
title: 'Insert a new object with the same data structure as the item above' title: 'Insert a new object with the same data structure as the item above'
}, 'Insert structure'), }, 'Insert structure'),