From ab5dec661e212e8742f9ac211f32721bc473fd47 Mon Sep 17 00:00:00 2001
From: john <johnbarlas39@gmail.com>
Date: Fri, 30 Dec 2016 00:25:11 +0200
Subject: [PATCH] add and delete refactored

---
 .../SimpleEditor/ContainerEditor.js           |  69 +---
 .../track_change/TrackChangesProvider.js      | 340 ++++++++++++++----
 2 files changed, 280 insertions(+), 129 deletions(-)

diff --git a/app/components/SimpleEditor/ContainerEditor.js b/app/components/SimpleEditor/ContainerEditor.js
index 8d5ccc2..4eb554e 100644
--- a/app/components/SimpleEditor/ContainerEditor.js
+++ b/app/components/SimpleEditor/ContainerEditor.js
@@ -73,72 +73,39 @@ class ContainerEditor extends SubstanceContainerEditor {
   }
 
   onTextInput (event) {
-    // console.log(this.context)
+    if (!this.props.trackChanges) return super.onTextInput(event)
+
     event.preventDefault()
     event.stopPropagation()
 
     if (!event.data) return
     this._state.skipNextObservation = true
 
-    if (!this.props.trackChanges) {
-      this.transaction(function (tx, args) {
-        if (this.domSelection) this.domSelection.clear()
-        args.text = event.data
-        return this.insertText(tx, args)
-      }.bind(this), { action: 'type' })
-      return
-    }
-
     const trackChangesProvider = this.context.trackChangesProvider
-    const status = 'add'
-    trackChangesProvider.handleTransaction(event, status)
-
-    // const isSelCollapsed = this.getSelection().isCollapsed()
-    // if (!isSelCollapsed) {
-    //   const trackChangesProvider = this.context.trackChangesProvider
-    //   const status = 'delete'
-    //   trackChangesProvider.handleTransaction(status)
-    // }
-    //
-    // this.transaction(function (tx, args) {
-    //   if (this.domSelection) this.domSelection.clear()
-    //   args.text = event.data
-    //   return this.insertText(tx, args)
-    // }.bind(this), { action: 'type' })
-    //
-    // // don't rewrite the above, call it with super
-    // if (this.props.trackChanges) {
-    //   const status = 'add'
-    //   trackChangesProvider.handleTransaction(status)
-    // }
+    const options = {
+      event: event,
+      status: 'add'
+    }
+    trackChangesProvider.handleTransaction(options)
   }
 
   _handleDeleteKey (event) {
+    if (!this.props.trackChanges) return super._handleDeleteKey(event)
+
     event.preventDefault()
     event.stopPropagation()
-    let direction = (event.keyCode === keys.BACKSPACE) ? 'left' : 'right'
-
-    if (this.props.trackChanges) {
-      const trackChangesProvider = this.context.trackChangesProvider
-      const status = 'delete'
-      trackChangesProvider.handleTransaction(event, status, direction)
-    } else {
-      this.transaction(function (tx, args) {
-        args.direction = direction
-        return this.delete(tx, args)
-      }.bind(this), { action: 'delete' })
+
+    // TODO -- needed?
+    const direction = (event.keyCode === keys.BACKSPACE) ? 'left' : 'right'
+
+    const trackChangesProvider = this.context.trackChangesProvider
+    const options = {
+      direction: direction,
+      status: 'delete'
     }
+    trackChangesProvider.handleTransaction(options)
   }
 
-  // delete (tx, args) {
-  //   let sel = args.selection
-  //   if (!sel.isCollapsed()) {
-  //     return deleteSelection(tx, args)
-  //   } else if (sel.isPropertySelection() || sel.isNodeSelection()) {
-  //     return deleteCharacter(tx, args)
-  //   }
-  // }
-
   // create an empty paragraph with an empty node
   // then select it for cursor focus
   createText () {
diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
index 4325616..032bd81 100644
--- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
+++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js
@@ -1,5 +1,15 @@
-import { keys, last } from 'lodash'
-import { createAnnotation, expandAnnotation } from 'substance'
+import {
+  filter,
+  find,
+  keys,
+  last
+} from 'lodash'
+
+import {
+  createAnnotation,
+  expandAnnotation,
+  truncateAnnotation
+} from 'substance'
 
 class TrackChangesProvider {
   constructor (config) {
@@ -7,22 +17,94 @@ class TrackChangesProvider {
     this.config.documentSession.on('didUpdate', this.handleUndoRedo, this)
   }
 
-  handleTransaction (event, status) {
-    if (status === 'add') {
-      const isSelCollapsed = this.isSelectionCollapsed()
-      if (!isSelCollapsed) {
-        const options = { 'deleteCollapsed': true }
-        this.createDeletionAnnotation(options)
-      }
+  handleTransaction (options) {
+    // const status = options.status
+
+    this.handleAdd(options)
+    this.handleDelete(options)
+    // if (this.shouldDelete(status)) this.delete()
+  }
+
+  handleAdd (options) {
+    const { event, status } = options
+    if (status !== 'add') return
+
+    const isSelectionCollapsed = this.isSelectionCollapsed()
+    const mode = this.getMode()
+
+    let selection
+
+    if (isSelectionCollapsed) {
       this.insertText(event)
-      this.createAdditionAnnotation()
+      if (mode) return
+      selection = this.setSelectionPlusOne('left')
+      this.createAddAnnotation(selection)
+      this.moveCursorTo('end')
       return
     }
+  }
+
+  handleDelete (options) {
+    const { status } = options
+    if (status !== 'delete') return
 
-    if (status === 'delete') {
-      this.createDeletionAnnotation()
+    const mode = this.getMode()
+    let selection
+
+    if (!mode) {
+      selection = this.setSelectionPlusOne('left')
+      this.createDeleteAnnotation(selection)
+      this.moveCursorTo('start')
       return
     }
+    if (mode === 'delete') {
+      selection = this.setSelectionPlusOne('left')
+      const annotation = this.getAnnotationByStatus('delete')
+      this.expandTrackAnnotation(selection, annotation)
+      this.moveCursorTo('start')
+    }
+
+    // const isSelectionCollapsed = this.isSelectionCollapsed()
+
+    // if (!this.isSelectionCollapsed()) options.deleteCollapsed = true
+    // this.createDeletionAnnotation(options)
+  }
+
+  // expand annotation
+  // truncate annotation
+
+  createAddAnnotation (selection) {
+    this.createTrackAnnotation(selection, 'add')
+  }
+
+  createDeleteAnnotation (selection) {
+    this.createTrackAnnotation(selection, 'delete')
+  }
+
+  createTrackAnnotation (selection, status) {
+    const surface = this.getSurface()
+
+    surface.transaction((tx, args) => {
+      const newNode = {
+        selection: selection,
+        node: {
+          status: status,
+          type: 'track-change'
+        }
+      }
+      createAnnotation(tx, newNode)
+    })
+  }
+
+  expandTrackAnnotation (selection, annotation) {
+    const surface = this.getSurface()
+
+    surface.transaction((tx, args) => {
+      args.selection = selection
+      args.anno = annotation
+
+      expandAnnotation(tx, args)
+    })
   }
 
   insertText (event) {
@@ -34,15 +116,13 @@ class TrackChangesProvider {
     }, { action: 'type' })
   }
 
-  onDeleteAnnotation () {
-    const anno = this.getExistingAnnotation()
-    const isDelete = (anno.status === 'delete')
-    return isDelete
-  }
-
   createAdditionAnnotation () {
     const mode = this.getMode()
-    const onDelete = this.onDeleteAnnotation()
+    const onDelete = this.isOnAnnotation('delete')
+    // const onAdd = this.isOnAnnotation('add')
+    // console.log('mode', mode)
+    // console.log('on delete', onDelete)
+    // console.log('on add', onAdd)
     if (mode && !onDelete) return
 
     const surface = this.getSurface()
@@ -65,54 +145,34 @@ class TrackChangesProvider {
     const info = {}
     surface.transaction(transformation, info)
 
-    surface.transaction((tx, args) => {
-      if (onDelete) {
-        // console.log(this.getAllExistingAnnotations())
-        const annos = this.getAllExistingAnnotations()
-        const deleteAnno = annos.find((obj) => {
-          // console.log(obj)
-          return obj.type === 'track-change' && obj.status === 'delete'
-        })
-        const addAnno = annos.find((obj) => {
-          // console.log(obj)
-          return obj.type === 'track-change' && obj.status === 'add'
-        })
-        // console.log(deleteAnno)
-        deleteAnno.updateRange(tx, {
-          start: {
-            startPath: deleteAnno.startPath,
-            offset: deleteAnno.startOffset
-          },
-          end: {
-            offset: addAnno.startOffset
-          }
-        })
-        // deleteAnno.endOffset = addAnno.startOffset
-        // console.log(deleteAnno)
-      }
-    })
-  }
+    if (onDelete) {
+      this.separateAnnotations()
+    }
 
-  getExistingAnnotation () {
-    const documentSession = this.getDocumentSession()
-    const selectionState = documentSession.getSelectionState()
-    const annotations = selectionState.getAnnotationsForType('track-change')
-    return annotations[0]
+    // if (onAdd) {
+    //
+    // }
   }
 
-  getAllExistingAnnotations () {
-    const documentSession = this.getDocumentSession()
-    const selectionState = documentSession.getSelectionState()
-    const annotations = selectionState.getAnnotationsForType('track-change')
-    return annotations
+  separateAnnotations () {
+    console.log('separate')
+    const surface = this.getSurface()
+    const deleteAnnotation = this.getAnnotationByStatus('delete')
+    const addAnnotation = this.getAnnotationByStatus('add')
+    console.log('delete anno', deleteAnnotation)
+    console.log('add anno', addAnnotation)
+
+    surface.transaction((tx, args) => {
+      args.anno = deleteAnnotation
+      args.selection = addAnnotation.getSelection()
+      truncateAnnotation(tx, args)
+    })
   }
 
   createDeletionAnnotation (options) {
-    let deleteCollapsed
-    if (options && options.deleteCollapsed) deleteCollapsed = true
-
-    const surface = this.getSurface()
+    const deleteCollapsed = options.deleteCollapsed
     const mode = this.getMode()
+    const surface = this.getSurface()
 
     const transformation = (tx, args) => {
       let selection = args.selection
@@ -141,13 +201,90 @@ class TrackChangesProvider {
     surface.transaction(transformation, info)
   }
 
-  isSelectionCollapsed () {
-    const surface = this.getSurface()
-    const selection = surface.getSelection()
-    const isCollapsed = selection.isCollapsed()
-    return isCollapsed
+  /*
+
+    DECISION MAKERS
+
+  */
+
+  shouldAdd (status) {
+    if (status !== 'add') return false
+
+    const mode = this.getMode()
+    if (mode) return false
+
+    return true
   }
 
+  shouldDelete (status) {
+    if (status === 'delete') return true
+
+    console.log(status)
+    console.log(this.isSelectionCollapsed())
+    if (status === 'create' && !this.isSelectionCollapsed()) return true
+    return false
+  }
+
+  // shouldExpand () {
+  //
+  // }
+
+  // shouldTruncate () {
+  //
+  // }
+
+  /*
+
+    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) {
+    const annotations = this.getAllExistingTrackAnnotations()
+    console.log('annos', annotations)
+    const annos = filter(annotations, (annotation) => {
+      return annotation.status === status
+    })
+    return annos[0]
+  }
+
+  getExistingAnnotation () {
+    const documentSession = this.getDocumentSession()
+    const selectionState = documentSession.getSelectionState()
+    const annotations = selectionState.getAnnotationsForType('track-change')
+    console.log(annotations)
+    return annotations[0]
+  }
+
+  getAllExistingTrackAnnotations () {
+    const documentSession = this.getDocumentSession()
+    const selectionState = documentSession.getSelectionState()
+    const annotations = selectionState.getAnnotationsForType('track-change')
+    return annotations
+  }
+
+  // returns whether the selection is on an add / delete tracked change
+  isOnAnnotation (status) {
+    const annotations = this.getAllExistingTrackAnnotations()
+    const annotation = find(annotations, (annotation) => {
+      return annotation.status === status
+    })
+
+    if (!annotation) return false
+    return true
+  }
+
+  /**
+
+    HISTORY HANDLERS
+
+  */
+
   // TODO -- shouldn't run both all the time
   handleUndoRedo (update, info) {
     if (!info.replay) return
@@ -185,14 +322,40 @@ class TrackChangesProvider {
     console.log(isTrack)
   }
 
-  // removeAnnotationFromHistory () {
-  //   const documentSession = this.getDocumentSession()
-  //   // console.log(documentSession.doneChanges)
-  //   setTimeout(() => {
-  //     console.log(documentSession.doneChanges[1].toJSON())
-  //     // documentSession.doneChanges.pop()
-  //   }) // ensure that text insertion has finished
-  // }
+  /*
+
+    SELECTION HANDLERS
+
+  */
+
+  // get delete direction
+  // is part of the selection outside the annotation
+  // move cursor to
+
+  setSelectionPlusOne (direction) {
+    const selection = this.getSelection()
+
+    if (direction === 'left') selection.startOffset -= 1
+    if (direction === 'right') selection.endOffset += 1
+
+    return selection
+  }
+
+  moveCursorTo (point) {
+    const selection = this.getSelection()
+    const surface = this.getSurface()
+
+    if (point === 'start') {
+      selection.endOffset = selection.startOffset
+    } else if (point === 'end') {
+      selection.startOffset = selection.endOffset
+    } else {
+      selection.startOffset = point
+      selection.endOffset = point
+    }
+
+    surface.setSelection(selection)
+  }
 
   clearSelection (args, status) {
     const selection = args.selection
@@ -213,14 +376,29 @@ class TrackChangesProvider {
     return selection
   }
 
+  isSelectionCollapsed () {
+    const selection = this.getSelection()
+    const isCollapsed = selection.isCollapsed()
+    return isCollapsed
+  }
+
+  /*
+
+    GETTERS
+
+  */
+
   getCommandManager () {
     return this.config.commandManager
   }
 
-  getTrackState () {
+  getCommandStates () {
     const commandManager = this.getCommandManager()
-    const commandStates = commandManager.getCommandStates()
-    return commandStates['track-change']
+    return commandManager.getCommandStates()
+  }
+
+  getDocumentSession () {
+    return this.config.documentSession
   }
 
   getMode () {
@@ -228,8 +406,9 @@ class TrackChangesProvider {
     return state.mode
   }
 
-  getDocumentSession () {
-    return this.config.documentSession
+  getSelection () {
+    const surface = this.getSurface()
+    return surface.getSelection()
   }
 
   getSurface () {
@@ -238,6 +417,11 @@ class TrackChangesProvider {
 
     return surfaceManager.getSurface(id)
   }
+
+  getTrackState () {
+    const commandStates = this.getCommandStates()
+    return commandStates['track-change']
+  }
 }
 
 export default TrackChangesProvider
-- 
GitLab