From c3a1c3e65dca6f3866420660c93cbd5c15beb748 Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 20 Jun 2017 03:05:54 -0700 Subject: [PATCH 01/19] Implemented collaboration with audio using webrtc --- src/editor/Collaboration.js | 68 +++++++++++++++++++++++++++++++++++++ src/editor/Editor.js | 4 +++ src/index.html | 1 + 3 files changed, 73 insertions(+) create mode 100644 src/editor/Collaboration.js diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js new file mode 100644 index 00000000000..a712dd3035b --- /dev/null +++ b/src/editor/Collaboration.js @@ -0,0 +1,68 @@ +define(function (require, exports, module) { + "use strict"; + + function Collaboration() { + var self = this; + var webrtc = new SimpleWebRTC({ + // the id/element dom element that will hold "our" videos + localVideoEl: 'localVideo', + // the id/element dom element that will hold remote videos + remoteVideosEl: 'remotesVideos', + // immediately ask for camera access + autoRequestMedia: true + }); + this.webrtc = webrtc; + this.webrtc.on('readyToCall', function () { + webrtc.joinRoom('thimble'); + }); + this.init(); + }; + + Collaboration.prototype.init = function() { + var self = this; + self.changing = false; + this.webrtc.connection.on('message', function (msg) { + if(msg.type == "data") { + var delta = msg.payload; + if(!self.codemirror || self.changing) { + return; + } + + self.changing = true; + var cm = self.codemirror; + var start = cm.indexFromPos(delta.from); + // apply the delete operation first + if (delta.removed.length > 0) { + var delLength = 0; + for (var i = 0; i < delta.removed.length; i++) { + delLength += delta.removed[i].length; + } + delLength += delta.removed.length - 1; + var from = cm.posFromIndex(start); + var to = cm.posFromIndex(start + delLength); + cm.replaceRange('', from, to); + } + // apply insert operation + var param = delta.text.join('\n'); + var from = cm.posFromIndex(start); + var to = from; + cm.replaceRange(param, from, to); + self.changing = false; + } + }); + }; + + Collaboration.prototype.setCodemirror = function(codemirror) { + this.codemirror = codemirror; + }; + + Collaboration.prototype.triggerCodemirrorChange = function(changeList) { + if(!this.changing) { + for(var i = 0; iBramble must be hosted + From 24c3ecccbec78a34f7682615b82d6679cf6f81e4 Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 20 Jun 2017 04:15:57 -0700 Subject: [PATCH 02/19] Shifted to load simplewebrtc.js from node_modules --- package.json | 1 + src/editor/Collaboration.js | 4 +++- src/index.html | 1 - src/main.js | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 48fcbf191e7..0460862b451 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "q": "1.4.1", "semver": "^4.1.0", "wolfy87-eventemitter": "^5.1.0", + "simplewebrtc": "^3.0.0", "xmldoc": "^0.1.2" }, "devDependencies": { diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index a712dd3035b..51549c03de2 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -1,6 +1,8 @@ define(function (require, exports, module) { "use strict"; + var SimpleWebRTC = require("simplewebrtc"); + function Collaboration() { var self = this; var webrtc = new SimpleWebRTC({ @@ -22,7 +24,7 @@ define(function (require, exports, module) { var self = this; self.changing = false; this.webrtc.connection.on('message', function (msg) { - if(msg.type == "data") { + if(msg.type === "data") { var delta = msg.payload; if(!self.codemirror || self.changing) { return; diff --git a/src/index.html b/src/index.html index 8f23576c7f4..d85c2cb7490 100644 --- a/src/index.html +++ b/src/index.html @@ -139,7 +139,6 @@

Bramble must be hosted

- diff --git a/src/main.js b/src/main.js index 552f501450f..587fdcd86d7 100644 --- a/src/main.js +++ b/src/main.js @@ -43,7 +43,8 @@ require.config({ // In various places in the code, it's useful to know if this is a dev vs. prod env. // See Gruntfile for prod override of this to config.prod.js. - "envConfig": "bramble/config/config.dev" + "envConfig" : "bramble/config/config.dev", + "simplewebrtc" : "../node_modules/simplewebrtc/out/simplewebrtc.bundle", }, map: { "*": { From 6230cc4442689a56643295fc0e12f19f8431e73c Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 20 Jun 2017 07:51:38 -0700 Subject: [PATCH 03/19] Added div to display peer video --- src/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.html b/src/index.html index d85c2cb7490..a579c4fc02d 100644 --- a/src/index.html +++ b/src/index.html @@ -132,6 +132,7 @@

Bramble must be hosted

require the "utils/AppInit" module and install a callback for "htmlReady" (e.g. AppInit.htmlReady(handler)) before touching the DOM. --> +
From 966e291bb874633e1a30e2f635108488015fb008 Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 20 Jun 2017 09:36:43 -0700 Subject: [PATCH 04/19] Removed video element --- src/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.html b/src/index.html index a579c4fc02d..d85c2cb7490 100644 --- a/src/index.html +++ b/src/index.html @@ -132,7 +132,6 @@

Bramble must be hosted

require the "utils/AppInit" module and install a callback for "htmlReady" (e.g. AppInit.htmlReady(handler)) before touching the DOM. --> -
From 81a87607c4239bb6a275849e3f12352c0ef461cf Mon Sep 17 00:00:00 2001 From: harkirat Date: Wed, 21 Jun 2017 12:13:47 -0700 Subject: [PATCH 05/19] Fixed structure of Collaboration.js --- src/editor/Collaboration.js | 44 ++++++++++++++----------------------- src/editor/Editor.js | 4 ++-- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 51549c03de2..cdbe968ad3b 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -4,36 +4,31 @@ define(function (require, exports, module) { var SimpleWebRTC = require("simplewebrtc"); function Collaboration() { - var self = this; var webrtc = new SimpleWebRTC({ - // the id/element dom element that will hold "our" videos - localVideoEl: 'localVideo', - // the id/element dom element that will hold remote videos - remoteVideosEl: 'remotesVideos', - // immediately ask for camera access - autoRequestMedia: true + // the id/element dom element that will hold "our" videos + localVideoEl: 'localVideo', + // the id/element dom element that will hold remote videos + remoteVideosEl: 'remotesVideos', + // immediately ask for camera access + autoRequestMedia: false }); this.webrtc = webrtc; - this.webrtc.on('readyToCall', function () { - webrtc.joinRoom('thimble'); - }); - this.init(); }; - Collaboration.prototype.init = function() { + Collaboration.prototype.init = function(codemirror) { + this.webrtc.joinRoom('thimble'); + this.changing = false; + this.codemirror = codemirror; var self = this; - self.changing = false; this.webrtc.connection.on('message', function (msg) { - if(msg.type === "data") { - var delta = msg.payload; - if(!self.codemirror || self.changing) { - return; + if(msg.type !== "data" || self.changing) { + return; } - + var delta = msg.payload; self.changing = true; var cm = self.codemirror; var start = cm.indexFromPos(delta.from); - // apply the delete operation first + // apply the delete operation first if (delta.removed.length > 0) { var delLength = 0; for (var i = 0; i < delta.removed.length; i++) { @@ -50,19 +45,14 @@ define(function (require, exports, module) { var to = from; cm.replaceRange(param, from, to); self.changing = false; - } }); }; - Collaboration.prototype.setCodemirror = function(codemirror) { - this.codemirror = codemirror; - }; - Collaboration.prototype.triggerCodemirrorChange = function(changeList) { if(!this.changing) { - for(var i = 0; i Date: Thu, 22 Jun 2017 13:19:32 -0700 Subject: [PATCH 06/19] Fixed spaces --- src/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.js b/src/main.js index 587fdcd86d7..6fdbcc94375 100644 --- a/src/main.js +++ b/src/main.js @@ -43,8 +43,8 @@ require.config({ // In various places in the code, it's useful to know if this is a dev vs. prod env. // See Gruntfile for prod override of this to config.prod.js. - "envConfig" : "bramble/config/config.dev", - "simplewebrtc" : "../node_modules/simplewebrtc/out/simplewebrtc.bundle", + "envConfig": "bramble/config/config.dev", + "simplewebrtc": "../node_modules/simplewebrtc/out/simplewebrtc.bundle", }, map: { "*": { From 723b7f75943177de1273535023cec00645c90313 Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 27 Jun 2017 09:36:04 -0700 Subject: [PATCH 07/19] Added initialization logic --- src/editor/Collaboration.js | 101 ++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index cdbe968ad3b..7e6e73c4238 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -1,7 +1,7 @@ define(function (require, exports, module) { "use strict"; - var SimpleWebRTC = require("simplewebrtc"); + var SimpleWebRTC = require("simplewebrtc"); function Collaboration() { var webrtc = new SimpleWebRTC({ @@ -13,39 +13,88 @@ define(function (require, exports, module) { autoRequestMedia: false }); this.webrtc = webrtc; + this.pending = []; // pending clients that need to be initialized. + this.changing = false; }; Collaboration.prototype.init = function(codemirror) { - this.webrtc.joinRoom('thimble'); - this.changing = false; - this.codemirror = codemirror; var self = this; + this.webrtc.joinRoom('thimble', function() { + self.codemirror = codemirror; + self.webrtc.sendToAll("new client", {}); + self.addListeners(); + }); + }; + + Collaboration.prototype.addListeners = function() { + var self = this; + this.webrtc.on("createdPeer", function(peer) { + self.initialiseNewClient(peer); + }); + this.webrtc.connection.on('message', function (msg) { - if(msg.type !== "data" || self.changing) { - return; + self.handleMessage(msg); + }); + }; + + Collaboration.prototype.handleMessage = function(msg) { + if(msg.type === "new client") { + this.addToPending(msg.from); + } + if(this.changing) { + return; + } + if(msg.type === "data") { + this.handleCodemirrorChange(msg.payload); + } + if(msg.type === "initClient") { + this.initiseEditor(msg.payload); + } + }; + + Collaboration.prototype.addToPending = function(id) { + this.pending.push(id); + }; + + Collaboration.prototype.initiseEditor = function(value) { + this.changing = true; + this.codemirror.setValue(value); + this.changing = false; + }; + + Collaboration.prototype.initialiseNewClient = function(peer) { + this.changing = true; + for(var i = 0; i 0) { - var delLength = 0; - for (var i = 0; i < delta.removed.length; i++) { - delLength += delta.removed[i].length; - } - delLength += delta.removed.length - 1; - var from = cm.posFromIndex(start); - var to = cm.posFromIndex(start + delLength); - cm.replaceRange('', from, to); + } + this.changing = false; + }; + + Collaboration.prototype.handleCodemirrorChange = function(delta) { + this.changing = true; + var cm = this.codemirror; + var start = cm.indexFromPos(delta.from); + // apply the delete operation first + if (delta.removed.length > 0) { + var delLength = 0; + for (var i = 0; i < delta.removed.length; i++) { + delLength += delta.removed[i].length; } - // apply insert operation - var param = delta.text.join('\n'); + delLength += delta.removed.length - 1; var from = cm.posFromIndex(start); - var to = from; - cm.replaceRange(param, from, to); - self.changing = false; - }); + var to = cm.posFromIndex(start + delLength); + cm.replaceRange('', from, to); + } + // apply insert operation + var param = delta.text.join('\n'); + var from = cm.posFromIndex(start); + var to = from; + cm.replaceRange(param, from, to); + this.changing = false; }; Collaboration.prototype.triggerCodemirrorChange = function(changeList) { From 1736e062e0c3c97511d6ae5de9372ee890f93f62 Mon Sep 17 00:00:00 2001 From: harkirat Date: Tue, 27 Jun 2017 23:41:24 -0700 Subject: [PATCH 08/19] Shifted to switch cases from for loop --- src/editor/Collaboration.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 7e6e73c4238..772c093ad2e 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -38,17 +38,16 @@ define(function (require, exports, module) { }; Collaboration.prototype.handleMessage = function(msg) { - if(msg.type === "new client") { - this.addToPending(msg.from); - } - if(this.changing) { - return; - } - if(msg.type === "data") { - this.handleCodemirrorChange(msg.payload); - } - if(msg.type === "initClient") { - this.initiseEditor(msg.payload); + switch(msg.type) { + case "new client": + this.addToPending(msg.from); + break; + case "data": + this.handleCodemirrorChange(msg.payload); + break; + case "initClient": + this.initiseEditor(msg.payload); + break; } }; @@ -57,6 +56,9 @@ define(function (require, exports, module) { }; Collaboration.prototype.initiseEditor = function(value) { + if(this.changing) { + return; + } this.changing = true; this.codemirror.setValue(value); this.changing = false; @@ -75,6 +77,9 @@ define(function (require, exports, module) { }; Collaboration.prototype.handleCodemirrorChange = function(delta) { + if(this.changing) { + return; + } this.changing = true; var cm = this.codemirror; var start = cm.indexFromPos(delta.from); From ce5d1ab81076749cdd2d1fcf585ca8788da78aa3 Mon Sep 17 00:00:00 2001 From: harkirat Date: Thu, 29 Jun 2017 23:40:45 -0700 Subject: [PATCH 09/19] Implemeted review comments --- src/editor/Collaboration.js | 51 +++++++++++++++---------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 772c093ad2e..2a3b6434718 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -22,49 +22,37 @@ define(function (require, exports, module) { this.webrtc.joinRoom('thimble', function() { self.codemirror = codemirror; self.webrtc.sendToAll("new client", {}); - self.addListeners(); - }); - }; - - Collaboration.prototype.addListeners = function() { - var self = this; - this.webrtc.on("createdPeer", function(peer) { - self.initialiseNewClient(peer); - }); + self.webrtc.on("createdPeer", function(peer) { + self.initializeNewClient(peer); + }); - this.webrtc.connection.on('message', function (msg) { - self.handleMessage(msg); + self.webrtc.connection.on('message', function (msg) { + self.handleMessage(msg); + }); }); }; Collaboration.prototype.handleMessage = function(msg) { switch(msg.type) { case "new client": - this.addToPending(msg.from); + this.pending.push(msg.from); break; - case "data": + case "codemirror-change": this.handleCodemirrorChange(msg.payload); break; case "initClient": - this.initiseEditor(msg.payload); + if(this.changing) { + return; + } + this.changing = true; + this.codemirror.setValue(msg.payload); + this.changing = false; break; } }; - Collaboration.prototype.addToPending = function(id) { - this.pending.push(id); - }; - Collaboration.prototype.initiseEditor = function(value) { - if(this.changing) { - return; - } - this.changing = true; - this.codemirror.setValue(value); - this.changing = false; - }; - - Collaboration.prototype.initialiseNewClient = function(peer) { + Collaboration.prototype.initializeNewClient = function(peer) { this.changing = true; for(var i = 0; i Date: Sat, 1 Jul 2017 04:32:08 -0700 Subject: [PATCH 10/19] Added unique rooms to prevent clashes --- src/editor/Collaboration.js | 11 +++++++++-- src/hosted.js | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 2a3b6434718..de6178a54ee 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -12,6 +12,14 @@ define(function (require, exports, module) { // immediately ask for camera access autoRequestMedia: false }); + var hash = location.hash.replace(/^#/, ""); + var m = /&?collaboration=([^&]*)/.exec(hash); + if(m && m[1]) { + this.room = m[1]; + } else { + this.room = Math.random().toString(36).substring(7); + } + console.log("room is " + this.room); this.webrtc = webrtc; this.pending = []; // pending clients that need to be initialized. this.changing = false; @@ -19,7 +27,7 @@ define(function (require, exports, module) { Collaboration.prototype.init = function(codemirror) { var self = this; - this.webrtc.joinRoom('thimble', function() { + this.webrtc.joinRoom("brackets-"+this.room, function() { self.codemirror = codemirror; self.webrtc.sendToAll("new client", {}); self.webrtc.on("createdPeer", function(peer) { @@ -51,7 +59,6 @@ define(function (require, exports, module) { } }; - Collaboration.prototype.initializeNewClient = function(peer) { this.changing = true; for(var i = 0; i Date: Sat, 1 Jul 2017 07:06:51 -0700 Subject: [PATCH 11/19] Logged url --- src/editor/Collaboration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index de6178a54ee..71a9d9746fe 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -19,7 +19,7 @@ define(function (require, exports, module) { } else { this.room = Math.random().toString(36).substring(7); } - console.log("room is " + this.room); + console.log("Link -> http://localhost:8000/src/hosted.html#?collaboration=" + this.room); this.webrtc = webrtc; this.pending = []; // pending clients that need to be initialized. this.changing = false; From 999d282614c93ae1c7e36cf034ab1c00d55fb2ca Mon Sep 17 00:00:00 2001 From: harkirat Date: Mon, 3 Jul 2017 01:05:21 -0700 Subject: [PATCH 12/19] Added logic to restrict changes amongst files --- src/editor/Collaboration.js | 39 ++++++++++++++++++++++++++----------- src/editor/Editor.js | 2 +- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 71a9d9746fe..ef773551146 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -2,6 +2,8 @@ define(function (require, exports, module) { "use strict"; var SimpleWebRTC = require("simplewebrtc"); + var StartupState = require("bramble/StartupState"); + var EditorManager = require("editor/EditorManager"); function Collaboration() { var webrtc = new SimpleWebRTC({ @@ -19,16 +21,9 @@ define(function (require, exports, module) { } else { this.room = Math.random().toString(36).substring(7); } - console.log("Link -> http://localhost:8000/src/hosted.html#?collaboration=" + this.room); - this.webrtc = webrtc; - this.pending = []; // pending clients that need to be initialized. - this.changing = false; - }; - Collaboration.prototype.init = function(codemirror) { var self = this; - this.webrtc.joinRoom("brackets-"+this.room, function() { - self.codemirror = codemirror; + webrtc.joinRoom("brackets-"+this.room, function() { self.webrtc.sendToAll("new client", {}); self.webrtc.on("createdPeer", function(peer) { self.initializeNewClient(peer); @@ -38,6 +33,15 @@ define(function (require, exports, module) { self.handleMessage(msg); }); }); + + console.log("Link -> http://localhost:8000/src/hosted.html#?collaboration=" + this.room); + this.webrtc = webrtc; + this.pending = []; // pending clients that need to be initialized. + this.changing = false; + }; + + Collaboration.prototype.init = function(codemirror) { + this.codemirror = codemirror; }; Collaboration.prototype.handleMessage = function(msg) { @@ -60,6 +64,7 @@ define(function (require, exports, module) { }; Collaboration.prototype.initializeNewClient = function(peer) { + // TODO: Recursively send all files, not just the currently open file. this.changing = true; for(var i = 0; i Date: Tue, 4 Jul 2017 08:07:39 -0700 Subject: [PATCH 13/19] Emmitted and cached all filesystem events and events for initialization --- src/editor/Collaboration.js | 114 ++++++++++++++++++++++++++++++++---- src/editor/Initializer.js | 50 ++++++++++++++++ 2 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 src/editor/Initializer.js diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index ef773551146..236212a10b1 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -4,6 +4,9 @@ define(function (require, exports, module) { var SimpleWebRTC = require("simplewebrtc"); var StartupState = require("bramble/StartupState"); var EditorManager = require("editor/EditorManager"); + var Initializer = require("editor/Initializer"); + var FileSystemEntry = require("filesystem/FileSystem"); + function Collaboration() { var webrtc = new SimpleWebRTC({ @@ -21,9 +24,8 @@ define(function (require, exports, module) { } else { this.room = Math.random().toString(36).substring(7); } - var self = this; - webrtc.joinRoom("brackets-"+this.room, function() { + webrtc.joinRoom("brackets-" + this.room, function() { self.webrtc.sendToAll("new client", {}); self.webrtc.on("createdPeer", function(peer) { self.initializeNewClient(peer); @@ -57,39 +59,85 @@ define(function (require, exports, module) { return; } this.changing = true; - this.codemirror.setValue(msg.payload); + EditorManager.getCurrentFullEditor()._codeMirror.setValue(msg.payload); this.changing = false; break; + case "initFiles": + if(this.fileIsCurrentlyOpen(msg.payload.path.replace(StartupState.project("root"), ""))) { + this.changing = true; + EditorManager.getCurrentFullEditor()._codeMirror.setValue(msg.payload.content); + this.changing = false; + console.log("file changed in codemirror" + msg.payload.path); + } else { + var file = FileSystemEntry.getFileForPath(msg.payload.path); + if(!file) { + return; + } + file.write(msg.payload.content, {}, function(err) { + console.log(err); + }); + } + break; } }; Collaboration.prototype.initializeNewClient = function(peer) { - // TODO: Recursively send all files, not just the currently open file. this.changing = true; for(var i = 0; i 0) { @@ -123,5 +171,51 @@ define(function (require, exports, module) { } }; + Collaboration.prototype.replaceRange = function(text, param, from, to) { + //Assuming change in same line + var lines = text.split("\n"); + //return text.slice(0, from) + param + text.slice( to, this.indexFromPos({line: text.length, ch: text[text.length - 1].length })); + if(from.line === to.line) { + lines[from.line] = lines[from.line].slice(0, from.ch) + param + lines[from.line].slice(to.ch, lines[from.line].length); + } else { + lines[from.line] = lines[from.line].slice(0, from.ch); + lines[to.line] = lines[to.line].slice(to.ch, text[from.line].length); + } + for(var i = from.line + 1; itext[i].length) { + i++; + index-=text[i].length; + } + } catch (e) { + console.log("exception : "+e); + } + return {line: i, ch: index}; + }; + exports.Collaboration = Collaboration; }); diff --git a/src/editor/Initializer.js b/src/editor/Initializer.js new file mode 100644 index 00000000000..b04c018331d --- /dev/null +++ b/src/editor/Initializer.js @@ -0,0 +1,50 @@ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ +/*global define */ + +define(function (require, exports, module) { + "use strict"; + + var Content = require("filesystem/impls/filer/lib/content"); + var async = require("filesystem/impls/filer/lib/async"); + var BracketsFiler = require("filesystem/impls/filer/BracketsFiler"); + var UrlCache = require("filesystem/impls/filer/UrlCache"); + var Path = BracketsFiler.Path; + var Transforms = require("filesystem/impls/filer/lib/transforms"); + var StartupState = require("bramble/StartupState"); + var decodePath = require("filesystem/impls/filer/FilerUtils").decodePath; + + // Walk the project root dir and make sure we have URLs generated for + // all file paths. Skip CSS and HTML files, since we need to rewrite them + // before they are useful (e.g., for linked files within them). + exports.initialize = function(callback) { + var fs = BracketsFiler.fs(); + function _load(dirPath, callback) { + fs.readdir(dirPath, function(err, entries) { + if(err) { + return callback(err); + } + + function _getUrl(name, callback) { + name = Path.join(dirPath, name); + fs.stat(name, function(err, stats) { + if(err) { + return callback(err); + } + if(stats.type === 'DIRECTORY') { + _load(name, callback); + } else { + var decodedFilename = decodePath(name); + callback(decodedFilename); + } + }); + } + for(var i = 0; i Date: Wed, 5 Jul 2017 08:22:46 -0700 Subject: [PATCH 14/19] Shifted to syncing all open codemirror systems rather than just the open one --- src/editor/Collaboration.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 236212a10b1..a538b2cc857 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -6,8 +6,8 @@ define(function (require, exports, module) { var EditorManager = require("editor/EditorManager"); var Initializer = require("editor/Initializer"); var FileSystemEntry = require("filesystem/FileSystem"); - - + var DocumentManager = require("document/DocumentManager"); + function Collaboration() { var webrtc = new SimpleWebRTC({ // the id/element dom element that will hold "our" videos @@ -63,9 +63,10 @@ define(function (require, exports, module) { this.changing = false; break; case "initFiles": - if(this.fileIsCurrentlyOpen(msg.payload.path.replace(StartupState.project("root"), ""))) { + var cm = this.getOpenCodemirrorInstance(msg.payload.path.replace(StartupState.project("root"), "")); + if(cm) { this.changing = true; - EditorManager.getCurrentFullEditor()._codeMirror.setValue(msg.payload.content); + cm.setValue(msg.payload.content); this.changing = false; console.log("file changed in codemirror" + msg.payload.path); } else { @@ -109,10 +110,12 @@ define(function (require, exports, module) { var delta = params.delta; var relPath = params.path; var fullPath = StartupState.project("root") + relPath; - if(!this.fileIsCurrentlyOpen(params.path)) { + var cm = this.getOpenCodemirrorInstance(params.path); + if(!cm) { var file = FileSystemEntry.getFileForPath(fullPath); var self = this; - file.read({}, function(err, text) { + console.log("writting to file" + file); + /*file.read({}, function(err, text) { self.changing = true; if(delta.removed.length) { var start = self.indexFromPos(text, delta.from); @@ -133,11 +136,10 @@ define(function (require, exports, module) { console.log(err); }); self.changing = false; - }); + });*/ return; } this.changing = true; - var cm = EditorManager.getCurrentFullEditor()._codeMirror; var start = cm.indexFromPos(delta.from); // apply the delete operation first if (delta.removed.length > 0) { @@ -197,10 +199,13 @@ define(function (require, exports, module) { return ch; }; - Collaboration.prototype.fileIsCurrentlyOpen = function(relPath) { + Collaboration.prototype.getOpenCodemirrorInstance = function(relPath) { var fullPath = StartupState.project("root") + relPath; - var currentEditor = EditorManager.getCurrentFullEditor(); - return currentEditor.getFile(relPath).fullPath === fullPath; + var doc = DocumentManager.getOpenDocumentForPath(fullPath); + if(doc && doc._masterEditor) { + return doc._masterEditor._codeMirror; + } + return null; }; Collaboration.prototype.posFromIndex = function(text, index) { From 877388cec5dabbf644575009b62ee5b0fd78fd67 Mon Sep 17 00:00:00 2001 From: harkirat Date: Fri, 7 Jul 2017 10:44:05 -0700 Subject: [PATCH 15/19] Removed code that modified filesystems, shifted to logging for now --- src/editor/Collaboration.js | 64 +------------------------------------ 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 68f062e5885..90f5a9519f3 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -116,29 +116,7 @@ define(function (require, exports, module) { if(!cm) { var file = FileSystemEntry.getFileForPath(fullPath); var self = this; - console.log("writting to file" + file); - /*file.read({}, function(err, text) { - self.changing = true; - if(delta.removed.length) { - var start = self.indexFromPos(text, delta.from); - var delLength = 0; - for (var i = 0; i < delta.removed.length; i++) { - delLength += delta.removed[i].length; - } - delLength += delta.removed.length - 1; - var from = self.indexFromPos(text, start); - var to = self.posFromIndex(text, start + delLength); - text = self.replaceRange(text, '', self.posFromIndex(text, start), to); - } - var param = delta.text.join('\n'); - var from = self.posFromIndex(text, start); - var to = from; - text = self.replaceRange(text, param, from, to); - file.write(text, {}, function(err) { - console.log(err); - }); - self.changing = false; - });*/ + console.log("writting to file which is not open in editor." + file); return; } this.changing = true; @@ -175,32 +153,6 @@ define(function (require, exports, module) { } }; - Collaboration.prototype.replaceRange = function(text, param, from, to) { - //Assuming change in same line - var lines = text.split("\n"); - //return text.slice(0, from) + param + text.slice( to, this.indexFromPos({line: text.length, ch: text[text.length - 1].length })); - if(from.line === to.line) { - lines[from.line] = lines[from.line].slice(0, from.ch) + param + lines[from.line].slice(to.ch, lines[from.line].length); - } else { - lines[from.line] = lines[from.line].slice(0, from.ch); - lines[to.line] = lines[to.line].slice(to.ch, text[from.line].length); - } - for(var i = from.line + 1; itext[i].length) { - i++; - index-=text[i].length; - } - } catch (e) { - console.log("exception : "+e); - } - return {line: i, ch: index}; - }; - exports.Collaboration = Collaboration; }); From de690011fce0c50cdc9d1d99a56f4afc5caf90ba Mon Sep 17 00:00:00 2001 From: harkirat Date: Fri, 7 Jul 2017 11:41:45 -0700 Subject: [PATCH 16/19] Removed redundant event --- src/editor/Collaboration.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 90f5a9519f3..587425659fc 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -56,14 +56,6 @@ define(function (require, exports, module) { case "codemirror-change": this.handleCodemirrorChange(msg.payload); break; - case "initClient": - if(this.changing) { - return; - } - this.changing = true; - EditorManager.getCurrentFullEditor()._codeMirror.setValue(msg.payload); - this.changing = false; - break; case "initFiles": var cm = this.getOpenCodemirrorInstance(msg.payload.path.replace(StartupState.project("root"), "")); if(cm) { @@ -72,6 +64,7 @@ define(function (require, exports, module) { this.changing = false; console.log("file changed in codemirror" + msg.payload.path); } else { + // No cm instance attached to file, need to change directly in indexeddb. var file = FileSystemEntry.getFileForPath(msg.payload.path); if(!file) { return; @@ -85,14 +78,6 @@ define(function (require, exports, module) { }; Collaboration.prototype.initializeNewClient = function(peer) { - this.changing = true; - for(var i = 0; i Date: Fri, 7 Jul 2017 14:10:08 -0700 Subject: [PATCH 17/19] Implemented review comments --- src/bramble/client/main.js | 5 +- src/editor/Collaboration.js | 112 +++++++++--------- src/editor/Editor.js | 6 +- .../bramble/lib/RemoteCommandHandler.js | 6 + src/hosted.js | 12 +- 5 files changed, 71 insertions(+), 70 deletions(-) diff --git a/src/bramble/client/main.js b/src/bramble/client/main.js index b55251481ff..bee93548182 100644 --- a/src/bramble/client/main.js +++ b/src/bramble/client/main.js @@ -285,7 +285,9 @@ define([ if (options.hideUntilReady) { _iframe.style.visibility = "visible"; } - + if(options.enableCollaboration) { + self._executeRemoteCommand({commandCategory: "bramble", command: "INITIALIZE_COLLABORATION",args: [{collaborationUrl: options.collaborationUrl}]}); + } // Set intial state _state.fullPath = data.fullPath; _state.filename = data.filename; @@ -304,7 +306,6 @@ define([ _state.autoUpdate = data.autoUpdate; _state.openSVGasXML = data.openSVGasXML; - setReadyState(Bramble.READY); } // Listen for callbacks from commands we triggered via _executeRemoteCommand else if(data.type === "bramble:remoteCommand:callback") { diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 04cddbfe4cf..1fd44bf66a7 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -1,15 +1,24 @@ define(function (require, exports, module) { "use strict"; - var SimpleWebRTC = require("simplewebrtc"); - var StartupState = require("bramble/StartupState"); - var EditorManager = require("editor/EditorManager"); - var Initializer = require("editor/Initializer"); - var FileSystemEntry = require("filesystem/FileSystem"); - var DocumentManager = require("document/DocumentManager"); + var SimpleWebRTC = require("simplewebrtc"), + StartupState = require("bramble/StartupState"), + EditorManager = require("editor/EditorManager"), + Initializer = require("editor/Initializer"), + FileSystemEntry = require("filesystem/FileSystem"), + DocumentManager = require("document/DocumentManager"); - function Collaboration() { - var webrtc = new SimpleWebRTC({ + var _webrtc; + var _changing; + var _pending; + var _room; + + function initialize(options) { + if(_webrtc) { + console.error("Collaboration already initialized"); + return; + } + _webrtc = new SimpleWebRTC({ // the id/element dom element that will hold "our" videos localVideoEl: 'localVideo', // the id/element dom element that will hold remote videos @@ -17,47 +26,39 @@ define(function (require, exports, module) { // immediately ask for camera access autoRequestMedia: false, // TODO : Shift this to config. - url: "localhost:8888" + url: options.collaborationUrl }); - //To be moved to the bramble API. - var query = (new URL(window.location.href)).searchParams; - this.room = query.get("collaboration") || Math.random().toString(36).substring(7); - var self = this; - webrtc.joinRoom("brackets-" + this.room, function() { - self.webrtc.sendToAll("new client", {}); - self.webrtc.on("createdPeer", function(peer) { - self.initializeNewClient(peer); + _room = options.room; + _webrtc.joinRoom(_room, function() { + _webrtc.sendToAll("new client", {}); + _webrtc.on("createdPeer", function(peer) { + _initializeNewClient(peer); }); - self.webrtc.connection.on('message', function (msg) { - self.handleMessage(msg); + _webrtc.connection.on('message', function (msg) { + _handleMessage(msg); }); }); - console.log(this.room); - this.webrtc = webrtc; - this.pending = []; // pending clients that need to be initialized. - this.changing = false; + console.log(_room); + _pending = []; // pending clients that need to be initialized. + _changing = false; }; - Collaboration.prototype.init = function(codemirror) { - this.codemirror = codemirror; - }; - - Collaboration.prototype.handleMessage = function(msg) { + function _handleMessage(msg) { switch(msg.type) { case "new client": - this.pending.push(msg.from); + _pending.push(msg.from); break; case "codemirror-change": - this.handleCodemirrorChange(msg.payload); + _handleCodemirrorChange(msg.payload); break; case "initFiles": - var cm = this.getOpenCodemirrorInstance(msg.payload.path.replace(StartupState.project("root"), "")); + var cm = _getOpenCodemirrorInstance(msg.payload.path.replace(StartupState.project("root"), "")); if(cm) { - this.changing = true; + _changing = true; cm.setValue(msg.payload.content); - this.changing = false; - console.log("file changed in codemirror" + msg.payload.path); + _changing = false; + console.log("file initializing in codemirror" + msg.payload.path); } else { // No cm instance attached to file, need to change directly in indexeddb. var file = FileSystemEntry.getFileForPath(msg.payload.path); @@ -67,14 +68,13 @@ define(function (require, exports, module) { file.write(msg.payload.content, {}, function(err) { console.log(err); }); + console.log("file initializing in indexeddb" + msg.payload.path); } break; } }; - Collaboration.prototype.initializeNewClient = function(peer) { - this.changing = false; - var self = this; + function _initializeNewClient(peer) { Initializer.initialize(function(fileName) { var file = FileSystemEntry.getFileForPath(fileName); file.read({}, function(err, text) { @@ -85,21 +85,20 @@ define(function (require, exports, module) { }); }; - Collaboration.prototype.handleCodemirrorChange = function(params) { - if(this.changing) { + function _handleCodemirrorChange(params) { + if(_changing) { return; } var delta = params.delta; var relPath = params.path; var fullPath = StartupState.project("root") + relPath; - var cm = this.getOpenCodemirrorInstance(params.path); + var cm = _getOpenCodemirrorInstance(params.path); if(!cm) { var file = FileSystemEntry.getFileForPath(fullPath); - var self = this; console.log("writting to file which is not open in editor." + file); return; } - this.changing = true; + _changing = true; var start = cm.indexFromPos(delta.from); // apply the delete operation first if (delta.removed.length > 0) { @@ -117,30 +116,31 @@ define(function (require, exports, module) { var from = cm.posFromIndex(start); var to = from; cm.replaceRange(param, from, to); - this.changing = false; + _changing = false; }; - Collaboration.prototype.triggerCodemirrorChange = function(changeList, fullPath) { - if(this.changing) { + function _getOpenCodemirrorInstance(relPath) { + var fullPath = StartupState.project("root") + relPath; + var doc = DocumentManager.getOpenDocumentForPath(fullPath); + if(doc && doc._masterEditor) { + return doc._masterEditor._codeMirror; + } + return null; + }; + + function triggerCodemirrorChange(changeList, fullPath) { + if(_changing) { return; } var relPath = fullPath.replace(StartupState.project("root"), ""); for(var i = 0; i Date: Mon, 10 Jul 2017 10:57:34 -0700 Subject: [PATCH 18/19] Removed file initialization logic --- src/editor/Collaboration.js | 11 +------- src/editor/Initializer.js | 50 ------------------------------------- 2 files changed, 1 insertion(+), 60 deletions(-) delete mode 100644 src/editor/Initializer.js diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index 1fd44bf66a7..cf8b7092577 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -3,8 +3,6 @@ define(function (require, exports, module) { var SimpleWebRTC = require("simplewebrtc"), StartupState = require("bramble/StartupState"), - EditorManager = require("editor/EditorManager"), - Initializer = require("editor/Initializer"), FileSystemEntry = require("filesystem/FileSystem"), DocumentManager = require("document/DocumentManager"); @@ -75,14 +73,7 @@ define(function (require, exports, module) { }; function _initializeNewClient(peer) { - Initializer.initialize(function(fileName) { - var file = FileSystemEntry.getFileForPath(fileName); - file.read({}, function(err, text) { - if(!err) { - peer.send("initFiles", {path: fileName, content: text}); - } - }); - }); + //Add logic to initialize files for the new peer. }; function _handleCodemirrorChange(params) { diff --git a/src/editor/Initializer.js b/src/editor/Initializer.js deleted file mode 100644 index b04c018331d..00000000000 --- a/src/editor/Initializer.js +++ /dev/null @@ -1,50 +0,0 @@ -/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ -/*global define */ - -define(function (require, exports, module) { - "use strict"; - - var Content = require("filesystem/impls/filer/lib/content"); - var async = require("filesystem/impls/filer/lib/async"); - var BracketsFiler = require("filesystem/impls/filer/BracketsFiler"); - var UrlCache = require("filesystem/impls/filer/UrlCache"); - var Path = BracketsFiler.Path; - var Transforms = require("filesystem/impls/filer/lib/transforms"); - var StartupState = require("bramble/StartupState"); - var decodePath = require("filesystem/impls/filer/FilerUtils").decodePath; - - // Walk the project root dir and make sure we have URLs generated for - // all file paths. Skip CSS and HTML files, since we need to rewrite them - // before they are useful (e.g., for linked files within them). - exports.initialize = function(callback) { - var fs = BracketsFiler.fs(); - function _load(dirPath, callback) { - fs.readdir(dirPath, function(err, entries) { - if(err) { - return callback(err); - } - - function _getUrl(name, callback) { - name = Path.join(dirPath, name); - fs.stat(name, function(err, stats) { - if(err) { - return callback(err); - } - if(stats.type === 'DIRECTORY') { - _load(name, callback); - } else { - var decodedFilename = decodePath(name); - callback(decodedFilename); - } - }); - } - for(var i = 0; i Date: Mon, 10 Jul 2017 11:08:45 -0700 Subject: [PATCH 19/19] Trimmed collaboration.js --- src/editor/Collaboration.js | 54 ++++++++++++------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/src/editor/Collaboration.js b/src/editor/Collaboration.js index cf8b7092577..53d126ab547 100644 --- a/src/editor/Collaboration.js +++ b/src/editor/Collaboration.js @@ -2,9 +2,7 @@ define(function (require, exports, module) { "use strict"; var SimpleWebRTC = require("simplewebrtc"), - StartupState = require("bramble/StartupState"), - FileSystemEntry = require("filesystem/FileSystem"), - DocumentManager = require("document/DocumentManager"); + StartupState = require("bramble/StartupState"); var _webrtc; var _changing; @@ -50,30 +48,27 @@ define(function (require, exports, module) { case "codemirror-change": _handleCodemirrorChange(msg.payload); break; - case "initFiles": - var cm = _getOpenCodemirrorInstance(msg.payload.path.replace(StartupState.project("root"), "")); - if(cm) { - _changing = true; - cm.setValue(msg.payload.content); - _changing = false; - console.log("file initializing in codemirror" + msg.payload.path); - } else { - // No cm instance attached to file, need to change directly in indexeddb. - var file = FileSystemEntry.getFileForPath(msg.payload.path); - if(!file) { - return; - } - file.write(msg.payload.content, {}, function(err) { - console.log(err); - }); - console.log("file initializing in indexeddb" + msg.payload.path); + case "initClient": + if(this.changing) { + return; } + this.changing = true; + this.codemirror.setValue(msg.payload); + this.changing = false; break; } }; - function _initializeNewClient(peer) { - //Add logic to initialize files for the new peer. + function _initializeNewClient(peer) { + this.changing = true; + for(var i = 0; i