mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
95 lines
2.9 KiB
CoffeeScript
95 lines
2.9 KiB
CoffeeScript
|
# This is some utility code to connect a CodeMirror editor
|
||
|
# to a sharejs document.
|
||
|
# It is heavily inspired from the Ace editor hook.
|
||
|
|
||
|
# Convert a CodeMirror delta into an op understood by share.js
|
||
|
applyToShareJS = (editorDoc, delta, doc) ->
|
||
|
# CodeMirror deltas give a text replacement.
|
||
|
# I tuned this operation a little bit, for speed.
|
||
|
startPos = 0 # Get character position from # of chars in each line.
|
||
|
i = 0 # i goes through all lines.
|
||
|
|
||
|
while i < delta.from.line
|
||
|
startPos += editorDoc.lineInfo(i).text.length + 1 # Add 1 for '\n'
|
||
|
i++
|
||
|
|
||
|
startPos += delta.from.ch
|
||
|
|
||
|
if delta.to.line == delta.from.line &&
|
||
|
delta.to.ch == delta.from.ch # Then nothing was removed.
|
||
|
doc.insert startPos, delta.text.join '\n'
|
||
|
else
|
||
|
delLen = delta.to.ch - delta.from.ch
|
||
|
while i < delta.to.line
|
||
|
delLen += editorDoc.lineInfo(i).text.length + 1 # Add 1 for '\n'
|
||
|
i++
|
||
|
doc.del startPos, delLen
|
||
|
doc.insert startPos, delta.text.join '\n' if delta.text
|
||
|
|
||
|
applyToShareJS editorDoc, delta.next, doc if delta.next
|
||
|
|
||
|
# Attach a CodeMirror editor to the document. The editor's contents are replaced
|
||
|
# with the document's contents unless keepEditorContents is true. (In which case
|
||
|
# the document's contents are nuked and replaced with the editor's).
|
||
|
window.sharejs.extendDoc 'attach_cm', (editor, keepEditorContents) ->
|
||
|
unless @provides.text
|
||
|
throw new Error 'Only text documents can be attached to CodeMirror2'
|
||
|
|
||
|
sharedoc = @
|
||
|
check = ->
|
||
|
window.setTimeout ->
|
||
|
editorText = editor.getValue()
|
||
|
otText = sharedoc.getValue()
|
||
|
|
||
|
if editorText != otText
|
||
|
console.error "Text does not match!"
|
||
|
console.error "editor: #{editorText}"
|
||
|
console.error "ot: #{otText}"
|
||
|
# Replace the editor text with the doc snapshot.
|
||
|
editor.setValue sharedoc.getValue()
|
||
|
, 0
|
||
|
|
||
|
if keepEditorContents
|
||
|
@del 0, sharedoc.getText().length
|
||
|
@insert 0, editor.getValue()
|
||
|
else
|
||
|
editor.setValue sharedoc.getText()
|
||
|
|
||
|
check()
|
||
|
|
||
|
# When we apply ops from sharejs, CodeMirror emits edit events.
|
||
|
# We need to ignore those to prevent an infinite typing loop.
|
||
|
suppress = false
|
||
|
|
||
|
# Listen for edits in CodeMirror.
|
||
|
editorListener = (ed, change) ->
|
||
|
return if suppress
|
||
|
applyToShareJS editor, change, sharedoc
|
||
|
|
||
|
check()
|
||
|
|
||
|
editor.setOption 'onChange', editorListener
|
||
|
|
||
|
@on 'insert', (pos, text) ->
|
||
|
suppress = true
|
||
|
# All the primitives we need are already in CM's API.
|
||
|
editor.replaceRange text, editor.posFromIndex(pos)
|
||
|
suppress = false
|
||
|
check()
|
||
|
|
||
|
@on 'delete', (pos, text) ->
|
||
|
suppress = true
|
||
|
from = editor.posFromIndex pos
|
||
|
to = editor.posFromIndex (pos + text.length)
|
||
|
editor.replaceRange '', from, to
|
||
|
suppress = false
|
||
|
check()
|
||
|
|
||
|
@detach_cm = ->
|
||
|
# TODO: can we remove the insert and delete event callbacks?
|
||
|
editor.setOption 'onChange', null
|
||
|
delete @detach_cm
|
||
|
|
||
|
return
|
||
|
|