diff --git a/app/components/SimpleEditor/Editor.js b/app/components/SimpleEditor/Editor.js index 9971c59abbceb84e1b014c7bb5981e886feefe09..d5395adde78d25007712e3c82b72711ba1dad679 100644 --- a/app/components/SimpleEditor/Editor.js +++ b/app/components/SimpleEditor/Editor.js @@ -35,7 +35,6 @@ class Editor extends ProseEditor { this.props.updateTrackChangesStatus(!this.props.trackChanges) this.extendState({ trackChanges: !this.props.trackChanges }) - console.log(this.el) } updateTrackChangeView () { @@ -178,9 +177,10 @@ class Editor extends ProseEditor { // TODO -- do I need all of these? // track changes provider - const trackChangesProvider = new TrackChangesProvider({ + const trackChangesProvider = new TrackChangesProvider(doc, { commandManager: this.commandManager, containerId: this.props.containerId, + controller: this, documentSession: this.documentSession, surfaceManager: this.surfaceManager, user: this.props.user diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js b/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js index 9ba3c897e1f8ccfda6ffda8334bcacf97e1a0e05..763c6fada7662f44f802383ab03fcd89ac027a41 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangeComponent.js @@ -1,18 +1,17 @@ -import { pickBy, clone, map, sortBy, findIndex } from 'lodash' -import { AnnotationComponent, createAnnotation, deleteNode } from 'substance' +import { AnnotationComponent } from 'substance' class TrackChangeComponent extends AnnotationComponent { render ($$) { - const { status } = this.props.node - const trackChangesView = this.toggleTrackChangeView() + const { id, status } = this.props.node + const trackChangesView = this.context.controller.state.trackChangesView const accept = $$('a') .addClass('sc-track-item-accept') - .on('click', this.acceptTrackChange) + .on('click', this.accept) const reject = $$('a') .addClass('sc-track-item-reject') - .on('click', this.rejectTrackChange) + .on('click', this.reject) const separator = $$('span') .addClass('sc-track-item-separator') @@ -24,6 +23,7 @@ class TrackChangeComponent extends AnnotationComponent { .append(reject) let el = $$('span') + .attr('data-id', id) .addClass(this.getClassNames()) .append(this.props.children) .append(container) @@ -41,133 +41,23 @@ class TrackChangeComponent extends AnnotationComponent { return el } - // TODO -- Move most of the funcs into provider - getSurface () { - const surfaceManager = this.context.surfaceManager - const containerId = this.context.controller.props.containerId - - return surfaceManager.getSurface(containerId) - } - - toggleTrackChangeView () { - const self = this - const surface = self.getSurface() - - if (!surface) return - return surface._owner.state.trackChangesView - } - - acceptTrackChange () { - const nodeId = this.props.node.id - const status = this.props.node.status - const ds = this.getDocumentSession() - const doc = ds.getDocument() - const nodeData = this.buildNodeData(nodeId) - const nextNodeId = this.findNextTrackNode(nodeId) - var self = this - ds.transaction(function (tx, args) { - if (status === 'add') createAnnotation(doc, nodeData) - deleteNode(tx, { nodeId: nodeId }) - if (status === 'delete') self.context.surface.delete(tx, nodeData) - }) - if (nextNodeId) { - this.focusToNext(nextNodeId) - } - } - - rejectTrackChange () { - const nodeId = this.props.node.id - const status = this.props.node.status - const ds = this.getDocumentSession() - const doc = ds.getDocument() - const nodeData = this.buildNodeData(nodeId) - const nextNodeId = this.findNextTrackNode(nodeId) - var self = this - ds.transaction(function (tx, args) { - if (status === 'delete') createAnnotation(doc, nodeData) - deleteNode(tx, { nodeId: nodeId }) - if (status === 'add') self.context.surface.delete(tx, nodeData) - }) - - if (nextNodeId) { - this.focusToNext(nextNodeId) - } + accept () { + this.resolve('accept') } - buildNodeData (nodeId) { - const ds = this.getDocumentSession() - const doc = ds.getDocument() - const trackChangeNode = doc.get(nodeId) - - const path = trackChangeNode.path - const startOffset = trackChangeNode.startOffset - const endOffset = trackChangeNode.endOffset - - const sel = ds.createSelection(path, startOffset, endOffset) - - return { - selection: sel, - node: { type: 'paragraph' } - } + reject () { + this.resolve('reject') } - findNextTrackNode (currentNodeId) { - const ds = this.getDocumentSession() - let doc = ds.getDocument() - let documentNodes = doc.getNodes() - const trackChanges = pickBy(documentNodes, function (value, key) { - return value.type === 'track-change' - }) - - // return entries sorted in document - const entries = this.sortNodes(trackChanges) - - // find index in Array of resolved track Change - const index = findIndex(entries, function (entry) { - return entry.id === currentNodeId - }) - - const nextIndex = index + 1 - - // If next index exist move to that else move to first - if (entries[nextIndex]) { - return entries[nextIndex].id - } else if (entries.length > 0) { - return entries[0].id - } - return - } - - focusToNext (nextNodeId) { - const nextNodeData = this.buildNodeData(nextNodeId) - this.context.surface.setSelection(nextNodeData.selection) - this.context.controller.scrollTo(nextNodeId) - } + resolve (action) { + const annotation = this.props.node + const provider = this.getProvider() - sortNodes (nodes) { - let trackChanges = clone(nodes) - const ds = this.getDocumentSession() - let doc = ds.getDocument() - const container = doc.get('body') - - trackChanges = map(trackChanges, function (trackChange) { - const blockId = trackChange.path[0] - const blockPosition = container.getPosition(blockId) - const nodePosition = trackChange.startOffset - - return { - id: trackChange.id, - blockPosition: blockPosition, - nodePosition: nodePosition, - node: trackChange - } - }) - - return sortBy(trackChanges, ['blockPosition', 'nodePosition']) + provider.resolve(annotation, action) } - getDocumentSession () { - return this.context.documentSession + getProvider () { + return this.context.trackChangesProvider } } diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index 7909693c26855dbd058e77d2868cccdd46a63ae9..4ab5116cdfca24bd552ef0f49f28fcaa0ae3fdc4 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -3,10 +3,14 @@ import { each, filter, find, + findIndex, keys, last, + map, maxBy, - minBy + minBy, + pickBy, + sortBy } from 'lodash' import { @@ -15,13 +19,17 @@ import { deleteNode, deleteSelection as deleteSel, expandAnnotation, - truncateAnnotation + truncateAnnotation, + TOCProvider } from 'substance' -class TrackChangesProvider { - constructor (config) { - this.config = config - this.config.documentSession.on('didUpdate', this.handleUndoRedo, this) +class TrackChangesProvider extends TOCProvider { + constructor (document, config) { + super(document, config) + config.documentSession.on('didUpdate', this.handleUndoRedo, this) + + // HACK -- use TOCProvider's event to capture new / deleted changes + this.on('toc:updated', this.reComputeEntries, this) } /* @@ -514,6 +522,90 @@ class TrackChangesProvider { surface.transaction(transformation, info) } + /* + + ACCEPT / REJECT + + */ + + resolve (annotation, action) { + const next = this.getNext(annotation) + const selection = annotation.getSelection() + const status = annotation.status + + this.removeTrackAnnotation(annotation) + + if ( + (action === 'accept' && status === 'delete') || + (action === 'reject' && status === 'add') + ) { + this.deleteSelection(selection) + } + + this.focus(next) + } + + computeEntries () { + let doc = this.getDocument() + let nodes = doc.getNodes() + + let changes = pickBy(nodes, node => { + return node.type === 'track-change' + }) + + let entries = this.sortNodes(changes) + return entries + } + + reComputeEntries () { + this.entries = this.computeEntries() + } + + sortNodes (nodes) { + const changes = clone(nodes) + const doc = this.getDocument() + const container = doc.get('body') + + const changesArray = map(changes, annotation => { + const blockId = annotation.path[0] + const blockPosition = container.getPosition(blockId) + const nodePosition = annotation.startOffset + + return { + id: annotation.id, + blockPosition: blockPosition, + nodePosition: nodePosition, + node: annotation + } + }) + + return sortBy(changesArray, ['blockPosition', 'nodePosition']) + } + + getNext (annotation) { + const entries = this.entries + if (entries.length <= 1) return + + const position = findIndex(entries, change => { + return change.node.id === annotation.id + }) + if (position === -1) return + const next = position + 1 + + if (next >= entries.length) return entries[0].node + return entries[next].node + } + + focus (annotation) { + if (!annotation) return + const surface = this.getSurface() + const { controller } = this.config + + controller.scrollTo(annotation.id) + annotation.endOffset = annotation.startOffset + surface.setSelection(annotation.getSelection()) + } + /* ANNOTATION HELPERS @@ -760,4 +852,6 @@ class TrackChangesProvider { } } +TOCProvider.tocTypes = ['track-change'] + export default TrackChangesProvider