mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Refactor ops model so it all happens in Document
This commit is contained in:
parent
0a6a6c3c28
commit
898277b4af
8 changed files with 115 additions and 74 deletions
|
@ -53,7 +53,6 @@ div.full-size(
|
||||||
events-bridge="reviewPanelEventsBridge"
|
events-bridge="reviewPanelEventsBridge"
|
||||||
track-changes-enabled="trackChangesFeatureFlag",
|
track-changes-enabled="trackChangesFeatureFlag",
|
||||||
track-changes= "editor.trackChanges",
|
track-changes= "editor.trackChanges",
|
||||||
ranges-tracker="reviewPanel.rangesTracker",
|
|
||||||
doc-id="editor.open_doc_id"
|
doc-id="editor.open_doc_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
define [
|
define [
|
||||||
"utils/EventEmitter"
|
"utils/EventEmitter"
|
||||||
"ide/editor/ShareJsDoc"
|
"ide/editor/ShareJsDoc"
|
||||||
], (EventEmitter, ShareJsDoc) ->
|
"ide/review-panel/RangesTracker"
|
||||||
|
], (EventEmitter, ShareJsDoc, RangesTracker) ->
|
||||||
class Document extends EventEmitter
|
class Document extends EventEmitter
|
||||||
@getDocument: (ide, doc_id) ->
|
@getDocument: (ide, doc_id) ->
|
||||||
@openDocs ||= {}
|
@openDocs ||= {}
|
||||||
|
@ -247,14 +248,15 @@ define [
|
||||||
@joined = true
|
@joined = true
|
||||||
@doc.catchUp( updates )
|
@doc.catchUp( updates )
|
||||||
# TODO: Worry about whether these ranges are consistent with the doc still
|
# TODO: Worry about whether these ranges are consistent with the doc still
|
||||||
@opening_ranges = ranges
|
@ranges?.changes = ranges?.changes
|
||||||
|
@ranges?.comments = ranges?.comments
|
||||||
callback()
|
callback()
|
||||||
else
|
else
|
||||||
@ide.socket.emit 'joinDoc', @doc_id, (error, docLines, version, updates, ranges) =>
|
@ide.socket.emit 'joinDoc', @doc_id, (error, docLines, version, updates, ranges) =>
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
@joined = true
|
@joined = true
|
||||||
@doc = new ShareJsDoc @doc_id, docLines, version, @ide.socket
|
@doc = new ShareJsDoc @doc_id, docLines, version, @ide.socket
|
||||||
@opening_ranges = ranges
|
@ranges = new RangesTracker(ranges?.changes, ranges?.comments)
|
||||||
@_bindToShareJsDocEvents()
|
@_bindToShareJsDocEvents()
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
@ -313,6 +315,8 @@ define [
|
||||||
inflightOp: inflightOp,
|
inflightOp: inflightOp,
|
||||||
pendingOp: pendingOp
|
pendingOp: pendingOp
|
||||||
v: version
|
v: version
|
||||||
|
@doc.on "change", (ops, oldSnapshot, msg) =>
|
||||||
|
@_applyOpsToRanges(ops, oldSnapshot, msg)
|
||||||
|
|
||||||
_onError: (error, meta = {}) ->
|
_onError: (error, meta = {}) ->
|
||||||
meta.doc_id = @doc_id
|
meta.doc_id = @doc_id
|
||||||
|
@ -325,3 +329,16 @@ define [
|
||||||
# the disconnect event, which means we try to leaveDoc when the connection comes back.
|
# the disconnect event, which means we try to leaveDoc when the connection comes back.
|
||||||
# This could intefere with the new connection of a new instance of this document.
|
# This could intefere with the new connection of a new instance of this document.
|
||||||
@_cleanUp()
|
@_cleanUp()
|
||||||
|
|
||||||
|
_applyOpsToRanges: (ops = [], oldSnapshot, msg) ->
|
||||||
|
track_changes_as = null
|
||||||
|
remote_op = msg?
|
||||||
|
if remote_op and msg.meta?.tc
|
||||||
|
track_changes_as = msg.meta.user_id
|
||||||
|
else if !remote_op and @track_changes_as?
|
||||||
|
track_changes_as = @track_changes_as
|
||||||
|
console.log "CHANGED", oldSnapshot, ops, track_changes_as
|
||||||
|
@ranges.track_changes = track_changes_as?
|
||||||
|
for op in ops
|
||||||
|
console.log "APPLYING OP", op, @ranges.track_changes
|
||||||
|
@ranges.applyOp op, { user_id: track_changes_as }
|
||||||
|
|
|
@ -34,8 +34,8 @@ define [
|
||||||
@_doc = new ShareJs.Doc @connection, @doc_id,
|
@_doc = new ShareJs.Doc @connection, @doc_id,
|
||||||
type: @type
|
type: @type
|
||||||
@_doc.setFlushDelay(SINGLE_USER_FLUSH_DELAY)
|
@_doc.setFlushDelay(SINGLE_USER_FLUSH_DELAY)
|
||||||
@_doc.on "change", () =>
|
@_doc.on "change", (args...) =>
|
||||||
@trigger "change"
|
@trigger "change", args...
|
||||||
@_doc.on "acknowledge", () =>
|
@_doc.on "acknowledge", () =>
|
||||||
@lastAcked = new Date() # note time of last ack from server for an op we sent
|
@lastAcked = new Date() # note time of last ack from server for an op we sent
|
||||||
@trigger "acknowledge"
|
@trigger "acknowledge"
|
||||||
|
|
|
@ -56,7 +56,6 @@ define [
|
||||||
eventsBridge: "="
|
eventsBridge: "="
|
||||||
trackChanges: "="
|
trackChanges: "="
|
||||||
trackChangesEnabled: "="
|
trackChangesEnabled: "="
|
||||||
rangesTracker: "="
|
|
||||||
docId: "="
|
docId: "="
|
||||||
}
|
}
|
||||||
link: (scope, element, attrs) ->
|
link: (scope, element, attrs) ->
|
||||||
|
|
|
@ -10,22 +10,15 @@ define [
|
||||||
constructor: (@$scope, @editor, @element) ->
|
constructor: (@$scope, @editor, @element) ->
|
||||||
window.trackChangesManager ?= @
|
window.trackChangesManager ?= @
|
||||||
|
|
||||||
@$scope.$watch "rangesTracker", (rangesTracker) =>
|
|
||||||
return if !rangesTracker?
|
|
||||||
@disconnectFromRangesTracker()
|
|
||||||
@rangesTracker = rangesTracker
|
|
||||||
@connectToRangesTracker()
|
|
||||||
|
|
||||||
@$scope.$watch "trackChanges", (track_changes) =>
|
@$scope.$watch "trackChanges", (track_changes) =>
|
||||||
return if !track_changes?
|
return if !track_changes?
|
||||||
@rangesTracker?.track_changes = track_changes
|
@setTrackChanges(track_changes)
|
||||||
|
|
||||||
@$scope.$watch "sharejsDoc", (doc) =>
|
@$scope.$watch "sharejsDoc", (doc) =>
|
||||||
return if !doc?
|
return if !doc?
|
||||||
if doc.opening_ranges?.changes?
|
@disconnectFromRangesTracker()
|
||||||
@rangesTracker.changes = doc.opening_ranges.changes
|
@rangesTracker = doc.ranges
|
||||||
if doc.opening_ranges?.comments?
|
@connectToRangesTracker()
|
||||||
@rangesTracker.comments = doc.opening_ranges.comments
|
|
||||||
|
|
||||||
@$scope.$on "comment:add", (e, comment) =>
|
@$scope.$on "comment:add", (e, comment) =>
|
||||||
@addCommentToSelection(comment)
|
@addCommentToSelection(comment)
|
||||||
|
@ -65,48 +58,15 @@ define [
|
||||||
onResize = () =>
|
onResize = () =>
|
||||||
@recalculateReviewEntriesScreenPositions()
|
@recalculateReviewEntriesScreenPositions()
|
||||||
|
|
||||||
onChange = (e) =>
|
|
||||||
if !@editor.initing
|
|
||||||
# This change is trigger by a sharejs 'change' event, which is before the
|
|
||||||
# sharejs 'remoteop' event. So wait until the next event loop when the 'remoteop'
|
|
||||||
# will have fired, before we decide if it was a remote op.
|
|
||||||
setTimeout () =>
|
|
||||||
if @nextUpdateMetaData?
|
|
||||||
user_id = @nextUpdateMetaData.user_id
|
|
||||||
# The remote op may have contained multiple atomic ops, each of which is an Ace
|
|
||||||
# 'change' event (i.e. bulk commenting out of lines is a single remote op
|
|
||||||
# but gives us one event for each % inserted). These all come in a single event loop
|
|
||||||
# though, so wait until the next one before clearing the metadata.
|
|
||||||
setTimeout () =>
|
|
||||||
@nextUpdateMetaData = null
|
|
||||||
else
|
|
||||||
user_id = window.user.id
|
|
||||||
|
|
||||||
was_tracking = @rangesTracker.track_changes
|
|
||||||
if @dont_track_next_update
|
|
||||||
@rangesTracker.track_changes = false
|
|
||||||
@dont_track_next_update = false
|
|
||||||
@applyChange(e, { user_id })
|
|
||||||
@rangesTracker.track_changes = was_tracking
|
|
||||||
|
|
||||||
# TODO: Just for debugging, remove before going live.
|
|
||||||
setTimeout () =>
|
|
||||||
@checkMapping()
|
|
||||||
, 100
|
|
||||||
|
|
||||||
onChangeSession = (e) =>
|
onChangeSession = (e) =>
|
||||||
e.oldSession?.getDocument().off "change", onChange
|
|
||||||
e.session.getDocument().on "change", onChange
|
|
||||||
@redrawAnnotations()
|
@redrawAnnotations()
|
||||||
|
|
||||||
bindToAce = () =>
|
bindToAce = () =>
|
||||||
@editor.getSession().getDocument().on "change", onChange
|
|
||||||
@editor.on "changeSelection", onChangeSelection
|
@editor.on "changeSelection", onChangeSelection
|
||||||
@editor.on "changeSession", onChangeSession
|
@editor.on "changeSession", onChangeSession
|
||||||
@editor.renderer.on "resize", onResize
|
@editor.renderer.on "resize", onResize
|
||||||
|
|
||||||
unbindFromAce = () =>
|
unbindFromAce = () =>
|
||||||
@editor.getSession().getDocument().off "change", onChange
|
|
||||||
@editor.off "changeSelection", onChangeSelection
|
@editor.off "changeSelection", onChangeSelection
|
||||||
@editor.off "changeSession", onChangeSession
|
@editor.off "changeSession", onChangeSession
|
||||||
@editor.renderer.off "resize", onResize
|
@editor.renderer.off "resize", onResize
|
||||||
|
@ -132,41 +92,49 @@ define [
|
||||||
@rangesTracker.off "comment:removed"
|
@rangesTracker.off "comment:removed"
|
||||||
@rangesTracker.off "comment:resolved"
|
@rangesTracker.off "comment:resolved"
|
||||||
@rangesTracker.off "comment:unresolved"
|
@rangesTracker.off "comment:unresolved"
|
||||||
|
|
||||||
|
setTrackChanges: (value) ->
|
||||||
|
if value
|
||||||
|
@$scope.sharejsDoc?.track_changes_as = window.user.id
|
||||||
|
else
|
||||||
|
@$scope.sharejsDoc?.track_changes_as = null
|
||||||
|
|
||||||
connectToRangesTracker: () ->
|
connectToRangesTracker: () ->
|
||||||
@rangesTracker.track_changes = @$scope.trackChanges
|
@setTrackChanges(@$scope.trackChanges)
|
||||||
|
|
||||||
|
# Add a timeout because on remote ops, we get these notifications before
|
||||||
|
# ace has updated
|
||||||
@rangesTracker.on "insert:added", (change) =>
|
@rangesTracker.on "insert:added", (change) =>
|
||||||
sl_console.log "[insert:added]", change
|
sl_console.log "[insert:added]", change
|
||||||
@_onInsertAdded(change)
|
setTimeout () => @_onInsertAdded(change)
|
||||||
@rangesTracker.on "insert:removed", (change) =>
|
@rangesTracker.on "insert:removed", (change) =>
|
||||||
sl_console.log "[insert:removed]", change
|
sl_console.log "[insert:removed]", change
|
||||||
@_onInsertRemoved(change)
|
setTimeout () => @_onInsertRemoved(change)
|
||||||
@rangesTracker.on "delete:added", (change) =>
|
@rangesTracker.on "delete:added", (change) =>
|
||||||
sl_console.log "[delete:added]", change
|
sl_console.log "[delete:added]", change
|
||||||
@_onDeleteAdded(change)
|
setTimeout () => @_onDeleteAdded(change)
|
||||||
@rangesTracker.on "delete:removed", (change) =>
|
@rangesTracker.on "delete:removed", (change) =>
|
||||||
sl_console.log "[delete:removed]", change
|
sl_console.log "[delete:removed]", change
|
||||||
@_onDeleteRemoved(change)
|
setTimeout () => @_onDeleteRemoved(change)
|
||||||
@rangesTracker.on "changes:moved", (changes) =>
|
@rangesTracker.on "changes:moved", (changes) =>
|
||||||
sl_console.log "[changes:moved]", changes
|
sl_console.log "[changes:moved]", changes
|
||||||
@_onChangesMoved(changes)
|
setTimeout () => @_onChangesMoved(changes)
|
||||||
|
|
||||||
@rangesTracker.on "comment:added", (comment) =>
|
@rangesTracker.on "comment:added", (comment) =>
|
||||||
sl_console.log "[comment:added]", comment
|
sl_console.log "[comment:added]", comment
|
||||||
@_onCommentAdded(comment)
|
setTimeout () => @_onCommentAdded(comment)
|
||||||
@rangesTracker.on "comment:moved", (comment) =>
|
@rangesTracker.on "comment:moved", (comment) =>
|
||||||
sl_console.log "[comment:moved]", comment
|
sl_console.log "[comment:moved]", comment
|
||||||
@_onCommentMoved(comment)
|
setTimeout () => @_onCommentMoved(comment)
|
||||||
@rangesTracker.on "comment:removed", (comment) =>
|
@rangesTracker.on "comment:removed", (comment) =>
|
||||||
sl_console.log "[comment:removed]", comment
|
sl_console.log "[comment:removed]", comment
|
||||||
@_onCommentRemoved(comment)
|
setTimeout () => @_onCommentRemoved(comment)
|
||||||
@rangesTracker.on "comment:resolved", (comment) =>
|
@rangesTracker.on "comment:resolved", (comment) =>
|
||||||
sl_console.log "[comment:resolved]", comment
|
sl_console.log "[comment:resolved]", comment
|
||||||
@_onCommentRemoved(comment)
|
setTimeout () => @_onCommentRemoved(comment)
|
||||||
@rangesTracker.on "comment:unresolved", (comment) =>
|
@rangesTracker.on "comment:unresolved", (comment) =>
|
||||||
sl_console.log "[comment:unresolved]", comment
|
sl_console.log "[comment:unresolved]", comment
|
||||||
@_onCommentAdded(comment)
|
setTimeout () => @_onCommentAdded(comment)
|
||||||
|
|
||||||
redrawAnnotations: () ->
|
redrawAnnotations: () ->
|
||||||
for change in @rangesTracker.changes
|
for change in @rangesTracker.changes
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Doc
|
||||||
# Its important that these event handlers are called with oldSnapshot.
|
# Its important that these event handlers are called with oldSnapshot.
|
||||||
# The reason is that the OT type APIs might need to access the snapshots to
|
# The reason is that the OT type APIs might need to access the snapshots to
|
||||||
# determine information about the received op.
|
# determine information about the received op.
|
||||||
@emit 'change', docOp, oldSnapshot
|
@emit 'change', docOp, oldSnapshot, msg
|
||||||
@emit 'remoteop', docOp, oldSnapshot, msg if isRemote
|
@emit 'remoteop', docOp, oldSnapshot, msg if isRemote
|
||||||
|
|
||||||
_connectionStateChanged: (state, data) ->
|
_connectionStateChanged: (state, data) ->
|
||||||
|
@ -274,6 +274,7 @@ class Doc
|
||||||
submitOp: (op, callback) ->
|
submitOp: (op, callback) ->
|
||||||
op = @type.normalize(op) if @type.normalize?
|
op = @type.normalize(op) if @type.normalize?
|
||||||
|
|
||||||
|
oldSnapshot = @snapshot
|
||||||
# If this throws an exception, no changes should have been made to the doc
|
# If this throws an exception, no changes should have been made to the doc
|
||||||
@snapshot = @type.apply @snapshot, op
|
@snapshot = @type.apply @snapshot, op
|
||||||
|
|
||||||
|
@ -284,7 +285,7 @@ class Doc
|
||||||
|
|
||||||
@pendingCallbacks.push callback if callback
|
@pendingCallbacks.push callback if callback
|
||||||
|
|
||||||
@emit 'change', op
|
@emit 'change', op, oldSnapshot
|
||||||
|
|
||||||
@delayedFlush()
|
@delayedFlush()
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ checkValidComponent = (c) ->
|
||||||
|
|
||||||
i_type = typeof c.i
|
i_type = typeof c.i
|
||||||
d_type = typeof c.d
|
d_type = typeof c.d
|
||||||
throw new Error 'component needs an i or d field' unless (i_type == 'string') ^ (d_type == 'string')
|
c_type = typeof c.c
|
||||||
|
throw new Error 'component needs an i, d or c field' unless (i_type == 'string') ^ (d_type == 'string') ^ (c_type == 'string')
|
||||||
|
|
||||||
throw new Error 'position cannot be negative' unless c.p >= 0
|
throw new Error 'position cannot be negative' unless c.p >= 0
|
||||||
|
|
||||||
|
@ -44,11 +45,15 @@ text.apply = (snapshot, op) ->
|
||||||
for component in op
|
for component in op
|
||||||
if component.i?
|
if component.i?
|
||||||
snapshot = strInject snapshot, component.p, component.i
|
snapshot = strInject snapshot, component.p, component.i
|
||||||
else
|
else if component.d?
|
||||||
deleted = snapshot[component.p...(component.p + component.d.length)]
|
deleted = snapshot[component.p...(component.p + component.d.length)]
|
||||||
throw new Error "Delete component '#{component.d}' does not match deleted text '#{deleted}'" unless component.d == deleted
|
throw new Error "Delete component '#{component.d}' does not match deleted text '#{deleted}'" unless component.d == deleted
|
||||||
snapshot = snapshot[...component.p] + snapshot[(component.p + component.d.length)..]
|
snapshot = snapshot[...component.p] + snapshot[(component.p + component.d.length)..]
|
||||||
|
else if component.c?
|
||||||
|
comment = snapshot[component.p...(component.p + component.c.length)]
|
||||||
|
throw new Error "Comment component '#{component.c}' does not match commented text '#{comment}'" unless component.c == comment
|
||||||
|
else
|
||||||
|
throw new Error "Unknown op type"
|
||||||
snapshot
|
snapshot
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,7 +117,7 @@ transformPosition = (pos, c, insertAfter) ->
|
||||||
pos + c.i.length
|
pos + c.i.length
|
||||||
else
|
else
|
||||||
pos
|
pos
|
||||||
else
|
else if c.d?
|
||||||
# I think this could also be written as: Math.min(c.p, Math.min(c.p - otherC.p, otherC.d.length))
|
# I think this could also be written as: Math.min(c.p, Math.min(c.p - otherC.p, otherC.d.length))
|
||||||
# but I think its harder to read that way, and it compiles using ternary operators anyway
|
# but I think its harder to read that way, and it compiles using ternary operators anyway
|
||||||
# so its no slower written like this.
|
# so its no slower written like this.
|
||||||
|
@ -122,6 +127,10 @@ transformPosition = (pos, c, insertAfter) ->
|
||||||
c.p
|
c.p
|
||||||
else
|
else
|
||||||
pos - c.d.length
|
pos - c.d.length
|
||||||
|
else if c.c?
|
||||||
|
pos
|
||||||
|
else
|
||||||
|
throw new Error("unknown op type")
|
||||||
|
|
||||||
# Helper method to transform a cursor position as a result of an op.
|
# Helper method to transform a cursor position as a result of an op.
|
||||||
#
|
#
|
||||||
|
@ -143,7 +152,7 @@ text._tc = transformComponent = (dest, c, otherC, side) ->
|
||||||
if c.i?
|
if c.i?
|
||||||
append dest, {i:c.i, p:transformPosition(c.p, otherC, side == 'right')}
|
append dest, {i:c.i, p:transformPosition(c.p, otherC, side == 'right')}
|
||||||
|
|
||||||
else # Delete
|
else if c.d? # Delete
|
||||||
if otherC.i? # delete vs insert
|
if otherC.i? # delete vs insert
|
||||||
s = c.d
|
s = c.d
|
||||||
if c.p < otherC.p
|
if c.p < otherC.p
|
||||||
|
@ -152,7 +161,7 @@ text._tc = transformComponent = (dest, c, otherC, side) ->
|
||||||
if s != ''
|
if s != ''
|
||||||
append dest, {d:s, p:c.p + otherC.i.length}
|
append dest, {d:s, p:c.p + otherC.i.length}
|
||||||
|
|
||||||
else # Delete vs delete
|
else if otherC.d? # Delete vs delete
|
||||||
if c.p >= otherC.p + otherC.d.length
|
if c.p >= otherC.p + otherC.d.length
|
||||||
append dest, {d:c.d, p:c.p - otherC.d.length}
|
append dest, {d:c.d, p:c.p - otherC.d.length}
|
||||||
else if c.p + c.d.length <= otherC.p
|
else if c.p + c.d.length <= otherC.p
|
||||||
|
@ -177,6 +186,51 @@ text._tc = transformComponent = (dest, c, otherC, side) ->
|
||||||
# This could be rewritten similarly to insert v delete, above.
|
# This could be rewritten similarly to insert v delete, above.
|
||||||
newC.p = transformPosition newC.p, otherC
|
newC.p = transformPosition newC.p, otherC
|
||||||
append dest, newC
|
append dest, newC
|
||||||
|
|
||||||
|
else if otherC.c?
|
||||||
|
append dest, c
|
||||||
|
|
||||||
|
else
|
||||||
|
throw new Error("unknown op type")
|
||||||
|
|
||||||
|
else if c.c? # Comment
|
||||||
|
if otherC.i?
|
||||||
|
if c.p < otherC.p < c.p + c.c.length
|
||||||
|
offset = otherC.p - c.p
|
||||||
|
new_c = (c.c[0..(offset-1)] + otherC.i + c.c[offset...])
|
||||||
|
append dest, {c:new_c, p:c.p, t: c.t}
|
||||||
|
else
|
||||||
|
append dest, {c:c.c, p:transformPosition(c.p, otherC, true), t: c.t}
|
||||||
|
|
||||||
|
else if otherC.d?
|
||||||
|
if c.p >= otherC.p + otherC.d.length
|
||||||
|
append dest, {c:c.c, p:c.p - otherC.d.length, t: c.t}
|
||||||
|
else if c.p + c.c.length <= otherC.p
|
||||||
|
append dest, c
|
||||||
|
else # Delete overlaps comment
|
||||||
|
# They overlap somewhere.
|
||||||
|
newC = {c:'', p:c.p, t: c.t}
|
||||||
|
if c.p < otherC.p
|
||||||
|
newC.c = c.c[...(otherC.p - c.p)]
|
||||||
|
if c.p + c.c.length > otherC.p + otherC.d.length
|
||||||
|
newC.c += c.c[(otherC.p + otherC.d.length - c.p)..]
|
||||||
|
|
||||||
|
# This is entirely optional - just for a check that the deleted
|
||||||
|
# text in the two ops matches
|
||||||
|
intersectStart = Math.max c.p, otherC.p
|
||||||
|
intersectEnd = Math.min c.p + c.c.length, otherC.p + otherC.d.length
|
||||||
|
cIntersect = c.c[intersectStart - c.p...intersectEnd - c.p]
|
||||||
|
otherIntersect = otherC.d[intersectStart - otherC.p...intersectEnd - otherC.p]
|
||||||
|
throw new Error 'Delete ops delete different text in the same region of the document' unless cIntersect == otherIntersect
|
||||||
|
|
||||||
|
newC.p = transformPosition newC.p, otherC
|
||||||
|
append dest, newC
|
||||||
|
|
||||||
|
else if otherC.c?
|
||||||
|
append dest, c
|
||||||
|
|
||||||
|
else
|
||||||
|
throw new Error("unknown op type")
|
||||||
|
|
||||||
dest
|
dest
|
||||||
|
|
||||||
|
|
|
@ -154,10 +154,13 @@ define [
|
||||||
if view == $scope.SubViews.OVERVIEW
|
if view == $scope.SubViews.OVERVIEW
|
||||||
refreshOverviewPanel()
|
refreshOverviewPanel()
|
||||||
|
|
||||||
$scope.$watch "editor.open_doc_id", (open_doc_id) ->
|
$scope.$watch "editor.sharejs_doc", (doc) ->
|
||||||
return if !open_doc_id?
|
return if !doc?
|
||||||
rangesTrackers[open_doc_id] ?= new RangesTracker()
|
console.log "DOC changed", doc
|
||||||
$scope.reviewPanel.rangesTracker = rangesTrackers[open_doc_id]
|
# The open doc range tracker is kept up to date in real-time so
|
||||||
|
# replace any outdated info with this
|
||||||
|
rangesTrackers[doc.doc_id] = doc.ranges
|
||||||
|
$scope.reviewPanel.rangesTracker = rangesTrackers[doc.doc_id]
|
||||||
|
|
||||||
$scope.$watch (() ->
|
$scope.$watch (() ->
|
||||||
entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
|
entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
|
||||||
|
|
Loading…
Reference in a new issue