diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index 23bf741f172609d492648574c859247f3ce01875..be28e3c302575870d064270c0243437223c040d8 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -1,6 +1,6 @@ import { clone, - each, + // each, filter, find, findIndex, @@ -8,8 +8,8 @@ import { keys, // last, map, - maxBy, - minBy, + // maxBy, + // minBy, pickBy, some, sortBy @@ -21,19 +21,27 @@ import { } from 'substance' import { - createTrackAnnotation, + createAdditionAnnotationOnLastChar, + deleteAllOwnAdditions, + deleteOrMergeAllOwnDeletions, + deleteSelectedAndCreateAddition, + expandAnnotationToDirection, + insertCharacterWithAddAnnotation, + insertCharacterWithoutExpandingAnnotation, + markSelectionAsDeleted, + selectCharacterAndMarkDeleted +} from './utils/handlerHelpers' + +import { + // createTrackAnnotation, deleteCharacter, deleteSelection, - expandTrackAnnotation, + // expandTrackAnnotation, insertText, - removeTrackAnnotation, - truncateTrackAnnotation + removeTrackAnnotation + // truncateTrackAnnotation } from './utils/transformations' -import { - createAdditionAnnotationOnLastChar -} from './utils/handlerHelpers' - class TrackChangesProvider extends TOCProvider { constructor (document, config) { super(document, config) @@ -57,6 +65,7 @@ class TrackChangesProvider extends TOCProvider { */ handleTransaction (options) { + options.editorSession = this.getEditorSession() options.selection = this.getSelection() options.surface = this.getSurface() options.user = this.config.user @@ -83,7 +92,7 @@ class TrackChangesProvider extends TOCProvider { const isOnAdd = this.isOnAnnotation('add') const isOnDelete = this.isOnAnnotation('delete') - if (notOnTrack) return this.insertCharacterWithAddAnnotation(options) + if (notOnTrack) return insertCharacterWithAddAnnotation(options) if (isOnAdd) { // annotation gets expanded automatically, unless the selection is on its left edge @@ -95,12 +104,12 @@ class TrackChangesProvider extends TOCProvider { if (isFromSameUser) { insertText(options) - if (isOnLeftEdge) this.expandAnnotationToDirection(annotation) + if (isOnLeftEdge) expandAnnotationToDirection(options, annotation) } if (!isFromSameUser) { if (isOnRightEdge) { - this.insertCharacterWithoutExpandingAnnotation(annotation, options) + insertCharacterWithoutExpandingAnnotation(options, annotation) } else { insertText(options) } @@ -123,15 +132,15 @@ class TrackChangesProvider extends TOCProvider { // not get inserted twice, and handle again if (withinAnnotation) { this.moveCursorTo(annotation.endOffset) - this.insertCharacterWithoutExpandingAnnotation(annotation, options) + insertCharacterWithoutExpandingAnnotation(options, annotation) options.selection = this.getSelection() return this.handleAdd(options) } - if (isOnLeftEdge) return this.insertCharacterWithAddAnnotation(options) + if (isOnLeftEdge) return insertCharacterWithAddAnnotation(options) if (isOnRightEdge) { - this.insertCharacterWithoutExpandingAnnotation(annotation, options) + insertCharacterWithoutExpandingAnnotation(options, annotation) return this.handleAdd(options) } } @@ -143,17 +152,18 @@ class TrackChangesProvider extends TOCProvider { const notOnTrack = this.isNotOnTrackAnnotation() const isOnDelete = this.isOnAnnotation('delete') - if (notOnTrack) return this.deleteSelectedAndCreateAddition(options) + if (notOnTrack) return deleteSelectedAndCreateAddition(options) // delete all additions of the same user and // shorten selection by the number of deleted characters - const shortenBy = this.deleteAllOwnAdditions(selection) - const startOffset = selection.startOffset - const endOffset = selection.endOffset - shortenBy + const shortenBy = deleteAllOwnAdditions(options, selection) + const startOffset = selection.start.offset + const endOffset = selection.end.offset - shortenBy selection = this.updateSelection(selection, startOffset, endOffset) options.selection = selection if (isOnDelete) { + // console.log('on delete') const annotation = this.getAnnotationByStatus('delete') const withinAnnotation = this.isSelectionContainedWithin(annotation) @@ -169,9 +179,9 @@ class TrackChangesProvider extends TOCProvider { // after deleting all own additions, there is still text selected // mark it as deleted and add new addition annotation at the end // TODO -- use selection.isCollapsed() - if (selection.endOffset > selection.startOffset) { - this.deleteOrMergeAllOwnDeletions(selection) - this.deleteSelectedAndCreateAddition(options) + if (selection.end.offset > selection.start.offset) { + deleteOrMergeAllOwnDeletions(options, selection) + deleteSelectedAndCreateAddition(options) return } @@ -202,7 +212,7 @@ class TrackChangesProvider extends TOCProvider { const isOnAdd = this.isOnAnnotation('add') const isOnDelete = this.isOnAnnotation('delete') - if (notOnTrack) return this.selectCharacterAndMarkDeleted(options) + if (notOnTrack) return selectCharacterAndMarkDeleted(options) if (isOnAdd) { const annotation = this.getAnnotationByStatus('add') @@ -224,7 +234,7 @@ class TrackChangesProvider extends TOCProvider { (isOnRightEdge && key === 'DELETE') || (!isFromSameUser && !isOnDelete) ) { - if (mode) return this.selectCharacterAndMarkDeleted(options) + if (mode) return selectCharacterAndMarkDeleted(options) pass = true } @@ -257,9 +267,10 @@ class TrackChangesProvider extends TOCProvider { } if (isFromSameUser) { - return this.expandAnnotationToDirection(annotation, direction) + options.cursorTo = direction.cursorTo + return expandAnnotationToDirection(options, annotation) } else { - return this.selectCharacterAndMarkDeleted(options) + return selectCharacterAndMarkDeleted(options) } } } @@ -271,9 +282,9 @@ class TrackChangesProvider extends TOCProvider { const notOnTrack = this.isNotOnTrackAnnotation() const isOnDelete = this.isOnAnnotation('delete') - if (notOnTrack) return this.markSelectionAsDeleted(options) + if (notOnTrack) return markSelectionAsDeleted(options) - const shortenBy = this.deleteAllOwnAdditions(selection) + const shortenBy = deleteAllOwnAdditions(options, selection) const startOffset = selection.start.offset const endOffset = selection.end.offset - shortenBy @@ -304,138 +315,10 @@ class TrackChangesProvider extends TOCProvider { // this.moveCursorTo(point) } - options.selection = this.deleteOrMergeAllOwnDeletions(selection) + options.selection = deleteOrMergeAllOwnDeletions(options, selection) // console.log(this.getSelection()) // options.selection = this.getSelection() - this.markSelectionAsDeleted(options) - } - - /* - HANDLER COMMON FUNCTIONS - */ - - deleteAllOwnAdditions (selection) { - const surface = this.getSurface() - const originalSelection = selection || this.getSelection() - let shortenBy = 0 - - const additions = this.getAllAnnotationsByStatus('add') - const ownAdditions = filter(additions, annotation => { - return this.isAnnotationFromTheSameUser(annotation) - }) - - each(ownAdditions, (annotation) => { - const selection = annotation.getSelection() - - // make sure only the part of the annotation that is selected is deleted - if (annotation.start.offset < originalSelection.start.offset) { - selection.start.offset = originalSelection.start.offset - } - - if (annotation.end.offset > originalSelection.end.offset) { - selection.end.offset = originalSelection.end.offset - } - - 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) - }) - - const selectionArray = [selection] - - each(ownDeletions, (annotation) => { - const annotationSelection = annotation.getSelection() - const contained = selection.contains(annotationSelection) - - if (!contained) { - selectionArray.push(annotationSelection) - } - - removeTrackAnnotation({ annotation, surface }) - }) - - selection.start.offset = minBy(selectionArray, 'start.offset').start.offset - selection.end.offset = maxBy(selectionArray, 'end.offset').end.offset - - return selection - // TODO - // this.updateSelection(selection, startOffset, endOffset) - } - - deleteSelectedAndCreateAddition (options) { - let { selection } = options - - options.status = 'delete' - createTrackAnnotation(options) - this.moveCursorTo('end', selection) - - // selection is now collapsed, so handle it as collapsed - this.handleAddCollapsed(options) - } - - 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) - - expandTrackAnnotation({ annotation, selection, surface }) - this.moveCursorTo(cursorTo) - } - - insertCharacterWithAddAnnotation (options) { - insertText(options) - - // TODO -- watch it with additions by other users - createAdditionAnnotationOnLastChar(options) - } - - insertCharacterWithoutExpandingAnnotation (annotation, options) { - insertText(options) - - const selection = this.setSelectionPlusOne('left') - options.selection = selection - options.annotation = annotation - options.doc = this.getDocument() - - truncateTrackAnnotation(options) - this.moveCursorTo('end') - - options.event = null // ? - } - - markSelectionAsDeleted (options) { - // const { direction, selection } = options - const { direction } = options - 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 - - createTrackAnnotation(options) - this.moveCursorTo(direction.cursorTo) + markSelectionAsDeleted(options) } /* diff --git a/app/components/SimpleEditor/elements/track_change/utils/annotationHelpers.js b/app/components/SimpleEditor/elements/track_change/utils/annotationHelpers.js new file mode 100644 index 0000000000000000000000000000000000000000..e8eff85a712bb56e418bddedeadede614251be60 --- /dev/null +++ b/app/components/SimpleEditor/elements/track_change/utils/annotationHelpers.js @@ -0,0 +1,38 @@ +import { filter } from 'lodash' + +const getAllAnnotationsByStatus = (options, status) => { + const annotations = getAllExistingTrackAnnotations(options) + + const annotationsByStatus = filter(annotations, (annotation) => { + return annotation.status === status + }) + + return annotationsByStatus +} + +const getAllExistingTrackAnnotations = (options) => { + // const editorSession = this.getEditorSession() + const { editorSession } = options + + const selectionState = editorSession.getSelectionState() + const annotations = selectionState.getAnnotationsForType('track-change') + + return annotations +} + +const getAnnotationUser = (annotation) => { + return annotation.user.id +} + +const isAnnotationFromTheSameUser = (options, annotation) => { + const annotationUser = getAnnotationUser(annotation) + const currentUser = options.user.id + + if (annotationUser === currentUser) return true + return false +} + +export { + getAllAnnotationsByStatus, + isAnnotationFromTheSameUser +} diff --git a/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js b/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js index 08358e0dcf4c6eb5149c3989684835ad5cd2fe1c..92f5df314bd39bab38dee7e635cab65158a46268 100644 --- a/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js +++ b/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js @@ -1,3 +1,10 @@ +import { clone, each, filter, maxBy, minBy } from 'lodash' + +import { + getAllAnnotationsByStatus, + isAnnotationFromTheSameUser +} from './annotationHelpers' + import { getSelection, moveCursorTo, @@ -5,7 +12,12 @@ import { } from './selectionHelpers' import { - createTrackAnnotation + createTrackAnnotation, + deleteSelection, + insertText, + expandTrackAnnotation, + removeTrackAnnotation, + truncateTrackAnnotation } from './transformations' const createAdditionAnnotationOnLastChar = options => { @@ -17,6 +29,151 @@ const createAdditionAnnotationOnLastChar = options => { moveCursorTo(options, 'end') } +const deleteAllOwnAdditions = options => { + const { selection, surface } = options + const originalSelection = selection + // const originalSelection = selection || this.getSelection() + let shortenBy = 0 + + const additions = getAllAnnotationsByStatus(options, 'add') + + const ownAdditions = filter(additions, annotation => { + return isAnnotationFromTheSameUser(options, annotation) + }) + + each(ownAdditions, (annotation) => { + const selection = annotation.getSelection() + + // make sure only the part of the annotation that is selected is deleted + if (annotation.start.offset < originalSelection.start.offset) { + selection.start.offset = originalSelection.start.offset + } + + if (annotation.end.offset > originalSelection.end.offset) { + selection.end.offset = originalSelection.end.offset + } + + shortenBy += (selection.end.offset - selection.start.offset) + // console.log(shortenBy) + + const options = { selection, surface } + deleteSelection(options) + }) + + // throw klfjdskljfsj + + return shortenBy // return how much shorter the selection should now be +} + +const deleteOrMergeAllOwnDeletions = (options, selection) => { + const { surface } = options + + const deletions = clone(getAllAnnotationsByStatus(options, 'delete')) + const ownDeletions = filter(deletions, annotation => { + return isAnnotationFromTheSameUser(options, annotation) + }) + + const selectionArray = [selection] + + each(ownDeletions, (annotation) => { + const annotationSelection = annotation.getSelection() + const contained = selection.contains(annotationSelection) + + if (!contained) { + selectionArray.push(annotationSelection) + } + + removeTrackAnnotation({ annotation, surface }) + }) + + selection.start.offset = minBy(selectionArray, 'start.offset').start.offset + selection.end.offset = maxBy(selectionArray, 'end.offset').end.offset + + return selection + // TODO + // this.updateSelection(selection, startOffset, endOffset) +} + +const deleteSelectedAndCreateAddition = (options) => { + options.status = 'delete' + createTrackAnnotation(options) + moveCursorTo(options, 'end') + + // selection is now collapsed, so handle it as collapsed + options.status = 'add' + const provider = getProvider(options) + provider.handleAddCollapsed(options) +} + +const getProvider = (options) => { + const { surface } = options + return surface.context.trackChangesProvider +} + +const expandAnnotationToDirection = (options, annotation) => { + const { surface } = options + const move = options.move || 'left' + const cursorTo = options.cursorTo || 'end' + + options.annotation = annotation + // const selection = setSelectionPlusOne(options, move) + options.selection = getSelection(surface) + setSelectionPlusOne(options, move) + + expandTrackAnnotation(options) + moveCursorTo(options, cursorTo) +} + +const insertCharacterWithAddAnnotation = (options) => { + insertText(options) + + // TODO -- watch it with additions by other users + createAdditionAnnotationOnLastChar(options) +} + +const insertCharacterWithoutExpandingAnnotation = (options, annotation) => { + insertText(options) + + options.selection = getSelection(options.surface) + options.selection = setSelectionPlusOne(options, 'left') + // options.selection = selection + options.annotation = annotation + options.doc = options.editorSession.getDocument() + + truncateTrackAnnotation(options) + moveCursorTo(options, 'end') + + options.event = null // ? +} + +const markSelectionAsDeleted = (options) => { + // const { direction, selection } = options + const { direction } = options + options.status = 'delete' + createTrackAnnotation(options) + moveCursorTo(options, direction.cursorTo) +} + +const selectCharacterAndMarkDeleted = (options) => { + const { direction, surface } = options + + setSelectionPlusOne(options, direction.move) + const selection = getSelection(surface) + options.selection = selection + + options.status = 'delete' + createTrackAnnotation(options) + moveCursorTo(options, direction.cursorTo) +} + export { - createAdditionAnnotationOnLastChar + createAdditionAnnotationOnLastChar, + deleteAllOwnAdditions, + deleteOrMergeAllOwnDeletions, + deleteSelectedAndCreateAddition, + expandAnnotationToDirection, + insertCharacterWithAddAnnotation, + insertCharacterWithoutExpandingAnnotation, + markSelectionAsDeleted, + selectCharacterAndMarkDeleted } diff --git a/app/components/SimpleEditor/elements/track_change/utils/transformations.js b/app/components/SimpleEditor/elements/track_change/utils/transformations.js index 0b0ed7c2208fc18caf10a5ffceee4b615248d1f4..fef1c9de5df749088f428ca8429d301cfa029d92 100644 --- a/app/components/SimpleEditor/elements/track_change/utils/transformations.js +++ b/app/components/SimpleEditor/elements/track_change/utils/transformations.js @@ -60,6 +60,8 @@ const createTrackAnnotation = options => { const { selection, status, surface, user } = options const info = getInfo() + console.log(selection) + // TODO -- these two ifs don't work anymore if (selection.isContainerSelection()) { return console.warn('Cannot delete a container')