From 1db42b33bd86599ded1950c0a01c59f207bc0ea9 Mon Sep 17 00:00:00 2001 From: Mal Curtis Date: Mon, 8 Jul 2013 12:29:39 +1200 Subject: [PATCH 1/2] Send document identifier when emitting `doc` Fixes issue when a client is editing multiple documents. The `doc` command had no awareness of which doc it had successfully connected to. --- lib/editor-socketio-server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/editor-socketio-server.js b/lib/editor-socketio-server.js index 1bacfdd..aaad0d7 100644 --- a/lib/editor-socketio-server.js +++ b/lib/editor-socketio-server.js @@ -33,7 +33,8 @@ EditorSocketIOServer.prototype.addClient = function (socket) { .emit('doc', { str: this.document, revision: this.operations.length, - clients: this.users + clients: this.users, + docId: this.docId }) .on('operation', function (revision, operation, cursor) { self.mayWrite(socket, function (mayWrite) { @@ -116,4 +117,4 @@ EditorSocketIOServer.prototype.onDisconnect = function (socket) { socket.broadcast['in'](this.docId).emit('client_left', clientId); }; -module.exports = EditorSocketIOServer; \ No newline at end of file +module.exports = EditorSocketIOServer; From 6830af4d3fa6753660244151301fbdbaa3915879 Mon Sep 17 00:00:00 2001 From: Mal Curtis Date: Tue, 16 Jul 2013 16:49:15 +1200 Subject: [PATCH 2/2] Enable multi document editing --- lib/codemirror-adapter.js | 23 +++++++++++++++++------ lib/editor-client.js | 6 +++++- lib/editor-socketio-server.js | 17 +++++++++++------ lib/socketio-adapter.js | 20 ++++++++++---------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/lib/codemirror-adapter.js b/lib/codemirror-adapter.js index 6e812bf..fa980c6 100644 --- a/lib/codemirror-adapter.js +++ b/lib/codemirror-adapter.js @@ -9,15 +9,20 @@ ot.CodeMirrorAdapter = (function () { function CodeMirrorAdapter (cm) { this.cm = cm; this.ignoreNextChange = false; + this.attach(); + } + // Add event listeners to the CodeMirror instance. + CodeMirrorAdapter.prototype.attach = function(){ bind(this, 'onChange'); bind(this, 'onCursorActivity'); bind(this, 'onFocus'); bind(this, 'onBlur'); - cm.on('change', this.onChange); - cm.on('cursorActivity', this.onCursorActivity); - cm.on('focus', this.onFocus); - cm.on('blur', this.onBlur); + this.cm.on('change', this.onChange); + this.cm.on('cursorActivity', this.onCursorActivity); + this.cm.on('focus', this.onFocus); + this.cm.on('blur', this.onBlur); + this.attached = true; } // Removes all event listeners from the CodeMirror instance. @@ -26,6 +31,7 @@ ot.CodeMirrorAdapter = (function () { this.cm.off('cursorActivity', this.onCursorActivity); this.cm.off('focus', this.onFocus); this.cm.off('blur', this.onBlur); + this.attached = false; }; function cmpPos (a, b) { @@ -131,7 +137,7 @@ ot.CodeMirrorAdapter = (function () { // Apply an operation to a CodeMirror instance. CodeMirrorAdapter.applyOperationToCodeMirror = function (operation, cm) { - cm.operation(function () { + var callback = function () { var ops = operation.ops; var index = 0; // holds the current index into CodeMirror's content for (var i = 0, l = ops.length; i < l; i++) { @@ -147,7 +153,12 @@ ot.CodeMirrorAdapter = (function () { cm.replaceRange('', from, to); } } - }); + }; + if(cm.operation){ + cm.operation(callback) + }else{ + callback(); + } }; CodeMirrorAdapter.prototype.registerCallbacks = function (cb) { diff --git a/lib/editor-client.js b/lib/editor-client.js index ecc7c6c..55eb229 100644 --- a/lib/editor-client.js +++ b/lib/editor-client.js @@ -127,7 +127,11 @@ ot.EditorClient = (function () { this.serverAdapter.registerCallbacks({ client_left: function (clientId) { self.onClientLeft(clientId); }, set_name: function (clientId, name) { self.getClientObject(clientId).setName(name); }, - ack: function () { self.serverAck(); }, + ack: function (docId) { + if(docId == self.docId){ + self.serverAck(); + } + }, operation: function (operation) { self.applyServer(TextOperation.fromJSON(operation)); }, diff --git a/lib/editor-socketio-server.js b/lib/editor-socketio-server.js index aaad0d7..49833ad 100644 --- a/lib/editor-socketio-server.js +++ b/lib/editor-socketio-server.js @@ -36,7 +36,10 @@ EditorSocketIOServer.prototype.addClient = function (socket) { clients: this.users, docId: this.docId }) - .on('operation', function (revision, operation, cursor) { + .on('operation', function (docId, revision, operation, cursor) { + if(docId != self.docId){ + return; + } self.mayWrite(socket, function (mayWrite) { if (!mayWrite) { console.log("User doesn't have the right to edit."); @@ -45,7 +48,10 @@ EditorSocketIOServer.prototype.addClient = function (socket) { self.onOperation(socket, revision, operation, cursor); }); }) - .on('cursor', function (obj) { + .on('cursor', function (docId, obj) { + if(docId != this.docId){ + return; + } self.mayWrite(socket, function (mayWrite) { if (!mayWrite) { console.log("User doesn't have the right to edit."); @@ -79,11 +85,10 @@ EditorSocketIOServer.prototype.onOperation = function (socket, revision, operati try { var clientId = socket.id; var wrappedPrime = this.receiveOperation(revision, wrapped); - console.log("new operation: " + wrapped); this.getClient(clientId).cursor = wrappedPrime.meta; - socket.emit('ack'); + socket.emit('ack', this.docId); socket.broadcast['in'](this.docId).emit( - 'operation', clientId, + 'operation', clientId, this.docId, wrappedPrime.wrapped.toJSON(), wrappedPrime.meta ); } catch (exc) { @@ -98,7 +103,7 @@ EditorSocketIOServer.prototype.updateCursor = function (socket, cursor) { } else { delete this.getClient(clientId).cursor; } - socket.broadcast['in'](this.docId).emit('cursor', clientId, cursor); + socket.broadcast['in'](this.docId).emit('cursor', clientId, this.docId, cursor); }; EditorSocketIOServer.prototype.setName = function (socket, name) { diff --git a/lib/socketio-adapter.js b/lib/socketio-adapter.js index 3d4c1e5..611ef89 100644 --- a/lib/socketio-adapter.js +++ b/lib/socketio-adapter.js @@ -15,24 +15,24 @@ ot.SocketIOAdapter = (function () { self.trigger('set_name', clientId, name); }) .on('ack', function () { self.trigger('ack'); }) - .on('operation', function (clientId, operation, cursor) { - self.trigger('operation', operation); - self.trigger('cursor', clientId, cursor); + .on('operation', function (clientId, docId, operation, cursor) { + self.trigger('operation', docId, operation); + self.trigger('cursor', clientId, docId, cursor); }) - .on('cursor', function (clientId, cursor) { - self.trigger('cursor', clientId, cursor); + .on('cursor', function (clientId, docId, cursor) { + self.trigger('cursor', clientId, docId, cursor); }) .on('reconnect', function () { self.trigger('reconnect'); }); } - SocketIOAdapter.prototype.sendOperation = function (revision, operation, cursor) { - this.socket.emit('operation', revision, operation, cursor); + SocketIOAdapter.prototype.sendOperation = function (docId, revision, operation, cursor) { + this.socket.emit('operation', docId, revision, operation, cursor); }; - SocketIOAdapter.prototype.sendCursor = function (cursor) { - this.socket.emit('cursor', cursor); + SocketIOAdapter.prototype.sendCursor = function (docId, cursor) { + this.socket.emit('cursor', docId, cursor); }; SocketIOAdapter.prototype.registerCallbacks = function (cb) { @@ -47,4 +47,4 @@ ot.SocketIOAdapter = (function () { return SocketIOAdapter; -}()); \ No newline at end of file +}());