From a787e3f8cef685e8aabe90e697531452cbb95512 Mon Sep 17 00:00:00 2001
From: john <johnbarlas39@gmail.com>
Date: Fri, 31 Mar 2017 19:34:39 +0300
Subject: [PATCH] move all track changes selection helpers to their own file

---
 .../track_change/TrackChangesProvider.js      | 200 +++---------------
 .../track_change/utils/handlerHelpers.js      |  24 ++-
 .../track_change/utils/historyHandlers.js     |  39 ++++
 .../track_change/utils/selectionHelpers.js    |  42 +++-
 .../track_change/utils/transformations.js     |   1 +
 5 files changed, 125 insertions(+), 181 deletions(-)
 create mode 100644 app/components/SimpleEditor/elements/track_change/utils/historyHandlers.js

diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
index bdf63bb..6ed4694 100644
--- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
+++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
@@ -1,27 +1,16 @@
 import {
   clone,
-  // each,
-  // filter,
-  // find,
   findIndex,
   includes,
-  keys,
-  // last,
   map,
-  // maxBy,
-  // minBy,
   pickBy,
   some,
   sortBy
 } from 'lodash'
 
-import {
-  // annotationHelpers,
-  TOCProvider
-} from 'substance'
+import { TOCProvider } from 'substance'
 
 import {
-  // getAllAnnotationsByStatus,
   getAnnotationByStatus,
   isAnnotationFromTheSameUser,
   isNotOnTrackAnnotation,
@@ -42,20 +31,26 @@ import {
   selectCharacterAndMarkDeleted
 } from './utils/handlerHelpers'
 
+// import { handleUndoRedo } from './utils/historyHandlers'
+
+import {
+  isSelectionCollapsed,
+  isSelectionContainedWithin,
+  moveCursorTo,
+  updateSelection
+} from './utils/selectionHelpers'
+
 import {
-  // createTrackAnnotation,
   deleteCharacter,
   deleteSelection,
-  // expandTrackAnnotation,
   insertText,
   removeTrackAnnotation
-  // truncateTrackAnnotation
 } from './utils/transformations'
 
 class TrackChangesProvider extends TOCProvider {
   constructor (document, config) {
     super(document, config)
-    // config.documentSession.on('didUpdate', this.handleUndoRedo, this)
+    // config.documentSession.on('didUpdate', handleUndoRedo, this)
 
     // handle button actions
     const editor = this.config.controller
@@ -75,7 +70,8 @@ class TrackChangesProvider extends TOCProvider {
   */
 
   handleTransaction (options) {
-    options.editorSession = this.getEditorSession()
+    // options.editor = this.config.controller
+    options.editorSession = this.config.editorSession
     options.selection = this.getSelection()
     options.surface = this.getSurface()
     options.user = this.config.user
@@ -89,15 +85,13 @@ class TrackChangesProvider extends TOCProvider {
   }
 
   handleAdd (options) {
-    const isSelectionCollapsed = this.isSelectionCollapsed()
+    const isCollapsed = isSelectionCollapsed(options)
 
-    if (isSelectionCollapsed) return this.handleAddCollapsed(options)
-    if (!isSelectionCollapsed) return this.handleAddNonCollapsed(options)
+    if (isCollapsed) return this.handleAddCollapsed(options)
+    if (!isCollapsed) return this.handleAddNonCollapsed(options)
   }
 
   handleAddCollapsed (options) {
-    // const { event } = options
-
     const notOnTrack = isNotOnTrackAnnotation(options)
     const isOnAdd = isOnAnnotation(options, 'add')
     const isOnDelete = isOnAnnotation(options, 'delete')
@@ -135,13 +129,13 @@ class TrackChangesProvider extends TOCProvider {
 
       const isOnLeftEdge = isSelectionOnLeftEdge(options, annotation)
       const isOnRightEdge = isSelectionOnRightEdge(options, annotation)
-      const withinAnnotation = this.isSelectionContainedWithin(annotation, true)
+      const withinAnnotation = isSelectionContainedWithin(options, annotation, true)
 
       // if contained within the delete annotation, move it to the edge,
       // insert character, set event to null so that the character does
       // not get inserted twice, and handle again
       if (withinAnnotation) {
-        this.moveCursorTo(annotation.endOffset)
+        moveCursorTo(options, annotation.end.offset)
         insertCharacterWithoutExpandingAnnotation(options, annotation)
         options.selection = this.getSelection()
         return this.handleAdd(options)
@@ -169,18 +163,17 @@ class TrackChangesProvider extends TOCProvider {
     const shortenBy = deleteAllOwnAdditions(options, selection)
     const startOffset = selection.start.offset
     const endOffset = selection.end.offset - shortenBy
-    selection = this.updateSelection(selection, startOffset, endOffset)
+    selection = updateSelection(options, selection, startOffset, endOffset)
     options.selection = selection
 
     if (isOnDelete) {
-      // console.log('on delete')
       const annotation = getAnnotationByStatus(options, 'delete')
-      const withinAnnotation = this.isSelectionContainedWithin(annotation)
+      const withinAnnotation = isSelectionContainedWithin(options, annotation)
 
       if (withinAnnotation) {
         // if selection is wholly contained within a delete annotation,
         // move to the end of the annotation and handle again
-        this.moveCursorTo(annotation.endOffset)
+        moveCursorTo(options, annotation.end.offset)
         options.selection = this.getSelection()
         return this.handleAddCollapsed(options)
       }
@@ -203,7 +196,7 @@ class TrackChangesProvider extends TOCProvider {
 
   handleDelete (options) {
     const { key, move } = options
-    const isSelectionCollapsed = this.isSelectionCollapsed()
+    const isCollapsed = isSelectionCollapsed(options)
 
     options.direction = {
       cursorTo: (move === 'left') ? 'start' : 'end',
@@ -211,8 +204,8 @@ class TrackChangesProvider extends TOCProvider {
       move: move
     }
 
-    if (isSelectionCollapsed) return this.handleDeleteCollapsed(options)
-    if (!isSelectionCollapsed) return this.handleDeleteNonCollapsed(options)
+    if (isCollapsed) return this.handleDeleteCollapsed(options)
+    if (!isCollapsed) return this.handleDeleteNonCollapsed(options)
   }
 
   handleDeleteCollapsed (options) {
@@ -273,7 +266,7 @@ class TrackChangesProvider extends TOCProvider {
       }
 
       if (moveOnly) {
-        return this.moveCursorTo(point)
+        return moveCursorTo(options, point)
       }
 
       if (isFromSameUser) {
@@ -298,35 +291,23 @@ class TrackChangesProvider extends TOCProvider {
     const startOffset = selection.start.offset
     const endOffset = selection.end.offset - shortenBy
 
-    this.updateSelection(selection, startOffset, endOffset)
+    updateSelection(options, selection, startOffset, endOffset)
 
     // TODO -- validate that this is not needed
     // if (selection.isCollapsed()) return this.handleDeleteCollapsed(options)
     if (selection.isCollapsed()) return
 
     if (isOnDelete) {
-      // console.log
       const annotation = getAnnotationByStatus(options, 'delete')
-      const containedWithin = this.isSelectionContainedWithin(annotation)
+      const containedWithin = isSelectionContainedWithin(options, annotation)
 
       if (containedWithin) {
         const point = annotation[direction.cursorTo + 'Offset']
-        return this.moveCursorTo(point)
+        return moveCursorTo(options, point)
       }
-
-      // const selection = this.getSelection()
-      // this.expandTrackAnnotation(selection, annotation)
-      //
-      // const key = direction.key
-      //
-      // let point
-      // if (key === 'BACKSPACE') point = selection.startOffset
-      // if (key === 'DELETE') point = selection.endOffset
-      // this.moveCursorTo(point)
     }
 
     options.selection = deleteOrMergeAllOwnDeletions(options, selection)
-    // console.log(this.getSelection())
     // options.selection = this.getSelection()
     markSelectionAsDeleted(options)
   }
@@ -422,7 +403,7 @@ class TrackChangesProvider extends TOCProvider {
     const selection = annotation.getSelection()
 
     surface.editorSession.setSelection(selection)
-    this.moveCursorTo('start')
+    moveCursorTo({ surface }, 'start')
   }
 
   canAct () {
@@ -431,121 +412,6 @@ class TrackChangesProvider extends TOCProvider {
     return some(accepted, (role) => includes(user.roles, role))
   }
 
-  /**
-
-    HISTORY HANDLERS
-
-  */
-
-  // TODO -- shouldn't run both all the time
-  handleUndoRedo (update, info) {
-    if (!info.replay) return
-    // console.log('update', update)
-    // console.log('info', info)
-    // this.handleUndo(update)
-    // this.handleRedo(update)
-  }
-
-  handleUndo (update) {
-    const deleted = update.change.deleted
-    const deletedLength = keys(deleted).length
-
-    // console.log(keys(deleted))
-
-    if (deletedLength === 0) return
-    if (deletedLength > 1) {
-      return console.warn('FIXME: Multiple operations in track changes replay!')
-    }
-
-    const deletedOp = deleted[keys(deleted)[0]]
-    if (!deletedOp.type === 'track-change') return
-
-    const documentSession = this.getEditorSession()
-    documentSession.undo()
-  }
-
-  handleRedo () {
-    // const documentSession = this.getEditorSession()
-    // const undoneChanges = documentSession.undoneChanges
-    // const lastChange = last(undoneChanges)
-    // const op = last(lastChange.ops)
-    //
-    // const isTrack = op.path[0].split('-').slice(0, -1).join('-') === 'track-change
-  }
-
-  /*
-
-    SELECTION HANDLERS
-
-  */
-
-  // isAnnotationContainedWithinSelection (annotation, strict) {
-  //   const selection = this.getSelection()
-  //   const annotationSelection = annotation.getSelection()
-  //
-  //   return selection.contains(annotationSelection, strict)
-  // }
-
-  isSelectionCollapsed () {
-    const selection = this.getSelection()
-    const isCollapsed = selection.isCollapsed()
-    return isCollapsed
-  }
-
-  // TODO -- refactor this and isAnnotationContainedWithinSelection into one
-  isSelectionContainedWithin (annotation, strict) {
-    const selection = this.getSelection()
-    // console.trace()
-    const annotationSelection = annotation.getSelection()
-
-    return annotationSelection.contains(selection, strict)
-
-    // const leftSide = (selection.startOffset < annotation.startOffset)
-    // const rightSide = (selection.endOffset > annotation.endOffset)
-    //
-    // if (leftSide || rightSide) return false
-    // return true
-  }
-
-  moveCursorTo (point, sel) {
-    const selection = sel || this.getSelection()
-    const surface = this.getSurface()
-
-    // TODO -- use substance's selection.collapse(direction)
-    if (point === 'start') {
-      selection.end.offset = selection.start.offset
-    } else if (point === 'end') {
-      selection.start.offset = selection.end.offset
-    } else {
-      selection.start.offset = point
-      selection.end.offset = point
-    }
-
-    surface.editorSession.setSelection(selection)
-  }
-
-  // setSelectionPlusOne (direction) {
-  //   const selection = this.getSelection()
-  //   const surface = this.getSurface()
-  //
-  //   if (direction === 'left') selection.start.offset -= 1
-  //   if (direction === 'right') selection.end.offset += 1
-  //
-  //   surface.editorSession.setSelection(selection)
-  //
-  //   return selection
-  // }
-
-  updateSelection (selection, startOffset, endOffset) {
-    const surface = this.getSurface()
-
-    selection.start.offset = startOffset
-    selection.end.offset = endOffset
-
-    surface.editorSession.setSelection(selection)
-    return selection
-  }
-
   /*
 
     GETTERS
@@ -556,14 +422,6 @@ class TrackChangesProvider extends TOCProvider {
     return this.config.commandManager
   }
 
-  getCurrentUser () {
-    return this.config.user.id
-  }
-
-  getEditorSession () {
-    return this.config.editorSession
-  }
-
   getMode () {
     const trackState = this.getTrackState()
     return trackState.mode
diff --git a/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js b/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js
index 92f5df3..fee91d6 100644
--- a/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js
+++ b/app/components/SimpleEditor/elements/track_change/utils/handlerHelpers.js
@@ -101,6 +101,8 @@ const deleteSelectedAndCreateAddition = (options) => {
 
   // selection is now collapsed, so handle it as collapsed
   options.status = 'add'
+  options.selection = getSelection(options.surface)
+
   const provider = getProvider(options)
   provider.handleAddCollapsed(options)
 }
@@ -132,18 +134,24 @@ const insertCharacterWithAddAnnotation = (options) => {
 }
 
 const insertCharacterWithoutExpandingAnnotation = (options, annotation) => {
+  // After text has been inserted, set the event to null to make sure it does
+  // not get added twice by a second iteration of the handlers.
+  // eg. if at the end of the logic path, handleAddCollapsed gets called
+  //     that will assume that there is text still to be inserted
   insertText(options)
+  options.event = null
 
-  options.selection = getSelection(options.surface)
-  options.selection = setSelectionPlusOne(options, 'left')
-  // options.selection = selection
-  options.annotation = annotation
-  options.doc = options.editorSession.getDocument()
+  // Clone the options, to make sure that the annotation or the selection
+  // does not change while the truncate operation is in progress.
+  const opts = clone(options)
 
-  truncateTrackAnnotation(options)
-  moveCursorTo(options, 'end')
+  opts.selection = getSelection(opts.surface)
+  opts.selection = setSelectionPlusOne(opts, 'left')
+  opts.annotation = annotation
+  opts.doc = opts.editorSession.getDocument()  // TODO -- should get from handler
 
-  options.event = null  // ?
+  truncateTrackAnnotation(opts)
+  moveCursorTo(opts, 'end')
 }
 
 const markSelectionAsDeleted = (options) => {
diff --git a/app/components/SimpleEditor/elements/track_change/utils/historyHandlers.js b/app/components/SimpleEditor/elements/track_change/utils/historyHandlers.js
new file mode 100644
index 0000000..0d0a353
--- /dev/null
+++ b/app/components/SimpleEditor/elements/track_change/utils/historyHandlers.js
@@ -0,0 +1,39 @@
+// TODO -- shouldn't run both all the time
+const handleUndoRedo = (update, info) => {
+  if (!info.replay) return
+  // console.log('update', update)
+  // console.log('info', info)
+  // this.handleUndo(update)
+  // this.handleRedo(update)
+}
+
+// const handleUndo = (update) => {
+//   const deleted = update.change.deleted
+//   const deletedLength = keys(deleted).length
+//
+//   // console.log(keys(deleted))
+//
+//   if (deletedLength === 0) return
+//   if (deletedLength > 1) {
+//     return console.warn('FIXME: Multiple operations in track changes replay!')
+//   }
+//
+//   const deletedOp = deleted[keys(deleted)[0]]
+//   if (!deletedOp.type === 'track-change') return
+//
+//   const documentSession = this.getEditorSession()
+//   documentSession.undo()
+// }
+
+// const handleRedo = () => {
+//   // const documentSession = this.getEditorSession()
+//   // const undoneChanges = documentSession.undoneChanges
+//   // const lastChange = last(undoneChanges)
+//   // const op = last(lastChange.ops)
+//   //
+//   // const isTrack = op.path[0].split('-').slice(0, -1).join('-') === 'track-change
+// }
+
+export {
+  handleUndoRedo
+}
diff --git a/app/components/SimpleEditor/elements/track_change/utils/selectionHelpers.js b/app/components/SimpleEditor/elements/track_change/utils/selectionHelpers.js
index d803aad..0923d05 100644
--- a/app/components/SimpleEditor/elements/track_change/utils/selectionHelpers.js
+++ b/app/components/SimpleEditor/elements/track_change/utils/selectionHelpers.js
@@ -2,9 +2,34 @@ const getSelection = (surface) => {
   return surface.domSelection.getSelection()
 }
 
+const isSelectionCollapsed = (options) => {
+  // const selection = this.getSelection()
+  const { selection } = options
+  const isCollapsed = selection.isCollapsed()
+  return isCollapsed
+}
+
+// TODO -- refactor this and isAnnotationContainedWithinSelection into one
+const isSelectionContainedWithin = (options, annotation, strict) => {
+  // const selection = this.getSelection()
+  const selection = getSelection(options.surface)
+
+  const annotationSelection = annotation.getSelection()
+
+  return annotationSelection.contains(selection, strict)
+
+  // const leftSide = (selection.startOffset < annotation.startOffset)
+  // const rightSide = (selection.endOffset > annotation.endOffset)
+  //
+  // if (leftSide || rightSide) return false
+  // return true
+}
+
 const moveCursorTo = (options, point) => {
   // const selection = sel || this.getSelection()
-  const { selection, surface } = options
+  // const { selection, surface } = options
+  const { surface } = options
+  const selection = getSelection(surface)
   // const surface = this.getSurface()
 
   // TODO -- use substance's selection.collapse(direction)
@@ -32,8 +57,21 @@ const setSelectionPlusOne = (options, direction) => {
   return selection
 }
 
+const updateSelection = (options, selection, startOffset, endOffset) => {
+  const { surface } = options
+
+  selection.start.offset = startOffset
+  selection.end.offset = endOffset
+
+  surface.editorSession.setSelection(selection)
+  return selection
+}
+
 export {
   getSelection,
+  isSelectionCollapsed,
+  isSelectionContainedWithin,
   moveCursorTo,
-  setSelectionPlusOne
+  setSelectionPlusOne,
+  updateSelection
 }
diff --git a/app/components/SimpleEditor/elements/track_change/utils/transformations.js b/app/components/SimpleEditor/elements/track_change/utils/transformations.js
index 1d44240..abf3dd9 100644
--- a/app/components/SimpleEditor/elements/track_change/utils/transformations.js
+++ b/app/components/SimpleEditor/elements/track_change/utils/transformations.js
@@ -125,6 +125,7 @@ const truncateTrackAnnotation = options => {
   const info = getInfo()
 
   const transformation = (tx, args) => {
+    // console.log(selection)
     annotationHelpers.truncateAnnotation(doc, annotation, selection)
   }
 
-- 
GitLab