From 7e6e12cc57c4d56a0043de6443e4b9772442543c Mon Sep 17 00:00:00 2001 From: john <johnbarlas39@gmail.com> Date: Fri, 6 Jan 2017 01:26:13 +0200 Subject: [PATCH] refactor and bug fixes on track change addition annotation handlers --- .../SimpleEditor/SimpleEditorWrapper.jsx | 2 - .../track_change/TrackChangeComponent.js | 49 ++- .../track_change/TrackChangesProvider.js | 338 ++++++++++-------- 3 files changed, 211 insertions(+), 178 deletions(-) diff --git a/app/components/SimpleEditor/SimpleEditorWrapper.jsx b/app/components/SimpleEditor/SimpleEditorWrapper.jsx index 9ca0910..7d4bb7f 100644 --- a/app/components/SimpleEditor/SimpleEditorWrapper.jsx +++ b/app/components/SimpleEditor/SimpleEditorWrapper.jsx @@ -142,8 +142,6 @@ export class SimpleEditorWrapper extends React.Component { render () { const { book, fragment, history, user } = this.props - // user.roles = user.getRoles() - console.log(fragment, user) // TODO -- merge update and updateComments return ( diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js b/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js index 1617e9d..c602a5b 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js @@ -2,47 +2,40 @@ import { AnnotationComponent, createAnnotation, deleteNode } from 'substance' class TrackChangeComponent extends AnnotationComponent { render ($$) { - // const user = this.context.controller.props.user - const status = this.props.node.status + const { status } = this.props.node const trackChangesView = this.toggleTrackChangeView() - let hideDeletes = '' - let showAdditions = '' - - if (trackChangesView === false && status === 'delete') { - hideDeletes = 'sc-track-delete-hide' - } - - if (trackChangesView === false && status === 'add') { - showAdditions = 'sc-track-add-show' - } const accept = $$('a') .addClass('sc-track-item') .on('click', this.acceptTrackChange) .append('accept') - const reject = $$('a').addClass('sc-track-item') - .on('click', this.rejectTrackChange) - .append('reject') - const seperator = $$('span').addClass('sc-track-separator') - .append(' / ') - const container = $$('span').addClass('sc-accept-reject-container') - .append(accept) - .append(seperator) - .append(reject) + const reject = $$('a') + .addClass('sc-track-item') + .on('click', this.rejectTrackChange) + .append('reject') + + const separator = $$('span') + .addClass('sc-track-separator') + .append(' / ') + + const container = $$('span') + .addClass('sc-accept-reject-container') + .append(accept) + .append(separator) + .append(reject) let el = $$('span') - // .attr('data-id', this.props.node.id) - // .attr('data-user', user.username) - // .attr('data-role', user.teams[0].name) .addClass(this.getClassNames()) - .addClass(hideDeletes) - .addClass(showAdditions) .append(this.props.children) .append(container) - const className = 'sc-track-change-' + status - el.addClass(className) + el.addClass('sc-track-change-' + status) + + if (trackChangesView === false) { + if (status === 'delete') el.addClass('sc-track-delete-hide') + if (status === 'add') el.addClass('sc-track-add-show') + } return el } diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index 94ff366..ff8ced4 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -3,9 +3,9 @@ import { filter, find, keys, - last, - max, - minBy + last + // max, + // minBy } from 'lodash' import { @@ -29,155 +29,194 @@ class TrackChangesProvider { */ handleTransaction (options) { - this.handleAdd(options) - this.handleDelete(options) + options.selection = this.getSelection() + this.chooseHanlder(options) } - handleAdd (options) { - const { event, status } = options - if (status !== 'add') return - // console.log('adding') + chooseHanlder (options) { + if (options.status === 'add') return this.handleAdd(options) + if (options.status === 'delete') return this.handleDelete(options) + } + handleAdd (options) { const isSelectionCollapsed = this.isSelectionCollapsed() - let selection - if (isSelectionCollapsed) { - // this.insertText(event) + if (isSelectionCollapsed) return this.handleAddCollapsed(options) + if (!isSelectionCollapsed) return this.handleAddNonCollapsed(options) + } - const notOnTrack = this.isNotOnTrackAnnotation() + handleAddCollapsed (options) { + const { event } = options - if (notOnTrack) { - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.moveCursorTo('end') - return - } else { - const isOnAdd = this.isOnAnnotation('add') + const notOnTrack = this.isNotOnTrackAnnotation() + const isOnAdd = this.isOnAnnotation('add') + const isOnDelete = this.isOnAnnotation('delete') - if (isOnAdd) { - const annotation = this.getAnnotationByStatus('add') - const isOnLeftEdge = this.isOnLeftEdge(annotation) + if (notOnTrack) return this.insertCharacterWithAddAnnotation(options) - this.insertText(event) - if (isOnLeftEdge) { - selection = this.setSelectionPlusOne('left') - this.expandTrackAnnotation(selection, annotation) - this.moveCursorTo('end') - return - } - return - } + if (isOnAdd) { + const annotation = this.getAnnotationByStatus('add') + const isOnLeftEdge = this.isOnLeftEdge(annotation) - const isOnDelete = this.isOnAnnotation('delete') + this.insertText(event) + if (isOnLeftEdge) this.expandAnnotationToTheLeft(annotation) + return + } - if (isOnDelete) { - console.log('on delete') - const annotation = this.getAnnotationByStatus('delete') - const withinAnnotation = this.isSelectionContainedWithin(annotation, true) - - if (withinAnnotation) { - // console.log('in') - this.moveCursorTo(annotation.endOffset) - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return - } + if (isOnDelete) { + const annotation = this.getAnnotationByStatus('delete') - console.log('out') - const isOnLeftEdge = this.isOnLeftEdge(annotation) - if (isOnLeftEdge) { - // console.log('left') - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.moveCursorTo('end') - return - } + const isOnLeftEdge = this.isOnLeftEdge(annotation) + const isOnRightEdge = this.isOnRightEdge(annotation) + const withinAnnotation = this.isSelectionContainedWithin(annotation, true) - const isOnRightEdge = this.isOnRightEdge(annotation) - if (isOnRightEdge) { - // console.log('right') - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return - } - } + if (withinAnnotation) { + this.moveCursorTo(annotation.endOffset) + this.insertCharacterWithoutExpandingAnnotation(annotation, options) + options.selection = this.getSelection() + return this.handleAdd(options) } - } else { - selection = this.getSelection() - const notOnTrack = this.isNotOnTrackAnnotation() + if (isOnLeftEdge) return this.insertCharacterWithAddAnnotation(options) - if (notOnTrack) { - this.createDeleteAnnotation(selection) - this.moveCursorTo('end') - - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return + if (isOnRightEdge) { + this.insertCharacterWithoutExpandingAnnotation(annotation, options) + return this.handleAdd(options) } + } + } - const isOnAdd = this.isOnAnnotation('add') + handleAddNonCollapsed (options) { + // const { event } = options + let { selection } = options - if (isOnAdd) { - const annotation = this.getAnnotationByStatus('add') - const withinAnnotation = this.isSelectionContainedWithin(annotation) + const notOnTrack = this.isNotOnTrackAnnotation() + // const isOnAdd = this.isOnAnnotation('add') + // const isOnDelete = this.isOnAnnotation('delete') - if (withinAnnotation) return this.insertText(event) + if (notOnTrack) return this.deleteSelectedAndCreateAddition(options) - 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') - return - } + const shortenBy = this.deleteAllOwnAdditions(selection) + options.selection = this.updateSelection(selection, selection.startOffset, selection.endOffset - shortenBy) + this.deleteSelectedAndCreateAddition(options) - const isOnDelete = this.isOnAnnotation('delete') + // 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') + // return + // } + // + // if (isOnDelete) { + // const annotation = this.getAnnotationByStatus('delete') + // const withinAnnotation = this.isSelectionContainedWithin(annotation) + // + // if (withinAnnotation) { + // this.moveCursorTo(annotation.endOffset) + // // options.selection = + // this.insertText(event) + // selection = this.setSelectionPlusOne('left') + // this.createAddAnnotation(selection) + // this.separateAnnotations() + // this.moveCursorTo('end') + // return + // } + // + // selection = this.getSelection() + // this.expandTrackAnnotation(selection, annotation) + // + // this.moveCursorTo(annotation.endOffset) + // this.insertText(event) + // selection = this.setSelectionPlusOne('left') + // this.createAddAnnotation(selection) + // this.separateAnnotations() + // this.moveCursorTo('end') + // return + // } + } - if (isOnDelete) { - const annotation = this.getAnnotationByStatus('delete') - const withinAnnotation = this.isSelectionContainedWithin(annotation) + deleteSelectedAndCreateAddition (options) { + let { selection } = options - if (withinAnnotation) { - this.moveCursorTo(annotation.endOffset) - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return - } + this.createDeleteAnnotation(selection) + this.moveCursorTo('end', selection) - selection = this.getSelection() - this.expandTrackAnnotation(selection, annotation) + const deleteAnnotation = this.getAnnotationByStatus('delete') + this.insertCharacterWithoutExpandingAnnotation(deleteAnnotation, options) + this.createAdditionAnnotationOnLastChar() + } - this.moveCursorTo(annotation.endOffset) - this.insertText(event) - selection = this.setSelectionPlusOne('left') - this.createAddAnnotation(selection) - this.separateAnnotations() - this.moveCursorTo('end') - return + // Inserts a character and then marks it as an add annotation + // If an add annotation existed on the left side of the new character already + // substance will expand this annotation on insertion + insertCharacterWithAddAnnotation (options) { + const { event } = options + this.insertText(event) + // TODO -- watch it with additions by other users + this.createAdditionAnnotationOnLastChar() + } + + createAdditionAnnotationOnLastChar () { + const selection = this.setSelectionPlusOne('left') + this.createAddAnnotation(selection) + this.moveCursorTo('end') + } + + expandAnnotationToTheLeft (annotation) { + const selection = this.setSelectionPlusOne('left') + this.expandTrackAnnotation(selection, annotation) + this.moveCursorTo('end') + } + + insertCharacterWithoutExpandingAnnotation (annotation, options) { + const { event } = options + let selection = options + + this.insertText(event) + selection = this.setSelectionPlusOne('left') + this.truncateTrackAnnotation(selection, annotation) + this.moveCursorTo('end') + + options.event = null + } + + deleteAllOwnAdditions (selection) { + // TODO -- for same user + const additions = this.getAllAnnotationsByStatus('add') + const originalSelection = selection || this.getSelection() + + let shortenBy = 0 + + 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 + } + + shortenBy += (selection.endOffset - selection.startOffset) + this.deleteSelection(selection) + }) + + return shortenBy // return how much shorter the selection should now be } handleDelete (options) { @@ -185,6 +224,8 @@ class TrackChangesProvider { if (status !== 'delete') return // console.log('deleting') + // console.log(this.getSelection()) + const isSelectionCollapsed = this.isSelectionCollapsed() let selection @@ -264,6 +305,7 @@ class TrackChangesProvider { const onAdd = this.isOnAnnotation('add') if (onAdd) { + // console.log('on add') const annotation = this.getAnnotationByStatus('add') const withinAnnotation = this.isSelectionContainedWithin(annotation) @@ -363,6 +405,19 @@ class TrackChangesProvider { surface.transaction(transformation, info) } + truncateTrackAnnotation (selection, annotation) { + const surface = this.getSurface() + const info = this.getInfo() + + const transformation = (tx, args) => { + args.anno = annotation + args.selection = selection + truncateAnnotation(tx, args) + } + + surface.transaction(transformation, info) + } + separateAnnotations () { const surface = this.getSurface() const info = this.getInfo() @@ -386,7 +441,9 @@ class TrackChangesProvider { } insertText (event) { + if (!event) return const surface = this.getSurface() + surface.transaction(function (tx, args) { if (surface.domSelection) surface.domSelection.clear() args.text = event.data || ' ' // if no data, it's a space key @@ -418,27 +475,6 @@ class TrackChangesProvider { 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 @@ -573,6 +609,12 @@ class TrackChangesProvider { // is part of the selection outside the annotation // move cursor to + updateSelection (selection, startOffset, endOffset) { + selection.startOffset = startOffset + selection.endOffset = endOffset + return selection + } + setSelectionPlusOne (direction) { const selection = this.getSelection() @@ -582,8 +624,8 @@ class TrackChangesProvider { return selection } - moveCursorTo (point) { - const selection = this.getSelection() + moveCursorTo (point, sel) { + const selection = sel || this.getSelection() const surface = this.getSurface() // TODO -- use substance's selection.collapse(direction) -- GitLab