kopia lustrzana https://github.com/c9/core
reimplement autosave after dalay option in collab-friendly way
rodzic
7c23e8e7ac
commit
2ca11b2d7d
|
@ -14,16 +14,20 @@ define(function(require, exports, module) {
|
||||||
var Plugin = imports.Plugin;
|
var Plugin = imports.Plugin;
|
||||||
var settings = imports.settings;
|
var settings = imports.settings;
|
||||||
|
|
||||||
|
var lang = require("ace/lib/lang");
|
||||||
|
|
||||||
/***** Initialization *****/
|
/***** Initialization *****/
|
||||||
|
|
||||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
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_CHANGE_TIMEOUT = options.slowChangeTimeout || 30000;
|
||||||
var SLOW_SAVE_THRESHOLD = 100 * 1024; // 100KB
|
|
||||||
|
|
||||||
var docChangeTimeout;
|
var docChangeTimeout;
|
||||||
|
var lastSaveTime = 0;
|
||||||
|
var sessionId;
|
||||||
var autosave;
|
var autosave;
|
||||||
|
var saveWhenIdle;
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
prefs.add({
|
prefs.add({
|
||||||
|
@ -31,10 +35,16 @@ define(function(require, exports, module) {
|
||||||
position: 150,
|
position: 150,
|
||||||
"Save": {
|
"Save": {
|
||||||
position: 100,
|
position: 100,
|
||||||
"Enable Auto-Save On Blur": {
|
"Auto-Save Files": {
|
||||||
type: "checkbox",
|
type: "dropdown",
|
||||||
position: 100,
|
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 *****/
|
/***** Helpers *****/
|
||||||
|
|
||||||
function onSettingChange() {
|
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)
|
if (autosave)
|
||||||
enable();
|
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() {
|
function enable() {
|
||||||
apf.on("movefocus", scheduleCheck);
|
apf.on("movefocus", scheduleCheck);
|
||||||
tabs.on("tabAfterActivate", scheduleCheck, plugin);
|
tabs.on("tabAfterActivate", scheduleCheck, plugin);
|
||||||
|
if (saveWhenIdle)
|
||||||
|
tabs.on("focusSync", attachToTab, plugin);
|
||||||
window.addEventListener("blur", scheduleCheck);
|
window.addEventListener("blur", scheduleCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
function disable() {
|
function disable() {
|
||||||
|
sessionId = null;
|
||||||
|
if (saveWhenIdle) {
|
||||||
|
saveWhenIdle.cancel();
|
||||||
|
saveWhenIdle = null;
|
||||||
|
}
|
||||||
|
if (docChangeTimeout) {
|
||||||
|
clearTimeout(docChangeTimeout);
|
||||||
|
docChangeTimeout = null;
|
||||||
|
}
|
||||||
apf.off("movefocus", scheduleCheck);
|
apf.off("movefocus", scheduleCheck);
|
||||||
tabs.off("tabAfterActivate", scheduleCheck);
|
tabs.off("tabAfterActivate", scheduleCheck);
|
||||||
|
tabs.off("focusSync", attachToTab);
|
||||||
window.removeEventListener("blur", scheduleCheck);
|
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) {
|
function scheduleCheck(e) {
|
||||||
if (docChangeTimeout)
|
if (docChangeTimeout)
|
||||||
return;
|
return;
|
||||||
|
@ -117,11 +171,6 @@ define(function(require, exports, module) {
|
||||||
function saveTab(tab, force) {
|
function saveTab(tab, force) {
|
||||||
if (!autosave) return;
|
if (!autosave) return;
|
||||||
|
|
||||||
if (!c9.has(c9.STORAGE)) {
|
|
||||||
save.setSavingState(tab, "offline");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var doc;
|
var doc;
|
||||||
if (!force && (!tab.path
|
if (!force && (!tab.path
|
||||||
|| !(doc = tab.document).changed
|
|| !(doc = tab.document).changed
|
||||||
|
@ -133,9 +182,18 @@ define(function(require, exports, module) {
|
||||||
|| !doc.hasValue()))
|
|| !doc.hasValue()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!c9.has(c9.STORAGE)) {
|
||||||
|
save.setSavingState(tab, "offline");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = Date.now();
|
||||||
save.save(tab, {
|
save.save(tab, {
|
||||||
silentsave: true,
|
silentsave: true,
|
||||||
}, function() {});
|
noUi: true,
|
||||||
|
}, function() {
|
||||||
|
lastSaveTime = t - Date.now();
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -146,12 +204,8 @@ define(function(require, exports, module) {
|
||||||
load();
|
load();
|
||||||
});
|
});
|
||||||
plugin.on("unload", function() {
|
plugin.on("unload", function() {
|
||||||
window.removeEventListener("blur", scheduleCheck);
|
disable();
|
||||||
autosave = false;
|
autosave = false;
|
||||||
if (docChangeTimeout) {
|
|
||||||
clearTimeout(docChangeTimeout);
|
|
||||||
docChangeTimeout = null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/***** Register and define API *****/
|
/***** Register and define API *****/
|
||||||
|
|
|
@ -46,6 +46,8 @@ require(["lib/chai/chai"], function (chai) {
|
||||||
"plugins/c9.ide.save/save",
|
"plugins/c9.ide.save/save",
|
||||||
{
|
{
|
||||||
packagePath: "plugins/c9.ide.save/autosave",
|
packagePath: "plugins/c9.ide.save/autosave",
|
||||||
|
ignoreFocusForTesting: true,
|
||||||
|
changeTimeout: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
packagePath: "plugins/c9.vfs.client/vfs_client_mock",
|
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) {
|
if (!onload.remain) {
|
||||||
describe("unload()", function() {
|
describe("unload()", function() {
|
||||||
it('should destroy all ui elements when it is unloaded', function(done) {
|
it('should destroy all ui elements when it is unloaded', function(done) {
|
||||||
|
|
|
@ -412,7 +412,7 @@ define(function(require, exports, module) {
|
||||||
doc.meta.$saveBuffer = true;
|
doc.meta.$saveBuffer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSavingState(tab, "saving");
|
setSavingState(tab, "saving", null, options.noUi);
|
||||||
|
|
||||||
var bookmark = doc.undoManager.position;
|
var bookmark = doc.undoManager.position;
|
||||||
var loadStartT = Date.now();
|
var loadStartT = Date.now();
|
||||||
|
@ -450,7 +450,7 @@ define(function(require, exports, module) {
|
||||||
if (options.path)
|
if (options.path)
|
||||||
tab.path = options.path;
|
tab.path = options.path;
|
||||||
|
|
||||||
setSavingState(tab, "saved", options.timeout);
|
setSavingState(tab, "saved", options.timeout, options.noUi);
|
||||||
settings.save();
|
settings.save();
|
||||||
logger.log("Successfully saved " + path);
|
logger.log("Successfully saved " + path);
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ define(function(require, exports, module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var stateTimer = null, pageTimers = {};
|
var stateTimer = null, pageTimers = {};
|
||||||
function setSavingState(tab, state, timeout) {
|
function setSavingState(tab, state, timeout, silent) {
|
||||||
clearTimeout(stateTimer);
|
clearTimeout(stateTimer);
|
||||||
clearTimeout(pageTimers[tab.name]);
|
clearTimeout(pageTimers[tab.name]);
|
||||||
|
|
||||||
|
@ -554,6 +554,12 @@ define(function(require, exports, module) {
|
||||||
else
|
else
|
||||||
delete doc.meta.$saving;
|
delete doc.meta.$saving;
|
||||||
|
|
||||||
|
if (!silent)
|
||||||
|
updateSavingUi();
|
||||||
|
emit("tabSavingState", { tab: tab });
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSavingUi(tab, state, timeout) {
|
||||||
if (state == "saving") {
|
if (state == "saving") {
|
||||||
btnSave.show();
|
btnSave.show();
|
||||||
|
|
||||||
|
@ -621,7 +627,6 @@ define(function(require, exports, module) {
|
||||||
btnSave.setCaption("Not saved");
|
btnSave.setCaption("Not saved");
|
||||||
tab.classList.add("error");
|
tab.classList.add("error");
|
||||||
}
|
}
|
||||||
emit("tabSavingState", { tab: tab });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Lifecycle *****/
|
/***** Lifecycle *****/
|
||||||
|
|
Ładowanie…
Reference in New Issue