mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Stop local and remote ops being batched together in the undo manager if they happen in the same flush
This commit is contained in:
parent
a8756432b7
commit
a6679a1aeb
3 changed files with 77 additions and 30 deletions
|
@ -322,10 +322,6 @@ define [
|
||||||
doc = session.getDocument()
|
doc = session.getDocument()
|
||||||
doc.on "change", onChange
|
doc.on "change", onChange
|
||||||
|
|
||||||
sharejs_doc.on "remoteop.recordRemote", (op, oldSnapshot, msg) ->
|
|
||||||
undoManager.nextUpdateIsRemote = true
|
|
||||||
trackChangesManager.nextUpdateMetaData = msg?.meta
|
|
||||||
|
|
||||||
editor.initing = true
|
editor.initing = true
|
||||||
sharejs_doc.attachToAce(editor)
|
sharejs_doc.attachToAce(editor)
|
||||||
editor.initing = false
|
editor.initing = false
|
||||||
|
|
|
@ -11,10 +11,10 @@ define [
|
||||||
show_remote_warning: false
|
show_remote_warning: false
|
||||||
|
|
||||||
@reset()
|
@reset()
|
||||||
@nextUpdateIsRemote = false
|
|
||||||
|
|
||||||
@editor.on "changeSession", (e) =>
|
@editor.on "changeSession", (e) =>
|
||||||
@reset()
|
@reset()
|
||||||
|
@session = e.session
|
||||||
e.session.setUndoManager(@)
|
e.session.setUndoManager(@)
|
||||||
|
|
||||||
showUndoConflictWarning: () ->
|
showUndoConflictWarning: () ->
|
||||||
|
@ -38,20 +38,44 @@ define [
|
||||||
@firstUpdate = false
|
@firstUpdate = false
|
||||||
return
|
return
|
||||||
aceDeltaSets = options.args[0]
|
aceDeltaSets = options.args[0]
|
||||||
@session = options.args[1]
|
|
||||||
return if !aceDeltaSets?
|
return if !aceDeltaSets?
|
||||||
|
@session = options.args[1]
|
||||||
|
|
||||||
lines = @session.getDocument().getAllLines()
|
# We need to split the delta sets into local or remote groups before pushing onto
|
||||||
linesBeforeChange = @_revertAceDeltaSetsOnDocLines(aceDeltaSets, lines)
|
# the undo stack, since these are treated differently.
|
||||||
simpleDeltaSets = @_aceDeltaSetsToSimpleDeltaSets(aceDeltaSets, linesBeforeChange)
|
splitDeltaSets = []
|
||||||
@undoStack.push(
|
currentDeltaSet = null # Make global to this function
|
||||||
deltaSets: simpleDeltaSets
|
do newDeltaSet = () ->
|
||||||
remote: @nextUpdateIsRemote
|
currentDeltaSet = {group: "doc", deltas: []}
|
||||||
)
|
splitDeltaSets.push currentDeltaSet
|
||||||
|
currentRemoteState = null
|
||||||
|
|
||||||
|
for deltaSet in aceDeltaSets or []
|
||||||
|
if deltaSet.group == "doc" # ignore code folding etc.
|
||||||
|
for delta in deltaSet.deltas
|
||||||
|
if currentDeltaSet.remote? and currentDeltaSet.remote != !!delta.remote
|
||||||
|
newDeltaSet()
|
||||||
|
currentDeltaSet.deltas.push delta
|
||||||
|
currentDeltaSet.remote = !!delta.remote
|
||||||
|
|
||||||
|
# The lines are currently as they are after applying all these deltas, but to turn into simple deltas,
|
||||||
|
# we need the lines before each delta group.
|
||||||
|
docLines = @session.getDocument().getAllLines()
|
||||||
|
docLines = @_revertAceDeltaSetsOnDocLines(aceDeltaSets, docLines)
|
||||||
|
for deltaSet in splitDeltaSets
|
||||||
|
{simpleDeltaSet, docLines} = @_aceDeltaSetToSimpleDeltaSet(deltaSet, docLines)
|
||||||
|
frame = {
|
||||||
|
deltaSets: [simpleDeltaSet]
|
||||||
|
remote: deltaSet.remote
|
||||||
|
}
|
||||||
|
@undoStack.push frame
|
||||||
@redoStack = []
|
@redoStack = []
|
||||||
@nextUpdateIsRemote = false
|
|
||||||
|
|
||||||
undo: (dontSelect) ->
|
undo: (dontSelect) ->
|
||||||
|
# We rely on the doclines being in sync with the undo stack, so make sure
|
||||||
|
# any pending undo deltas are processed.
|
||||||
|
@session.$syncInformUndoManager()
|
||||||
|
|
||||||
localUpdatesMade = @_shiftLocalChangeToTopOfUndoStack()
|
localUpdatesMade = @_shiftLocalChangeToTopOfUndoStack()
|
||||||
return if !localUpdatesMade
|
return if !localUpdatesMade
|
||||||
|
|
||||||
|
@ -206,19 +230,16 @@ define [
|
||||||
throw "Unknown delta type"
|
throw "Unknown delta type"
|
||||||
return doc.split("\n")
|
return doc.split("\n")
|
||||||
|
|
||||||
_aceDeltaSetsToSimpleDeltaSets: (aceDeltaSets, docLines) ->
|
_aceDeltaSetToSimpleDeltaSet: (deltaSet, docLines) ->
|
||||||
simpleDeltaSets = []
|
simpleDeltas = []
|
||||||
for deltaSet in aceDeltaSets
|
for delta in deltaSet.deltas
|
||||||
if deltaSet.group == "doc" # ignore fold changes
|
simpleDeltas.push @_aceDeltaToSimpleDelta(delta, docLines)
|
||||||
simpleDeltas = []
|
docLines = @_applyAceDeltasToDocLines([delta], docLines)
|
||||||
for delta in deltaSet.deltas
|
simpleDeltaSet = {
|
||||||
simpleDeltas.push @_aceDeltaToSimpleDelta(delta, docLines)
|
deltas: simpleDeltas
|
||||||
docLines = @_applyAceDeltasToDocLines([delta], docLines)
|
group: deltaSet.group
|
||||||
simpleDeltaSets.push {
|
}
|
||||||
deltas: simpleDeltas
|
return {simpleDeltaSet, docLines}
|
||||||
group: deltaSet.group
|
|
||||||
}
|
|
||||||
return simpleDeltaSets
|
|
||||||
|
|
||||||
_simpleDeltaSetsToAceDeltaSets: (simpleDeltaSets, docLines) ->
|
_simpleDeltaSetsToAceDeltaSets: (simpleDeltaSets, docLines) ->
|
||||||
for deltaSet in simpleDeltaSets
|
for deltaSet in simpleDeltaSets
|
||||||
|
|
|
@ -110,16 +110,46 @@ window.sharejs.extendDoc 'attach_ace', (editor, keepEditorContents, maxDocLength
|
||||||
|
|
||||||
row:row, column:offset
|
row:row, column:offset
|
||||||
|
|
||||||
|
# We want to insert a remote:true into the delta if the op comes from the
|
||||||
|
# underlying sharejs doc (which means it is from a remote op), so we have to do
|
||||||
|
# the work of editorDoc.insert and editorDoc.remove manually. These methods are
|
||||||
|
# copied from ace.js doc#insert and #remove, and then inject the remote:true
|
||||||
|
# flag into the delta.
|
||||||
doc.on 'insert', (pos, text) ->
|
doc.on 'insert', (pos, text) ->
|
||||||
|
if (editorDoc.getLength() <= 1)
|
||||||
|
editorDoc.$detectNewLine(text)
|
||||||
|
|
||||||
|
lines = editorDoc.$split(text)
|
||||||
|
position = offsetToPos(pos)
|
||||||
|
start = editorDoc.clippedPos(position.row, position.column)
|
||||||
|
end = {
|
||||||
|
row: start.row + lines.length - 1,
|
||||||
|
column: (if lines.length == 1 then start.column else 0) + lines[lines.length - 1].length
|
||||||
|
}
|
||||||
|
|
||||||
suppress = true
|
suppress = true
|
||||||
editorDoc.insert offsetToPos(pos), text
|
editorDoc.applyDelta({
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
action: "insert",
|
||||||
|
lines: lines,
|
||||||
|
remote: true
|
||||||
|
});
|
||||||
suppress = false
|
suppress = false
|
||||||
check()
|
check()
|
||||||
|
|
||||||
doc.on 'delete', (pos, text) ->
|
doc.on 'delete', (pos, text) ->
|
||||||
suppress = true
|
|
||||||
range = Range.fromPoints offsetToPos(pos), offsetToPos(pos + text.length)
|
range = Range.fromPoints offsetToPos(pos), offsetToPos(pos + text.length)
|
||||||
editorDoc.remove range
|
start = editorDoc.clippedPos(range.start.row, range.start.column)
|
||||||
|
end = editorDoc.clippedPos(range.end.row, range.end.column)
|
||||||
|
suppress = true
|
||||||
|
editorDoc.applyDelta({
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
action: "remove",
|
||||||
|
lines: editorDoc.getLinesForRange({start: start, end: end})
|
||||||
|
remote: true
|
||||||
|
});
|
||||||
suppress = false
|
suppress = false
|
||||||
check()
|
check()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue