mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-09 07:16:03 +00:00
Merge pull request #3356 from overleaf/jpa-unified-remote-flag
[frontend] sharejs: replace 'suppress' hack w/ unified 'remote' flag GitOrigin-RevId: 25e761a1e543d08477d9b0f3960ddf055d38790b
This commit is contained in:
parent
4680af4b7d
commit
0f2e5542e0
4 changed files with 36 additions and 51 deletions
|
@ -244,7 +244,7 @@ class AutoCompleteManager {
|
|||
// NOTE: this is also the case when a user backspaces over a highlighted
|
||||
// region
|
||||
if (
|
||||
!change.remote &&
|
||||
change.origin !== 'remote' &&
|
||||
change.action === 'insert' &&
|
||||
end.row === cursorPosition.row &&
|
||||
end.column === cursorPosition.column + 1
|
||||
|
|
|
@ -34,7 +34,7 @@ export default (MetadataManager = class MetadataManager {
|
|||
this.debouncer = {} // DocId => Timeout
|
||||
|
||||
const onChange = change => {
|
||||
if (change.remote) {
|
||||
if (change.origin === 'remote') {
|
||||
return
|
||||
}
|
||||
if (!['remove', 'insert'].includes(change.action)) {
|
||||
|
|
|
@ -14,7 +14,7 @@ class UndoManager {
|
|||
}
|
||||
|
||||
onChange(change) {
|
||||
if (!change.remote) return
|
||||
if (change.origin !== 'remote') return
|
||||
|
||||
// HACK: remote changes in Ace are added by the ShareJS/Ace adapter
|
||||
// asynchronously via a timeout (see attach_ace function). This makes it
|
||||
|
|
81
services/web/frontend/js/vendor/libs/sharejs.js
vendored
81
services/web/frontend/js/vendor/libs/sharejs.js
vendored
|
@ -1477,7 +1477,7 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
var editorDoc = editor.getSession().getDocument();
|
||||
editorDoc.setNewLineMode('unix');
|
||||
|
||||
var check = function check() {
|
||||
function check() {
|
||||
return window.setTimeout(function () {
|
||||
var editorText = editorDoc.getValue();
|
||||
var otText = doc.getText();
|
||||
|
@ -1493,22 +1493,15 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
, 0);
|
||||
};
|
||||
|
||||
if (keepEditorContents) {
|
||||
doc.del(0, doc.getText().length);
|
||||
doc.insert(0, editorDoc.getValue());
|
||||
} else {
|
||||
editorDoc.setValue(doc.getText());
|
||||
}
|
||||
onDelete(0, editorDoc.getValue());
|
||||
onInsert(0, doc.getText());
|
||||
|
||||
check();
|
||||
|
||||
// When we apply ops from sharejs, ace emits edit events. We need to ignore those
|
||||
// to prevent an infinite typing loop.
|
||||
var suppress = false;
|
||||
|
||||
// Listen for edits in ace
|
||||
var editorListener = function editorListener(change) {
|
||||
if (suppress) {
|
||||
function editorListener(change) {
|
||||
if (change.origin === 'remote') {
|
||||
// this change has been injected via sharejs
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1520,7 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
editorDoc.on('change', editorListener);
|
||||
|
||||
// Horribly inefficient.
|
||||
var offsetToPos = function offsetToPos(offset) {
|
||||
function offsetToPos(offset) {
|
||||
// Again, very inefficient.
|
||||
var lines = editorDoc.getAllLines();
|
||||
|
||||
|
@ -1545,12 +1538,13 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
return { 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.
|
||||
var onInsert = function onInsert(pos, text) {
|
||||
// We want to insert the flag `origin: 'remote'` into the delta if the op
|
||||
// is the initial document write or 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 `origin: 'remote'` flag into the delta.
|
||||
function onInsert(pos, text) {
|
||||
if (editorDoc.getLength() <= 1) {
|
||||
editorDoc.$detectNewLine(text);
|
||||
}
|
||||
|
@ -1563,31 +1557,27 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
column: (lines.length === 1 ? start.column : 0) + lines[lines.length - 1].length
|
||||
};
|
||||
|
||||
suppress = true;
|
||||
editorDoc.applyDelta({
|
||||
start: start,
|
||||
end: end,
|
||||
action: 'insert',
|
||||
lines: lines,
|
||||
remote: true
|
||||
origin: 'remote'
|
||||
});
|
||||
suppress = false;
|
||||
return check();
|
||||
};
|
||||
|
||||
var onDelete = function onDelete(pos, text) {
|
||||
function onDelete(pos, text) {
|
||||
var range = Range.fromPoints(offsetToPos(pos), offsetToPos(pos + text.length));
|
||||
var start = editorDoc.clippedPos(range.start.row, range.start.column);
|
||||
var 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
|
||||
origin: 'remote'
|
||||
});
|
||||
suppress = false;
|
||||
return check();
|
||||
};
|
||||
|
||||
|
@ -1632,6 +1622,11 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
// 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).
|
||||
// NOTE: When upgrading CM, make sure to check for new special cases of
|
||||
// origin prefixes as documented for `doc.setSelection`. We are using
|
||||
// a custom `origin: 'remote'` which may conflict.
|
||||
// Perma link of the docs at the time of writing this note:
|
||||
// https://web.archive.org/web/20201029163528/https://codemirror.net/doc/manual.html#selection_origin
|
||||
window.sharejs.extendDoc('attach_cm', function (editor, keepEditorContents) {
|
||||
if (!this.provides.text) {
|
||||
throw new Error('Only text documents can be attached to CodeMirror2');
|
||||
|
@ -1640,7 +1635,7 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
var sharedoc = this;
|
||||
var editorDoc = editor.getDoc();
|
||||
|
||||
var check = function check() {
|
||||
function check() {
|
||||
return window.setTimeout(function () {
|
||||
var editorText = editor.getValue();
|
||||
var otText = sharedoc.getText();
|
||||
|
@ -1658,22 +1653,15 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
, 0);
|
||||
};
|
||||
|
||||
if (keepEditorContents) {
|
||||
this.del(0, sharedoc.getText().length);
|
||||
this.insert(0, editor.getValue());
|
||||
} else {
|
||||
editor.setValue(sharedoc.getText());
|
||||
}
|
||||
onDelete(0, editor.getValue());
|
||||
onInsert(0, sharedoc.getText());
|
||||
|
||||
check();
|
||||
|
||||
// When we apply ops from sharejs, CodeMirror emits edit events.
|
||||
// We need to ignore those to prevent an infinite typing loop.
|
||||
var suppress = false;
|
||||
|
||||
// Listen for edits in CodeMirror.
|
||||
var editorListener = function editorListener(ed, change) {
|
||||
if (suppress) {
|
||||
function editorListener(ed, change) {
|
||||
if (change.origin === 'remote') {
|
||||
// this change has been injected via sharejs
|
||||
return;
|
||||
}
|
||||
var fromUndo = (change.origin === 'undo')
|
||||
|
@ -1683,26 +1671,23 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
|
||||
editorDoc.on('change', editorListener);
|
||||
|
||||
var onInsert = function onInsert(pos, text) {
|
||||
suppress = true;
|
||||
function onInsert(pos, text) {
|
||||
// All the primitives we need are already in CM's API.
|
||||
editor.replaceRange(text, editor.posFromIndex(pos));
|
||||
// call signature: editor.replaceRange(text, from, to, origin)
|
||||
editor.replaceRange(text, editor.posFromIndex(pos), undefined, 'remote');
|
||||
// Clear CM's undo/redo history on remote edit. This prevents issues where
|
||||
// a user can accidentally remove another user's edits
|
||||
editor.clearHistory();
|
||||
suppress = false;
|
||||
return check();
|
||||
};
|
||||
|
||||
var onDelete = function onDelete(pos, text) {
|
||||
suppress = true;
|
||||
function onDelete(pos, text) {
|
||||
var from = editor.posFromIndex(pos);
|
||||
var to = editor.posFromIndex(pos + text.length);
|
||||
editor.replaceRange('', from, to);
|
||||
editor.replaceRange('', from, to, 'remote');
|
||||
// Clear CM's undo/redo history on remote edit. This prevents issues where
|
||||
// a user can accidentally remove another user's edits
|
||||
editor.clearHistory()
|
||||
suppress = false;
|
||||
return check();
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue