jquery-crate
Version:
Cratify tool that turns a division into a distributed and decentralized collaborative editor
173 lines (158 loc) • 6.43 kB
JavaScript
var Marker = require('../view/marker.js');
function EditorController(model, viewEditor){
var self = this, editor = viewEditor.editor;
this.viewEditor = viewEditor;
this.fromRemote = false;
// #B initialize the string within the editor
function getStringChildNode(childNode){
var result = '';
if (childNode.e !== null){ result = childNode.e; };
for (var i=0; i<childNode.children.length; ++i){
result += getStringChildNode(childNode.children[i]);
};
return result;
};
editor.setValue(getStringChildNode(model.sequence.root),1);
var insertRemoveOp = false;
editor.getSession().on('change', function(e){
switch(e.data.action){
case 'removeLines':
case 'removeText':
case 'insertLines':
case 'insertText':
insertRemoveOp = true;
}
});
editor.getSession().getSelection().on('changeCursor', function(e, sel){
if (!insertRemoveOp){
var range = sel.getRange();
model.core.caretMoved({
start: editor.getSession().getDocument().positionToIndex(range.start),
end: editor.getSession().getDocument().positionToIndex(range.end)
});
}
insertRemoveOp = false;
});
editor.getSession().on('change', function(e) {
var begin, end, text, message, j=0;
if (!self.fromRemote){
// #1 process the boundaries from range to index and text
begin = editor.getSession().getDocument().positionToIndex(
e.data.range.start);
switch (e.data.action){
case 'removeLines':
end = begin;
for (var i=0; i<e.data.lines.length;++i){
end += e.data.lines[i].length+1; // +1 because of \n
};
remoteCaretsUpdate(begin, begin-end);
break;
case 'removeText':
if (e.data.text.length === 1){
end = begin+1; //faster
} else {
end = editor.getSession().getDocument().positionToIndex(
e.data.range.end);
};
remoteCaretsUpdate(begin, begin-end);
break;
case 'insertLines':
text = '';
for (var i=0; i<e.data.lines.length;++i){
text = text + (e.data.lines[i]) + '\n';
};
end = begin + text.length;
remoteCaretsUpdate(begin, text.length);
break;
case 'insertText':
text = e.data.text;
end = editor.getSession().getDocument().positionToIndex(
e.data.range.end);
remoteCaretsUpdate(begin, text.length);
break;
};
// #2 update the underlying CRDT model and broadcast the results
for (var i=begin; i<end; ++i){
switch (e.data.action){
case 'insertText': model.core.insert(text[j], i); break;
case 'insertLines': model.core.insert(text[j], i); break;
case 'removeText': model.core.remove(begin); break;
case 'removeLines': model.core.remove(begin); break;
};
++j;
};
};
});
model.core.on('remoteInsert', function(element, index){
var aceDocument = editor.getSession().getDocument(),
delta,
tempFromRemote;
if (index!==-1){
delta = {action: 'insertText',
range: { start: aceDocument.indexToPosition(index-1),
end: aceDocument.indexToPosition(index)},
text: element},
tempFromRemote = self.fromRemote;
self.fromRemote = true;
aceDocument.applyDeltas([delta]);
remoteCaretsUpdate(index,1);
self.fromRemote = tempFromRemote;
};
});
model.core.on('remoteRemove', function(index){
var aceDocument = editor.getSession().getDocument(),
delta,
tempFromRemote;
if (index !== -1){
delta = {action: 'removeText',
range: { start: aceDocument.indexToPosition(index - 1),
end: aceDocument.indexToPosition(index)},
text: null};
tempFromRemote = self.fromRemote;
self.fromRemote = true;
aceDocument.applyDeltas([delta]);
remoteCaretsUpdate(index,-1);
self.fromRemote = tempFromRemote;
};
});
model.core.on('remoteCaretMoved', function(range, origin){
if (!origin) return;
if (editor.session.remoteCarets[origin]){
// #A update the existing cursor
var marker = editor.session.remoteCarets[origin];
marker.cursors = [range]; // save the cursors as indexes
editor.getSession()._signal('changeFrontMarker');
marker.refresh();
}else{
// #B create a new cursor
var marker = new Marker(editor.session, origin, range);
editor.session.addDynamicMarker(marker, true);
editor.session.remoteCarets[origin] = marker;
marker.refresh();
// call marker.session.removeMarker(marker.id) to remove it
// call marker.redraw after changing one of cursors
}
});
editor.session.remoteCarets = {};
function remoteCaretsUpdate(index, length){
var change = false, document = editor.session.getDocument();
for (origin in editor.session.remoteCarets){
var remoteCaret = editor.session.remoteCarets[origin];
for (i=0; i<remoteCaret.cursors.length; ++i){
var cursor = remoteCaret.cursors[i];
if (cursor.start >= index){
cursor.start += length;
change = true;
}
if (cursor.end >= index){
cursor.end += length;
change = true;
}
}
}
if (change){
editor.session._signal('changeFrontMarker');
}
};
};
module.exports = EditorController;