diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index 2f0fee2e23367ec66b4aabb301eedf0e03324902..7a0a201e37524e4558a97a2fa19695e759a5b90d 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -16,10 +16,20 @@ import { } from 'lodash' import { - annotationHelpers, + // annotationHelpers, TOCProvider } from 'substance' +import { + createTrackAnnotation, + deleteCharacter, + deleteSelection, + expandTrackAnnotation, + insertText, + removeTrackAnnotation, + truncateTrackAnnotation +} from './utils/transformations' + class TrackChangesProvider extends TOCProvider { constructor (document, config) { super(document, config) @@ -43,6 +53,9 @@ class TrackChangesProvider extends TOCProvider { handleTransaction (options) { options.selection = this.getSelection() + options.surface = this.getSurface() + options.user = this.config.user + this.chooseHanlder(options) } @@ -59,7 +72,7 @@ class TrackChangesProvider extends TOCProvider { } handleAddCollapsed (options) { - const { event } = options + // const { event } = options const notOnTrack = this.isNotOnTrackAnnotation() const isOnAdd = this.isOnAnnotation('add') @@ -76,7 +89,7 @@ class TrackChangesProvider extends TOCProvider { const mode = this.getMode() if (isFromSameUser) { - this.insertText(event) + insertText(options) if (isOnLeftEdge) this.expandAnnotationToDirection(annotation) } @@ -84,7 +97,7 @@ class TrackChangesProvider extends TOCProvider { if (isOnRightEdge) { this.insertCharacterWithoutExpandingAnnotation(annotation, options) } else { - this.insertText(event) + insertText(options) } if (mode) this.createAdditionAnnotationOnLastChar() @@ -211,7 +224,7 @@ class TrackChangesProvider extends TOCProvider { } if (!isFromSameUser && isOnDelete) pass = true - if (!pass) return this.deleteCharacter(direction.move) + if (!pass) return deleteCharacter(options) } if (isOnDelete) { @@ -261,8 +274,9 @@ class TrackChangesProvider extends TOCProvider { this.updateSelection(selection, startOffset, endOffset) - // console.log('collapsed', selection.isCollapsed()) - if (selection.isCollapsed()) return this.handleDeleteCollapsed(options) + // TODO -- validate that this is not needed + // if (selection.isCollapsed()) return this.handleDeleteCollapsed(options) + if (selection.isCollapsed()) return if (isOnDelete) { // console.log @@ -297,11 +311,16 @@ class TrackChangesProvider extends TOCProvider { createAdditionAnnotationOnLastChar () { const selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) + const status = 'add' + const surface = this.getSurface() + const { user } = this.config + + createTrackAnnotation({ selection, status, surface, user }) this.moveCursorTo('end') } deleteAllOwnAdditions (selection) { + const surface = this.getSurface() const originalSelection = selection || this.getSelection() let shortenBy = 0 @@ -314,22 +333,28 @@ class TrackChangesProvider extends TOCProvider { const selection = annotation.getSelection() // make sure only the part of the annotation that is selected is deleted - if (annotation.startOffset < originalSelection.startOffset) { - selection.startOffset = originalSelection.startOffset + if (annotation.start.offset < originalSelection.start.offset) { + selection.start.offset = originalSelection.start.offset } - if (annotation.endOffset > originalSelection.endOffset) { - selection.endOffset = originalSelection.endOffset + if (annotation.end.offset > originalSelection.end.offset) { + selection.end.offset = originalSelection.end.offset } - shortenBy += (selection.endOffset - selection.startOffset) - this.deleteSelection(selection) + shortenBy += (selection.end.offset - selection.start.offset) + + const options = { selection, surface } + deleteSelection(options) }) + // throw llsdjlkfjdslkjlkdfjlksj + return shortenBy // return how much shorter the selection should now be } deleteOrMergeAllOwnDeletions (selection) { + const surface = this.getSurface() + const deletions = clone(this.getAllAnnotationsByStatus('delete')) const ownDeletions = filter(deletions, annotation => { return this.isAnnotationFromTheSameUser(annotation) @@ -345,7 +370,7 @@ class TrackChangesProvider extends TOCProvider { selectionArray.push(annotationSelection) } - this.removeTrackAnnotation(annotation) + removeTrackAnnotation({ annotation, surface }) }) selection.start.offset = minBy(selectionArray, 'start.offset').start.offset @@ -359,7 +384,8 @@ class TrackChangesProvider extends TOCProvider { deleteSelectedAndCreateAddition (options) { let { selection } = options - this.createDeleteAnnotation(selection) + options.status = 'delete' + createTrackAnnotation(options) this.moveCursorTo('end', selection) // selection is now collapsed, so handle it as collapsed @@ -368,173 +394,54 @@ class TrackChangesProvider extends TOCProvider { expandAnnotationToDirection (annotation, options) { if (!options) options = {} + const surface = this.getSurface() const move = options.move || 'left' const cursorTo = options.cursorTo || 'end' const selection = this.setSelectionPlusOne(move) - this.expandTrackAnnotation(selection, annotation) + + expandTrackAnnotation({ annotation, selection, surface }) this.moveCursorTo(cursorTo) } insertCharacterWithAddAnnotation (options) { - const { event } = options - this.insertText(event) + insertText(options) // TODO -- watch it with additions by other users this.createAdditionAnnotationOnLastChar() } insertCharacterWithoutExpandingAnnotation (annotation, options) { - const { event } = options - let selection = options + insertText(options) + + const selection = this.setSelectionPlusOne('left') + options.selection = selection + options.annotation = annotation + options.doc = this.getDocument() - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.truncateTrackAnnotation(selection, annotation) + truncateTrackAnnotation(options) this.moveCursorTo('end') - options.event = null + options.event = null // ? } markSelectionAsDeleted (options) { const { direction, selection } = options - this.createDeleteAnnotation(selection) + options.status = 'delete' + createTrackAnnotation(options) this.moveCursorTo(direction.cursorTo) } selectCharacterAndMarkDeleted (options) { const { direction } = options + options.status = 'delete' const selection = this.setSelectionPlusOne(direction.move) + options.selection = selection - this.createDeleteAnnotation(selection) + createTrackAnnotation(options) this.moveCursorTo(direction.cursorTo) } - /* - - TRANSFORMATIONS - - */ - - createAddAnnotation (selection) { - this.createTrackAnnotation(selection, 'add') - } - - createDeleteAnnotation (selection) { - this.createTrackAnnotation(selection, 'delete') - } - - // TODO -- selection could default to current selection - createTrackAnnotation (selection, status) { - const surface = this.getSurface() - const info = this.getInfo() - const { user } = this.config - - if (selection.isContainerSelection()) { - return console.warn('Cannot delete a container') - } - - if (selection.isNodeSelection()) { - if (selection.isCollapsed()) return this.deleteCharacter('left') - return this.deleteSelection(selection) - } - - const transformation = (tx, args) => { - const newNode = { - selection: selection, - status: status, - type: 'track-change', - path: selection.path, - start: selection.start, - end: selection.end, - user: { - id: user.id, - roles: user.roles, - username: user.username - } - } - tx.create(newNode) - } - - surface.editorSession.transaction(transformation, info) - } - - deleteCharacter (direction) { - const surface = this.getSurface() - const info = { action: 'delete' } - - const transformation = (tx, args) => { - args.direction = direction - return tx.deleteCharacter(direction) - } - - surface.editorSession.transaction(transformation, info) - } - - deleteSelection (selection) { - const surface = this.getSurface() - const info = { action: 'delete' } - const transformation = (tx, args) => { - tx.setSelection({ - type: 'property', - path: selection.path, - surfaceId: 'body', - startOffset: selection.start.offset, - endOffset: selection.end.offset - }) - return tx.deleteSelection() - } - - surface.editorSession.transaction(transformation, info) - } - - expandTrackAnnotation (selection, annotation) { - const surface = this.getSurface() - const info = this.getInfo() - - const transformation = (tx, args) => { - args.selection = selection - args.anno = annotation - - annotationHelpers.expandAnnotation(tx, args.anno, args.selection) - } - - surface.editorSession.transaction(transformation, info) - } - - insertText (event) { - if (!event) return - const surface = this.getSurface() - - surface.editorSession.transaction(function (tx, args) { - if (surface.domSelection) surface.domSelection.clear() - args.text = event.data || ' ' // if no data, it's a space key - return tx.insertText(args.text) - }, { action: 'type' }) - } - - removeTrackAnnotation (annotation) { - const surface = this.getSurface() - - const transformation = (tx, args) => { - tx.delete(annotation.id) - } - - surface.editorSession.transaction(transformation) - } - - truncateTrackAnnotation (selection, annotation) { - const surface = this.getSurface() - const info = this.getInfo() - const doc = this.getDocument() - - const transformation = (tx, args) => { - annotationHelpers.truncateAnnotation(doc, annotation, selection) - } - - surface.editorSession.transaction(transformation, info) - } - /* ACCEPT / REJECT @@ -543,16 +450,22 @@ class TrackChangesProvider extends TOCProvider { resolve (annotation, action) { // const next = this.getNext(annotation) - const selection = annotation.getSelection() + // const selection = annotation.getSelection() const status = annotation.status - this.removeTrackAnnotation(annotation) + let options = { + annotation: annotation, + surface: this.getSurface() + } + + removeTrackAnnotation(options) if ( (action === 'accept' && status === 'delete') || (action === 'reject' && status === 'add') ) { - this.deleteSelection(selection) + options.selection = annotation.getSelection() + deleteSelection(options) } // this.focus(next) diff --git a/app/components/SimpleEditor/elements/track_change/utils/transformations.js b/app/components/SimpleEditor/elements/track_change/utils/transformations.js new file mode 100644 index 0000000000000000000000000000000000000000..0b0ed7c2208fc18caf10a5ffceee4b615248d1f4 --- /dev/null +++ b/app/components/SimpleEditor/elements/track_change/utils/transformations.js @@ -0,0 +1,153 @@ +import { annotationHelpers } from 'substance' + +/* + + TEXT TRANSFORMATIONS + +*/ + +const deleteCharacter = options => { + // const surface = this.getSurface() + const { direction, surface } = options + const move = direction.move + const info = { action: 'delete' } + + const transformation = (tx, args) => { + args.direction = move + return tx.deleteCharacter(move) + } + + surface.editorSession.transaction(transformation, info) +} + +const deleteSelection = options => { + const { selection, surface } = options + const info = { action: 'delete' } + + const transformation = (tx, args) => { + tx.setSelection({ + type: 'property', + path: selection.path, + surfaceId: 'body', + startOffset: selection.start.offset, + endOffset: selection.end.offset + }) + + return tx.deleteSelection() + } + + surface.editorSession.transaction(transformation, info) +} + +const insertText = options => { + const { event, surface } = options + if (!event) return + + surface.editorSession.transaction(function (tx, args) { + if (surface.domSelection) surface.domSelection.clear() + args.text = event.data || ' ' // if no data, it's a space key + return tx.insertText(args.text) + }, { action: 'type' }) +} + +/* + + ANNOTATION TRANSFORMATIONS + +*/ + +const createTrackAnnotation = options => { + const { selection, status, surface, user } = options + const info = getInfo() + + // TODO -- these two ifs don't work anymore + if (selection.isContainerSelection()) { + return console.warn('Cannot delete a container') + } + + if (selection.isNodeSelection()) { + // console.log('node selection!') + if (selection.isCollapsed()) { + // options.direction. + return this.deleteCharacter('left') + } + return this.deleteSelection(selection) + } + + const transformation = (tx, args) => { + const newNode = { + selection: selection, + status: status, + type: 'track-change', + path: selection.path, + start: selection.start, + end: selection.end, + user: { + id: user.id, + roles: user.roles, + username: user.username + } + } + tx.create(newNode) + } + + surface.editorSession.transaction(transformation, info) +} + +const expandTrackAnnotation = options => { + const { annotation, selection, surface } = options + const info = getInfo() + + const transformation = (tx, args) => { + args.selection = selection + args.anno = annotation + + annotationHelpers.expandAnnotation(tx, args.anno, args.selection) + } + + surface.editorSession.transaction(transformation, info) +} + +const removeTrackAnnotation = options => { + const { annotation, surface } = options + + const transformation = (tx, args) => { + tx.delete(annotation.id) + } + + surface.editorSession.transaction(transformation) +} + +const truncateTrackAnnotation = options => { + const { annotation, doc, selection, surface } = options + const info = getInfo() + + const transformation = (tx, args) => { + annotationHelpers.truncateAnnotation(doc, annotation, selection) + } + + surface.editorSession.transaction(transformation, info) +} + +// Prevent substance from running getBoundingRectangle, +// as we will unset the selection manually. + +const getInfo = () => { + return { skipSelection: true } +} + +/* + + EXPORT + +*/ + +export { + createTrackAnnotation, + deleteCharacter, + deleteSelection, + expandTrackAnnotation, + insertText, + removeTrackAnnotation, + truncateTrackAnnotation +}