diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index dbc3e0d390cc72bc9b418cc772bd66f383267209..da3fcd32e86d0ce7ff24f5d52a5d7a74b4628f2d 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -1,13 +1,17 @@ import { + each, filter, find, keys, - last + last, + max, + minBy } from 'lodash' import { createAnnotation, deleteCharacter as deleteChar, + deleteSelection as deleteSel, expandAnnotation, truncateAnnotation } from 'substance' @@ -18,6 +22,12 @@ class TrackChangesProvider { this.config.documentSession.on('didUpdate', this.handleUndoRedo, this) } + /* + + HANDLERS + + */ + handleTransaction (options) { this.handleAdd(options) this.handleDelete(options) @@ -58,15 +68,42 @@ class TrackChangesProvider { } } else { selection = this.getSelection() - this.createDeleteAnnotation(selection) - this.moveCursorTo('end') - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return + const notOnTrack = this.isNotOnTrackAnnotation() + + if (notOnTrack) { + this.createDeleteAnnotation(selection) + this.moveCursorTo('end') + + this.insertText(event) + selection = this.setSelectionPlusOne('left') + this.createAddAnnotation(selection) + this.separateAnnotations() + this.moveCursorTo('end') + return + } + + const isOnAdd = this.isOnAnnotation('add') + + if (isOnAdd) { + const annotation = this.getAnnotationByStatus('add') + const withinAnnotation = this.isSelectionContainedWithin(annotation) + + if (withinAnnotation) return this.insertText(event) + + selection = this.getSelection() + this.createDeleteAnnotation(selection) + const allAdditions = this.getAllAnnotationsByStatus('add') + const firstAddition = minBy(allAdditions, 'startOffset') + this.deleteAllOwnAdditions() + + const moveTo = max([firstAddition.startOffset, selection.startOffset]) + this.moveCursorTo(moveTo) + this.insertText(event) + selection = this.setSelectionPlusOne('left') + this.createAddAnnotation(selection) + this.moveCursorTo('end') + } } } @@ -131,6 +168,12 @@ class TrackChangesProvider { } } + /* + + TRANSFORMATIONS + + */ + createAddAnnotation (selection) { this.createTrackAnnotation(selection, 'add') } @@ -205,23 +248,59 @@ class TrackChangesProvider { surface.transaction(transformation, info) } + deleteSelection (selection) { + const surface = this.getSurface() + const info = { action: 'delete' } + + const transformation = (tx, args) => { + args.selection = selection + return deleteSel(tx, args) + } + + surface.transaction(transformation, info) + } + + // TODO -- also needs multiple additions + deleteAllOwnAdditions () { + // TODO -- for same user + const additions = this.getAllAnnotationsByStatus('add') + const originalSelection = this.getSelection() + + each(additions, (annotation) => { + const selection = annotation.getSelection() + + // make sure only part of annotation that is selected is deleted + if (annotation.startOffset < originalSelection.startOffset) { + selection.startOffset = originalSelection.startOffset + } + if (annotation.endOffset > originalSelection.endOffset) { + selection.endOffset = originalSelection.endOffset + } + + this.deleteSelection(selection) + }) + } + /* ANNOTATION HELPERS */ - // is on left edge - // is on right edge // is annotation from the same user - // TODO -- handle multiple delete and add annotations - getAnnotationByStatus (status) { + getAllAnnotationsByStatus (status) { const annotations = this.getAllExistingTrackAnnotations() const annotationsByStatus = filter(annotations, (annotation) => { return annotation.status === status }) - return annotationsByStatus[0] + return annotationsByStatus + } + + // TODO -- handle multiple delete and add annotations + getAnnotationByStatus (status) { + const annotationsForStatus = this.getAllAnnotationsByStatus(status) + return annotationsForStatus[0] } getExistingAnnotation () { @@ -238,6 +317,19 @@ class TrackChangesProvider { return annotations } + // getDistinctAnnotationsForSelection () { + // const selection = this.getSelection() + // const annotations = this.getAllExistingTrackAnnotations() + // + // console.log(selection) + // console.log(annotations) + // + // console.log(selection.getFragments()) + // + // // get all annotations by status (add / delete) + // // get all pieces of free text + // } + // prevent substance from running getBoundingRectangle, // as we will unset the selection manually getInfo () { @@ -266,8 +358,8 @@ class TrackChangesProvider { } isNotOnTrackAnnotation () { - const mode = this.getMode() - return (mode === null) + const annotations = this.getAllExistingTrackAnnotations() + return (annotations.length === 0) } /** @@ -336,6 +428,7 @@ class TrackChangesProvider { const selection = this.getSelection() const surface = this.getSurface() + // TODO -- use substance's selection.collapse(direction) if (point === 'start') { selection.endOffset = selection.startOffset } else if (point === 'end') { @@ -373,6 +466,16 @@ class TrackChangesProvider { return isCollapsed } + isSelectionContainedWithin (annotation) { + const selection = this.getSelection() + + const leftSide = (selection.startOffset < annotation.startOffset) + const rightSide = (selection.endOffset > annotation.endOffset) + + if (leftSide || rightSide) return false + return true + } + /* GETTERS diff --git a/app/components/SimpleEditor/elements/track_change/trackChange.scss b/app/components/SimpleEditor/elements/track_change/trackChange.scss index bd8eb65dd658e191601276684ec59044c972670d..b8131dcb69f9b590a484b516ce06e559e6fac3ec 100644 --- a/app/components/SimpleEditor/elements/track_change/trackChange.scss +++ b/app/components/SimpleEditor/elements/track_change/trackChange.scss @@ -4,13 +4,11 @@ .sc-track-change-add { background-color: #f7f70c; + display: inline-block; + text-decoration: none; } .sc-track-change-delete { background-color: red; text-decoration: line-through; - - .sc-track-change-add { - text-decoration: none !important; - } }