reimplement autosave after dalay option in collab-friendly way

pull/483/merge
nightwing 2017-12-23 23:25:42 +04:00
rodzic 7c23e8e7ac
commit 2ca11b2d7d
3 zmienionych plików z 108 dodań i 23 usunięć

Wyświetl plik

@ -14,16 +14,20 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var settings = imports.settings;
var lang = require("ace/lib/lang");
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
var CHANGE_TIMEOUT = 500;
var CHANGE_TIMEOUT = options.changeTimeout || 1000;
var SLOW_CHANGE_TIMEOUT = options.slowChangeTimeout || 30000;
var SLOW_SAVE_THRESHOLD = 100 * 1024; // 100KB
var docChangeTimeout;
var lastSaveTime = 0;
var sessionId;
var autosave;
var saveWhenIdle;
function load() {
prefs.add({
@ -31,10 +35,16 @@ define(function(require, exports, module) {
position: 150,
"Save": {
position: 100,
"Enable Auto-Save On Blur": {
type: "checkbox",
"Auto-Save Files": {
type: "dropdown",
position: 100,
path: "user/general/@autosave"
path: "user/general/@autosave",
width: 130,
items: [
{ caption: "Off", value: false },
{ caption: "On Focus Change", value: "onFocusChange" },
{ caption: "After Delay", value: "afterDelay" },
],
}
}
}
@ -52,25 +62,69 @@ define(function(require, exports, module) {
/***** Helpers *****/
function onSettingChange() {
autosave = settings.getBool("user/general/@autosave");
autosave = settings.get("user/general/@autosave");
if (autosave == "off" || autosave == "false")
autosave = false;
disable();
if (autosave == "afterDelay")
enableDelay();
if (autosave)
enable();
else
disable();
}
function enableDelay() {
saveWhenIdle = lang.delayedCall(function() {
var tab = tabs.focussedTab;
var ace = tab && tab.editor && tab.editor.ace;
if (ace && ace.session && sessionId == ace.session.id) {
saveTab(tab);
}
});
}
function enable() {
apf.on("movefocus", scheduleCheck);
tabs.on("tabAfterActivate", scheduleCheck, plugin);
if (saveWhenIdle)
tabs.on("focusSync", attachToTab, plugin);
window.addEventListener("blur", scheduleCheck);
}
function disable() {
sessionId = null;
if (saveWhenIdle) {
saveWhenIdle.cancel();
saveWhenIdle = null;
}
if (docChangeTimeout) {
clearTimeout(docChangeTimeout);
docChangeTimeout = null;
}
apf.off("movefocus", scheduleCheck);
tabs.off("tabAfterActivate", scheduleCheck);
tabs.off("focusSync", attachToTab);
window.removeEventListener("blur", scheduleCheck);
}
function attachToTab(e) {
var ace = e.tab && e.tab.editor && e.tab.editor.ace;
if (ace)
ace.on("beforeEndOperation", beforeEndOperation);
}
function beforeEndOperation(e, ace) {
if (!saveWhenIdle)
return ace.off("beforeEndOperation", beforeEndOperation);
if (!ace.isFocused() && !options.ignoreFocusForTesting)
return;
sessionId = ace.session.id;
if (sessionId && ace.curOp.docChanged && ace.curOp.command.name) {
var timeout = Math.min(Math.max(CHANGE_TIMEOUT, lastSaveTime || 0), SLOW_CHANGE_TIMEOUT);
saveWhenIdle.delay(timeout);
}
}
function scheduleCheck(e) {
if (docChangeTimeout)
return;
@ -117,11 +171,6 @@ define(function(require, exports, module) {
function saveTab(tab, force) {
if (!autosave) return;
if (!c9.has(c9.STORAGE)) {
save.setSavingState(tab, "offline");
return;
}
var doc;
if (!force && (!tab.path
|| !(doc = tab.document).changed
@ -133,9 +182,18 @@ define(function(require, exports, module) {
|| !doc.hasValue()))
return;
if (!c9.has(c9.STORAGE)) {
save.setSavingState(tab, "offline");
return;
}
var t = Date.now();
save.save(tab, {
silentsave: true,
}, function() {});
noUi: true,
}, function() {
lastSaveTime = t - Date.now();
});
return true;
}
@ -146,12 +204,8 @@ define(function(require, exports, module) {
load();
});
plugin.on("unload", function() {
window.removeEventListener("blur", scheduleCheck);
disable();
autosave = false;
if (docChangeTimeout) {
clearTimeout(docChangeTimeout);
docChangeTimeout = null;
}
});
/***** Register and define API *****/

Wyświetl plik

@ -46,6 +46,8 @@ require(["lib/chai/chai"], function (chai) {
"plugins/c9.ide.save/save",
{
packagePath: "plugins/c9.ide.save/autosave",
ignoreFocusForTesting: true,
changeTimeout: 5,
},
{
packagePath: "plugins/c9.vfs.client/vfs_client_mock",
@ -175,6 +177,30 @@ require(["lib/chai/chai"], function (chai) {
});
});
it("should automatically save after delay", function(done) {
settings.set("user/general/@autosave", "afterDelay");
var path = "/autosave2.txt";
createAndChangeTab(path, function(tab) {
expect(tab.document.changed).to.ok;
setTimeout(function() {
expect(tab.document.changed).to.ok;
tab.editor.ace.execCommand("insertstring", "x");
}, 10);
save.once("afterSave", function() {
fs.readFile(path, function(err, data) {
if (err) throw err;
expect(data).to.equal("testx" + path);
expect(tab.document.changed).to.not.ok;
fs.unlink(path, function() {
done();
});
});
});
});
});
if (!onload.remain) {
describe("unload()", function() {
it('should destroy all ui elements when it is unloaded', function(done) {

Wyświetl plik

@ -412,7 +412,7 @@ define(function(require, exports, module) {
doc.meta.$saveBuffer = true;
}
setSavingState(tab, "saving");
setSavingState(tab, "saving", null, options.noUi);
var bookmark = doc.undoManager.position;
var loadStartT = Date.now();
@ -450,7 +450,7 @@ define(function(require, exports, module) {
if (options.path)
tab.path = options.path;
setSavingState(tab, "saved", options.timeout);
setSavingState(tab, "saved", options.timeout, options.noUi);
settings.save();
logger.log("Successfully saved " + path);
}
@ -541,7 +541,7 @@ define(function(require, exports, module) {
}
var stateTimer = null, pageTimers = {};
function setSavingState(tab, state, timeout) {
function setSavingState(tab, state, timeout, silent) {
clearTimeout(stateTimer);
clearTimeout(pageTimers[tab.name]);
@ -554,6 +554,12 @@ define(function(require, exports, module) {
else
delete doc.meta.$saving;
if (!silent)
updateSavingUi();
emit("tabSavingState", { tab: tab });
}
function updateSavingUi(tab, state, timeout) {
if (state == "saving") {
btnSave.show();
@ -621,7 +627,6 @@ define(function(require, exports, module) {
btnSave.setCaption("Not saved");
tab.classList.add("error");
}
emit("tabSavingState", { tab: tab });
}
/***** Lifecycle *****/