mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-02 13:20:23 -05:00
70 lines
2.5 KiB
CoffeeScript
70 lines
2.5 KiB
CoffeeScript
|
# Create an op which converts oldval -> newval.
|
||
|
#
|
||
|
# This function should be called every time the text element is changed. Because changes are
|
||
|
# always localised, the diffing is quite easy.
|
||
|
#
|
||
|
# This algorithm is O(N), but I suspect you could speed it up somehow using regular expressions.
|
||
|
applyChange = (doc, oldval, newval) ->
|
||
|
return if oldval == newval
|
||
|
commonStart = 0
|
||
|
commonStart++ while oldval.charAt(commonStart) == newval.charAt(commonStart)
|
||
|
|
||
|
commonEnd = 0
|
||
|
commonEnd++ while oldval.charAt(oldval.length - 1 - commonEnd) == newval.charAt(newval.length - 1 - commonEnd) and
|
||
|
commonEnd + commonStart < oldval.length and commonEnd + commonStart < newval.length
|
||
|
|
||
|
doc.del commonStart, oldval.length - commonStart - commonEnd unless oldval.length == commonStart + commonEnd
|
||
|
doc.insert commonStart, newval[commonStart ... newval.length - commonEnd] unless newval.length == commonStart + commonEnd
|
||
|
|
||
|
window.sharejs.extendDoc 'attach_textarea', (elem) ->
|
||
|
doc = this
|
||
|
elem.value = @getText()
|
||
|
prevvalue = elem.value
|
||
|
|
||
|
replaceText = (newText, transformCursor) ->
|
||
|
newSelection = [
|
||
|
transformCursor elem.selectionStart
|
||
|
transformCursor elem.selectionEnd
|
||
|
]
|
||
|
|
||
|
scrollTop = elem.scrollTop
|
||
|
elem.value = newText
|
||
|
elem.scrollTop = scrollTop if elem.scrollTop != scrollTop
|
||
|
[elem.selectionStart, elem.selectionEnd] = newSelection
|
||
|
|
||
|
@on 'insert', (pos, text) ->
|
||
|
transformCursor = (cursor) ->
|
||
|
if pos < cursor
|
||
|
cursor + text.length
|
||
|
else
|
||
|
cursor
|
||
|
#for IE8 and Opera that replace \n with \r\n.
|
||
|
prevvalue = elem.value.replace /\r\n/g, '\n'
|
||
|
replaceText prevvalue[...pos] + text + prevvalue[pos..], transformCursor
|
||
|
|
||
|
@on 'delete', (pos, text) ->
|
||
|
transformCursor = (cursor) ->
|
||
|
if pos < cursor
|
||
|
cursor - Math.min(text.length, cursor - pos)
|
||
|
else
|
||
|
cursor
|
||
|
#for IE8 and Opera that replace \n with \r\n.
|
||
|
prevvalue = elem.value.replace /\r\n/g, '\n'
|
||
|
replaceText prevvalue[...pos] + prevvalue[pos + text.length..], transformCursor
|
||
|
|
||
|
genOp = (event) ->
|
||
|
onNextTick = (fn) -> setTimeout fn, 0
|
||
|
onNextTick ->
|
||
|
if elem.value != prevvalue
|
||
|
# IE constantly replaces unix newlines with \r\n. ShareJS docs
|
||
|
# should only have unix newlines.
|
||
|
prevvalue = elem.value
|
||
|
applyChange doc, doc.getText(), elem.value.replace /\r\n/g, '\n'
|
||
|
|
||
|
for event in ['textInput', 'keydown', 'keyup', 'select', 'cut', 'paste']
|
||
|
if elem.addEventListener
|
||
|
elem.addEventListener event, genOp, false
|
||
|
else
|
||
|
elem.attachEvent 'on'+event, genOp
|
||
|
|