Skip to content

Commit 42ecb9e

Browse files
committed
Use standard save pattern (fix #52 and #53)
1 parent 949978c commit 42ecb9e

11 files changed

Lines changed: 120 additions & 31 deletions

File tree

addons/editor/addon-built.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

addons/editor/views/base.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ define([], function() {
1818
// Constructor
1919
initialize: function(options) {
2020
FilesBaseView.__super__.initialize.apply(this, arguments);
21-
if (this.model == null) this.model = new File({
22-
"codebox": box
23-
});
21+
22+
// Related tab
23+
this.tab = this.parent;
24+
25+
// Create base model
26+
if (this.model == null) this.model = new File({"codebox": box});
2427
this.model.on("set", this.render, this);
28+
29+
// Load base file
2530
if (this.options.path != null) this.load(this.options.path);
2631
return this;
2732
},

addons/editor/views/editor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ define([
130130
name: 'save',
131131
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
132132
exec: _.bind(function(editor) {
133-
133+
this.sync.save();
134134
}, this)
135135
});
136136
this.focus();

addons/editor/views/file.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,39 @@ define([
2323
// Build editor
2424
this.editor = new EditorView();
2525

26+
// Parent tab
27+
this.tab.on("tab:state", function(state) {
28+
if (state) this.editor.focus();
29+
}, this);
30+
this.tab.on("tab:close", function() {
31+
this.editor.sync.close();
32+
this.editor.off();
33+
}, this);
34+
2635
// Bind editor sync state changements
27-
this.editor.on("sync:state", function(state) {
28-
this.$(".action-editor-state").toggleClass("btn-danger", !state);
29-
this.$(".action-editor-state").toggleClass("btn-success", state);
36+
this.editor.sync.on("sync:state", function(state) {
37+
if (!state) {
38+
this.tab.setTabState("offline", true);
39+
} else {
40+
this.tab.setTabState("offline", false);
41+
}
42+
}, this);
43+
44+
this.editor.sync.on("sync:modified", function(state) {
45+
this.tab.setTabState("warning", state);
3046
}, this);
3147

3248
// Define file for code editor
3349
this.editor.sync.setFile(this.model, {
3450
'sync': this.options.edition
3551
});
36-
37-
// Parent tab
38-
this.parent.on("tab:state", function(state) {
39-
if (state) this.editor.focus();
40-
}, this);
41-
this.parent.on("tab:close", function() {
42-
this.editor.sync.close();
43-
}, this);
4452
this.editor.focus();
4553
},
4654

4755
// Finish rendering
4856
finish: function() {
4957
// Add editor to content
5058
this.editor.$el.appendTo(this.$(".editor-inner"));
51-
this.modeChanged();
52-
this.updateParticipants();
5359

5460
return FileEditorView.__super__.finish.apply(this, arguments);
5561
}

client/resources/stylesheets/components/tabs.less

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
z-index: 1;
4343
}
4444

45+
.state {
46+
margin-right: 5px;
47+
}
48+
4549
.close {
4650
margin-left: 8px;
4751
font-weight: 200;

client/utils/filesync.js

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ define([
5555
this.ping = false; // ping
5656
this.participants = []; // participants list
5757
this.syncState = false; // sync connexion state
58+
this.modified = false;
5859

5960
// Add timer for ping
6061
this.timer = setInterval(_.bind(this._intervalPing, this), 15*1000);
@@ -222,7 +223,7 @@ define([
222223
logging.log("socket connecting ...");
223224
});
224225
socket.on('message', function(data) {
225-
logging.log("socket editor packet ", data);
226+
logging.log("socket receive packet ", data);
226227
self.ping = true;
227228
if (data.action == null || data.path == null || self.file.path() != data.path) {
228229
return;
@@ -252,12 +253,20 @@ define([
252253
if (data.participants != null) {
253254
self.setParticipants(data.participants)
254255
}
256+
if (data.state != null) {
257+
self.modifiedState(data.state);
258+
}
255259
break;
256260
case "patch":
257261
if (data.patch != null) {
258262
self.patchContent(data);
259263
}
260264
break;
265+
case "modified":
266+
if (data.state != null) {
267+
self.modifiedState(data.state);
268+
}
269+
break;
261270
}
262271
self.setSyncState(true);
263272
});
@@ -267,6 +276,15 @@ define([
267276
}
268277
},
269278

279+
/*
280+
* Set modified (and not saved) state
281+
*/
282+
modifiedState: function(state) {
283+
if (this.modified == state) return;
284+
this.modified = state;
285+
this.trigger("sync:modified", this.modified);
286+
},
287+
270288
/*
271289
* Set file to the editor
272290
*/
@@ -290,8 +308,14 @@ define([
290308

291309
/* Socket for the connexion */
292310
socket: function() {
311+
var that = this;
312+
313+
if (this._socket) return Q(this._socket);
293314
if (this.file != null) {
294-
return this.file.codebox.socket("filesync");
315+
return this.file.codebox.socket("filesync", true).then(function(s) {
316+
that._socket = s;
317+
return that._socket;
318+
})
295319
} else {
296320
throw new Error("need 'file' to create sync socket");
297321
}
@@ -486,7 +510,7 @@ define([
486510
this.participants = _.compact(_.map(parts, function(participant, i) {
487511
participant.user = collaborators.getById(participant.userId);
488512
if (!participant.user) {
489-
logger.error("participant non user:", participant.userId);
513+
logging.error("participant non user:", participant.userId);
490514
return null;
491515
}
492516
participant.color = this.options.colors[i % this.options.colors.length];
@@ -522,6 +546,7 @@ define([
522546
'path': this.file.path()
523547
});
524548

549+
logging.log("send packet", data);
525550
this.socket().then(function(socket) {
526551
socket.json.send(data);
527552
})
@@ -602,11 +627,19 @@ define([
602627
return true;
603628
},
604629

630+
/*
631+
* Save the file
632+
*/
633+
save: function() {
634+
return this.send("save");
635+
},
636+
605637
/*
606638
* Close the connexion
607639
*/
608640
close: function() {
609-
return this.send("close");
641+
this.send("close");
642+
this.off();
610643
},
611644
});
612645

client/views/components/tabs.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ define([
1919
"dblclick": "createSection",
2020
"dragstart": "dragStart"
2121
},
22+
states: {
23+
'warning': "fa-exclamation",
24+
'offline': "fa-flash"
25+
},
2226

2327
// Constructor
2428
initialize: function() {
@@ -36,11 +40,19 @@ define([
3640
render: function() {
3741
this.$el.empty();
3842

43+
var tab = this.tabs.tabs[this.tabid];
44+
3945
var inner = $("<div>", {
4046
"class": "inner",
41-
"html": this.tabs.tabs[this.tabid].title
47+
"html": tab.title
4248
}).appendTo(this.$el);
4349

50+
if (tab.state && this.states[tab.state]) {
51+
$("<i>", {
52+
"class": "state fa "+this.states[tab.state]
53+
}).prependTo(inner);
54+
}
55+
4456
if (this.options.close) {
4557
$("<a>", {
4658
"class": "close",
@@ -144,6 +156,16 @@ define([
144156
return this;
145157
},
146158

159+
// Set tab state
160+
setTabState: function(state, value) {
161+
if (value === false && state != this.tabs.tabs[this.tabid].state) {
162+
return this;
163+
}
164+
this.tabs.tabs[this.tabid].state = (value == null || value) ? state : null;
165+
this.tabs.tabs[this.tabid].tab.render();
166+
return this;
167+
},
168+
147169
// Set tab title
148170
setTabId: function(t) {
149171
this.tabs.tabs[this.tabid].uniqueId = t;
@@ -275,6 +297,7 @@ define([
275297
tabinfos = {
276298
"tabid": tabid,
277299
"title": options.title,
300+
"state": null,
278301
"uniqueId": options.uniqueId,
279302
"type": this.options.type,
280303
"view": null,
@@ -392,12 +415,12 @@ define([
392415

393416
// Close a tab by tabid
394417
close: function(tabid, force) {
395-
//if (_.size(this.tabs) <= 1) return this;
396418
if (this.tabs[tabid] == null) return this;
397419

398420
// Triger in tab
399421
this.tabs[tabid].view.trigger("tab:close");
400-
422+
this.tabs[tabid].view.off();
423+
401424
delete this.tabs[tabid].view;
402425
delete this.tabs[tabid];
403426

core/cb.files.sync/environment.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function Environment(path, creator, service) {
1616
this.users = {};
1717
this.path = path;
1818
this.locked = false;
19+
this.modified = false;
1920
this.service = service;
2021

2122
this.doc = new Document(this.path, creator.userId, this.service);
@@ -82,6 +83,14 @@ Environment.prototype.getUser = function(user) {
8283
return this.users[user.key()];
8384
};
8485

86+
Environment.prototype.modifiedState = function(state) {
87+
if (this.modified == state) return;
88+
this.modified = state;
89+
this.notifyAll("modified", {
90+
'state': this.modified
91+
});
92+
};
93+
8594
Environment.prototype.usersInfo = function() {
8695
// Get infornmation on every use in the environment
8796
return _.map(this.users, function(user) {
@@ -148,7 +157,8 @@ Environment.prototype.notify = function(users, action, data) {
148157
Environment.prototype.getSyncData = function() {
149158
return {
150159
content: this.doc.getContent(),
151-
participants: this.usersInfo()
160+
participants: this.usersInfo(),
161+
state: this.modified
152162
};
153163
};
154164

@@ -182,6 +192,12 @@ Environment.prototype.sync = function(user, payload) {
182192
);
183193
};
184194

195+
Environment.prototype.save = function(user, payload) {
196+
// Synchronize content
197+
this.doc.save();
198+
return this.modifiedState(false);
199+
};
200+
185201
Environment.prototype.ping = function(user, payload) {
186202
// List all current users with their respective info
187203
return this.notify(user, 'participants',
@@ -223,6 +239,8 @@ Environment.prototype.patch = function(user, payload) {
223239
return this.syncAll();
224240
}
225241

242+
this.modifiedState(true);
243+
226244
return this.notifyOthers(user, null, payload);
227245
};
228246

core/cb.files.sync/manager.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var createEnvironment = require('./environment').createEnvironment;
99

1010
var actions = {
1111
"sync": "sync",
12+
"save": "save",
1213
"ping": "ping",
1314
"close": "close",
1415
"patch": "patch",

core/cb.files.sync/models/document.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ Document.prototype.patch = function(patchText, preHash, postHash) {
3535
// Update buffer
3636
this.buffer = diff.patch_apply(patch, this.buffer)[0];
3737

38-
// Update remote version
39-
this.update();
40-
4138
return true;
4239
};
4340

@@ -49,9 +46,9 @@ Document.prototype.write = function(content) {
4946
return Q.nfbind(this.service.invoke)('write', this.path, content, this.creatorId);
5047
};
5148

52-
Document.prototype.update = _.debounce(function() {
49+
Document.prototype.save = function() {
5350
return this.write(this.buffer);
54-
}, 1000);
51+
};
5552

5653
Document.prototype.load = function() {
5754
var that = this;

0 commit comments

Comments
 (0)