diff --git a/plugins/c9.ide.editors/tabmanager.js b/plugins/c9.ide.editors/tabmanager.js
index fd0be714..ef663ffe 100644
--- a/plugins/c9.ide.editors/tabmanager.js
+++ b/plugins/c9.ide.editors/tabmanager.js
@@ -630,7 +630,7 @@ define(function(require, module, exports) {
if (!loaded || tab.document.meta.preview)
return;
- var lastTab = focussedTab;
+ var lastTab = e.lastTab || focussedTab;
if (!focussedTab || focussedTab.pane == tab.pane && focussedTab != tab)
focusTab(tab, true, true);
diff --git a/plugins/c9.ide.save/autosave.js b/plugins/c9.ide.save/autosave.js
index 539591e2..9ae008c9 100644
--- a/plugins/c9.ide.save/autosave.js
+++ b/plugins/c9.ide.save/autosave.js
@@ -1,122 +1,117 @@
define(function(require, exports, module) {
main.consumes = [
- "Plugin", "c9", "ui", "layout", "tooltip",
- "anims", "menus", "tabManager", "save",
- "preferences.experimental"
+ "Plugin", "c9", "settings", "tabManager", "preferences", "save", "apf"
];
main.provides = ["autosave"];
return main;
function main(options, imports, register) {
var c9 = imports.c9;
- var Plugin = imports.Plugin;
+ var apf = imports.apf;
var save = imports.save;
- var tooltip = imports.tooltip;
var tabs = imports.tabManager;
- var experimental = imports["preferences.experimental"];
+ var prefs = imports.preferences;
+ var Plugin = imports.Plugin;
+ var settings = imports.settings;
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
- var INTERVAL = 60000;
var CHANGE_TIMEOUT = 500;
var SLOW_CHANGE_TIMEOUT = options.slowChangeTimeout || 30000;
var SLOW_SAVE_THRESHOLD = 100 * 1024; // 100KB
- var docChangeTimeout = null;
- var btnSave, autosave = true, saveInterval;
- var enabled = options.testing
- || experimental.addExperiment("autosave", false, "Files/Auto-Save");
+ var docChangeTimeout;
+ var autosave;
- var loaded = false;
function load() {
- if (loaded || !enabled) return false;
- loaded = true;
-
- // when we're back online we'll trigger an autosave if enabled
- c9.on("stateChange", function(e) {
- if (e.state & c9.STORAGE && !(e.last & c9.STORAGE))
- check();
- }, plugin);
-
- save.getElement("btnSave", function(btn) {
- btnSave = btn;
- transformButton();
- });
-
- tabs.on("tabCreate", function(e) {
- var tab = e.tab;
- tab.document.undoManager.on("change", function(e) {
- if (!autosave || !tab.path)
- return;
-
- clearTimeout(docChangeTimeout);
- docChangeTimeout = setTimeout(function() {
- saveTab(tab);
- }, tab.document.meta.$slowSave
- ? SLOW_CHANGE_TIMEOUT
- : CHANGE_TIMEOUT);
- }, plugin);
- }, plugin);
-
- tabs.on("tabDestroy", function(e) {
- if (!e.tab.path)
- return;
-
- if (tabs.getTabs().length == 1)
- btnSave.hide();
-
- saveTab(e.tab);
- }, plugin);
-
- save.on("beforeWarn", function(e) {
- if (autosave && !e.tab.document.meta.newfile) {
- saveTab(e.tab);
- return false;
+ prefs.add({
+ "File": {
+ position: 150,
+ "Save": {
+ position: 100,
+ "Enable Auto-Save On Blur": {
+ type: "checkbox",
+ position: 100,
+ path: "user/general/@autosave"
+ }
+ }
}
}, plugin);
- }
-
- function transformButton() {
- if (!btnSave) return;
- if (btnSave.autosave === autosave) return;
- if (autosave) {
- // Transform btnSave
- btnSave.setAttribute("caption", "");
- btnSave.setAttribute("margin", "0 20");
- btnSave.removeAttribute("tooltip");
- btnSave.removeAttribute("command");
- apf.setStyleClass(btnSave.$ext, "btnSave");
-
- tooltip.add(btnSave, {
- message: "Changes to your file are automatically saved.
\
- View all your changes through the Revision History pane. \
- Rollback to a previous state, or make comparisons.",
- width: "250px",
- hideonclick: true
- }, plugin);
- }
- else {
-
- }
-
- btnSave.autosave = autosave;
+ settings.setDefaults("user/general", [["autosave", false]]);
+ settings.on("read", onSettingChange, plugin);
+ settings.on("user/general", onSettingChange, plugin);
+ save.on("beforeWarn", function(e) {
+ if (autosave && saveTab(e.tab))
+ return false;
+ }, plugin);
}
/***** Helpers *****/
-
- function check() {
- if (!autosave) return;
-
- var pages = tabs.getTabs();
- for (var tab, i = 0, l = pages.length; i < l; i++) {
- if ((tab = pages[i]).document.changed && tab.path)
- saveTab(tab);
+
+ function onSettingChange() {
+ autosave = settings.getBool("user/general/@autosave");
+ if (autosave)
+ enable();
+ else
+ disable();
+ }
+
+ function enable() {
+ apf.on("movefocus", scheduleCheck);
+ tabs.on("tabAfterActivate", scheduleCheck, plugin);
+ window.addEventListener("blur", scheduleCheck);
+ }
+
+ function disable() {
+ apf.off("movefocus", scheduleCheck);
+ tabs.off("tabAfterActivate", scheduleCheck);
+ window.removeEventListener("blur", scheduleCheck);
+ }
+
+ function scheduleCheck(e) {
+ if (docChangeTimeout)
+ return;
+ var tab;
+ var fromElement = e.fromElement;
+ var toElement = e.toElement;
+ if (e.type == "blur") {
+ tab = tabs.focussedTab;
}
+ else if (fromElement) {
+ var fakePage = fromElement.$fake;
+ if (toElement && (toElement == fakePage || fromElement == toElement.$fake)) {
+ fakePage = fromElement.$prevFake || toElement.$prevFake;
+ if (fakePage)
+ return;
+ }
+
+ tab = fromElement.cloud9tab || fakePage && fakePage.cloud9tab;
+ if (!tab || !tab.path)
+ return;
+ while (toElement) {
+ if (/window|menu|item/.test(toElement.localName))
+ return;
+ toElement = toElement.parentNode;
+ }
+ }
+ else if (e.lastTab) {
+ tab = e.lastTab;
+ }
+ if (!tab || !tab.path)
+ return;
+
+ docChangeTimeout = setTimeout(function() {
+ docChangeTimeout = null;
+ var activeElement = apf.document.activeElement;
+ var nodeName = activeElement && activeElement.localName;
+ // do nothing if the tab is still focused, or is a clone of the focussed tab
+ if (nodeName === "page" && tabs.focussedTab && tabs.focussedTab.path === tab.path)
+ return;
+ saveTab(tab);
+ });
}
function saveTab(tab, force) {
@@ -133,22 +128,16 @@ define(function(require, exports, module) {
|| doc.meta.newfile
|| doc.meta.nofs
|| doc.meta.error
- || doc.meta.$saving))
+ || doc.meta.$saving
+ || doc.meta.preview
+ || !doc.hasValue()))
return;
-
- var value = doc.value;
- var slow = value.length > SLOW_SAVE_THRESHOLD;
- if (slow && !doc.meta.$slowSave) {
- doc.meta.$slowSave = true;
- return;
- }
- doc.meta.$slowSave = slow;
-
+
save.save(tab, {
silentsave: true,
- timeout: 1,
- value: value
}, function() {});
+
+ return true;
}
/***** Lifecycle *****/
@@ -156,27 +145,20 @@ define(function(require, exports, module) {
plugin.on("load", function() {
load();
});
- plugin.on("enable", function() {
- autosave = true;
- transformButton();
- });
- plugin.on("disable", function() {
- autosave = false;
- transformButton();
- });
plugin.on("unload", function() {
- if (saveInterval)
- clearInterval(saveInterval);
-
- loaded = false;
+ window.removeEventListener("blur", scheduleCheck);
+ autosave = false;
+ if (docChangeTimeout) {
+ clearTimeout(docChangeTimeout);
+ docChangeTimeout = null;
+ }
});
/***** Register and define API *****/
/**
* Implements auto save for Cloud9. When the user enables autosave
- * the contents of files are automatically saved about 500ms after the
- * change is made.
+ * the contents of files are automatically saved when the editor is blurred
* @singleton
**/
plugin.freezePublicAPI({ });
diff --git a/plugins/c9.ide.save/autosave_test.js b/plugins/c9.ide.save/autosave_test.js
index 70bb4dba..b4381962 100644
--- a/plugins/c9.ide.save/autosave_test.js
+++ b/plugins/c9.ide.save/autosave_test.js
@@ -2,8 +2,7 @@
"use client";
-require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
- function (architect, chai, baseProc) {
+require(["lib/chai/chai"], function (chai) {
var expect = chai.expect;
document.body.appendChild(document.createElement("div"))
@@ -16,7 +15,6 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
debug: true,
hosted: true,
local: false,
- davPrefix: "/"
},
"plugins/c9.core/ext",
@@ -37,7 +35,7 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
"plugins/c9.ide.editors/undomanager",
{
packagePath: "plugins/c9.ide.editors/editors",
- defaultEditor: "texteditor"
+ defaultEditor: "ace"
},
"plugins/c9.ide.editors/editor",
"plugins/c9.ide.editors/tabmanager",
@@ -48,17 +46,15 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
"plugins/c9.ide.save/save",
{
packagePath: "plugins/c9.ide.save/autosave",
- testing: true
},
{
- packagePath: "plugins/c9.vfs.client/vfs_client"
+ packagePath: "plugins/c9.vfs.client/vfs_client_mock",
+ storage: false
},
- "plugins/c9.vfs.client/endpoint",
- "plugins/c9.ide.auth/auth",
"plugins/c9.core/api",
{
packagePath: "plugins/c9.fs/fs",
- baseProc: baseProc
+ cli: true
},
"plugins/c9.fs/fs.cache.xml",
@@ -67,27 +63,15 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
provides: [],
setup: main
}
- ], architect);
+ ]);
function main(options, imports, register) {
+ var settings = imports.settings
var tabs = imports.tabManager;
var fs = imports.fs;
var save = imports.save;
var autosave = imports.autosave;
- function countEvents(count, expected, done) {
- if (count == expected)
- done();
- else
- throw new Error("Wrong Event Count: "
- + count + " of " + expected);
- }
-
- expect.html.setConstructor(function(tab) {
- if (typeof tab == "object")
- return tab.pane.aml.getPage("editor::" + tab.editorType).$ext;
- });
-
function changeTab(path, done) {
var tab = tabs.findTab(path);
tabs.focusTab(tab);
@@ -98,41 +82,90 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"],
return tab;
}
+ function createAndChangeTab(path, options, done) {
+ if (!done) {
+ done = options;
+ options = {};
+ }
+ fs.writeFile(path, path, function(err) {
+ if (err) throw err;
+
+ options.path = path;
+ tabs.open(options, function() {
+ changeTab(path, done);
+ });
+ });
+ }
+
describe('autosave', function() {
this.timeout(5000);
- before(function(done) {
+ beforeEach(function(done) {
tabs.once("ready", function() {
- tabs.getPanes()[0].focus();
- var path = "/autosave1.txt";
- fs.writeFile(path, path, function(err) {
- if (err) throw err;
-
- tabs.openFile(path, function() {
- setTimeout(done, 50);
- });
+ tabs.setState(null, function() {
+ tabs.getPanes()[0].focus();
+ done();
});
});
-
- bar.$ext.style.background = "rgba(220, 220, 220, 0.93)";
- bar.$ext.style.position = "fixed";
- bar.$ext.style.left = "20px";
- bar.$ext.style.right = "20px";
- bar.$ext.style.bottom = "20px";
- bar.$ext.style.height = "150px";
-
- document.body.style.marginBottom = "180px";
});
- it('should automatically save a tab that is changed', function(done) {
- var path = "/autosave1.txt";
- changeTab(path, function(tab) {
+ it("should not autosave when restoring state", function(done) {
+ settings.set("user/general/@autosave", false);
+ var pane = tabs.getPanes()[0].hsplit(true);
+
+ prepareTabs(testRestoreState);
+
+ function prepareTabs(callback) {
+ createAndChangeTab("/autosave1.txt", function(tab) {
+ expect(tab.document.changed).to.ok;
+ createAndChangeTab("/__proto__", function() {
+ createAndChangeTab("/