diff --git a/configs/cli.js b/configs/cli.js
index 80a8d3f5..e3fd3411 100644
--- a/configs/cli.js
+++ b/configs/cli.js
@@ -80,6 +80,10 @@ return [
packagePath: "./c9.cli.open/open",
platform: process.platform
},
+ {
+ packagePath: "./c9.cli.exec/exec",
+ platform: process.platform
+ },
{
packagePath: "./c9.cli.open/restart",
platform: process.platform
diff --git a/configs/client-default.js b/configs/client-default.js
index 0cc65505..9bc8bc4a 100644
--- a/configs/client-default.js
+++ b/configs/client-default.js
@@ -317,7 +317,10 @@ module.exports = function(options) {
"plugins/c9.ide.language/tooltip",
"plugins/c9.ide.language/jumptodef",
"plugins/c9.ide.language/worker_util_helper",
- "plugins/c9.ide.language.generic/generic",
+ {
+ packagePath: "plugins/c9.ide.language.generic/generic",
+ mode_completer: options.ssh,
+ },
"plugins/c9.ide.language.css/css",
"plugins/c9.ide.language.html/html",
"plugins/c9.ide.language.javascript/javascript",
@@ -694,14 +697,15 @@ module.exports = function(options) {
no_newsletter: options.user.no_newsletter,
subscription_on_signup: options.user.subscription_on_signup,
premium: options.user.premium,
- region: options.user.region
+ region: options.user.region,
},
project: {
id: options.project.id,
name: options.project.name,
contents: options.project.contents,
descr: options.project.descr,
- remote: options.project.remote
+ remote: options.project.remote,
+ premium: options.project.premium,
}
},
{
@@ -719,12 +723,6 @@ module.exports = function(options) {
packagePath: "plugins/c9.cli.bridge/bridge_commands",
basePath: workspaceDir
},
- {
- packagePath: "plugins/c9.ide.help.support/support",
- baseurl: options.ideBaseUrl,
- userSnapApiKey: options.support.userSnapApiKey,
- screenshotSupport: true
- },
{
packagePath: "plugins/c9.ide.help/help",
staticPrefix: staticPrefix + "/plugins/c9.ide.help"
@@ -811,13 +809,28 @@ module.exports = function(options) {
"plugins/c9.ide.test.mocha/mocha",
+ // git integration v2
+ // {
+ // packagePath: "plugins/c9.ide.scm/scm.commit",
+ // staticPrefix: staticPrefix + "/plugins/c9.ide.scm"
+ // },
+ // "plugins/c9.ide.scm/scm",
+ // "plugins/c9.ide.scm/scm.branches",
+ // "plugins/c9.ide.scm/dialog.localchanges",
+ // "plugins/c9.ide.scm/scm.log",
+ // "plugins/c9.ide.scm/git",
+ // "plugins/c9.ide.scm/diff.split",
+ // "plugins/c9.ide.scm/diff.unified",
+
+ // // git integration v1
+ "plugins/c9.ide.scm/v1/scm",
+ "plugins/c9.ide.scm/v1/scmpanel",
+ "plugins/c9.ide.scm/v1/detail",
+ "plugins/c9.ide.scm/v1/log",
+ "plugins/c9.ide.scm/v1/git",
+ "plugins/c9.ide.scm/v1/editor",
+
// git integration
- "plugins/c9.ide.scm/scm",
- "plugins/c9.ide.scm/scmpanel",
- "plugins/c9.ide.scm/detail",
- "plugins/c9.ide.scm/log",
- "plugins/c9.ide.scm/git",
- "plugins/c9.ide.scm/editor",
"plugins/c9.ide.scm/mergetool"
];
diff --git a/docs/CODING_STANDARDS.md b/docs/CODING_STANDARDS.md
index 6a6eea2d..8318a955 100644
--- a/docs/CODING_STANDARDS.md
+++ b/docs/CODING_STANDARDS.md
@@ -695,6 +695,31 @@ API Documentation
All classes and public API should be documented using [JSDuck annotations](https://github.com/senchalabs/jsduck).
+Commit messages
+---------------
+
+We try to adhere to https://github.com/blog/926-shiny-new-commit-styles and to a lesser extent http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html.
+Don't write `I fixed a bug` or `Fixed bug`, or even `Added a cool fix for bug`. Just write `Fix bug in wrop wraffles` or `Add feature flip floppers`, present tense.
+
+Branch Naming
+-------------
+
+We follow the uni-repo approach so our source code is in one place. To work around some of the issues - for example looking at all PRs affecting a certain service - we prefix branches with the name of the service(s) the branch affects.
+
+PR branch names, e.g.
+
+ “api-”, “ide-”, “multi-ide-vfs-sapi-”
+
+Checking for branch naming consistency is part of the review process and the teams responsibility.
+
+ Use “all-” in case of doubt. E.g., https://github.com/c9/newclient/pull/12962/files affects redis schema code.
+
+Generally, releasing changes affecting several services is a smell so this can help you identify possible issues.
+
+You can now look for all PRs which made it in like so (api in this case):
+
+ git log --oneline --first-parent SHA..origin/master | grep -v bump | grep api-
+
Other Resources
===============
diff --git a/node_modules/ace/lib/ace/edit_session/folding.js b/node_modules/ace/lib/ace/edit_session/folding.js
index fbab03fa..4e67fe45 100644
--- a/node_modules/ace/lib/ace/edit_session/folding.js
+++ b/node_modules/ace/lib/ace/edit_session/folding.js
@@ -772,7 +772,7 @@ function Folding() {
this.removeFold(fold);
else
this.expandFold(fold);
- return;
+ return fold;
}
var range = this.getFoldWidgetRange(row, true);
@@ -781,7 +781,7 @@ function Folding() {
fold = this.getFoldAt(range.start.row, range.start.column, 1);
if (fold && range.isEqual(fold.range)) {
this.removeFold(fold);
- return;
+ return fold;
}
}
diff --git a/node_modules/ace/lib/ace/ext/whitespace.js b/node_modules/ace/lib/ace/ext/whitespace.js
index 7f39b092..04074988 100644
--- a/node_modules/ace/lib/ace/ext/whitespace.js
+++ b/node_modules/ace/lib/ace/ext/whitespace.js
@@ -127,10 +127,20 @@ exports.trimTrailingSpace = function(session, options) {
var lines = doc.getAllLines();
var min = options && options.trimEmpty ? -1 : 0;
- var cursors = session.selection.rangeCount
- ? session.selection.ranges.map(function(x) { return x.cursor; })
- : [session.selection.getCursor()];
- var ci = options && options.keepCursorPosition ? 0 : -1;
+ var cursors = [], ci = -1;
+ if (options && options.keepCursorPosition) {
+ if (session.selection.rangeCount) {
+ session.selection.rangeList.ranges.forEach(function(x, i, ranges) {
+ var next = ranges[i + 1];
+ if (next && next.cursor.row == x.cursor.row)
+ return;
+ cursors.push(x.cursor);
+ });
+ } else {
+ cursors.push(session.selection.getCursor());
+ }
+ ci = 0;
+ }
var cursorRow = cursors[ci] && cursors[ci].row;
for (var i = 0, l=lines.length; i < l; i++) {
@@ -138,8 +148,8 @@ exports.trimTrailingSpace = function(session, options) {
var index = line.search(/\s+$/);
if (i == cursorRow) {
- if (index < cursors[ci].column)
- index = min;
+ if (index < cursors[ci].column && index > min)
+ index = cursors[ci].column;
ci++;
cursorRow = cursors[ci] ? cursors[ci].row : -1;
}
diff --git a/node_modules/ace/lib/ace/ext/whitespace_test.js b/node_modules/ace/lib/ace/ext/whitespace_test.js
index 419ae74f..422d346c 100644
--- a/node_modules/ace/lib/ace/ext/whitespace_test.js
+++ b/node_modules/ace/lib/ace/ext/whitespace_test.js
@@ -1,13 +1,14 @@
if (typeof process !== "undefined") {
require("amd-loader");
- require("../test/mockdom");
}
define(function(require, exports, module) {
"use strict";
+require("../multi_select");
var assert = require("assert");
var EditSession = require("../edit_session").EditSession;
+var UndoManager = require("../undomanager").UndoManager;
var whitespace = require("./whitespace");
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
@@ -111,8 +112,90 @@ module.exports = {
assert.equal(indent.length, 1);
next();
- }
+ },
+ "test trimTrailingSpace": function(next) {
+ var session = new EditSession([
+ "a",
+ "\t b \t",
+ " ",
+ "\t",
+ "\t\tx\t\t",
+ " ",
+ " "
+ ]);
+ session.setUndoManager(new UndoManager());
+
+ function testOne(value, options) {
+ console.log(JSON.stringify(session.getValue()))
+
+ whitespace.trimTrailingSpace(session, options);
+ assert.equal(value, session.getValue());
+ session.markUndoGroup();
+ session.getUndoManager().undo();
+ }
+
+ testOne("a\n\t b\n \n\t\n\t\tx\n \n ")
+
+ testOne("a\n\t b\n\n\n\t\tx\n\n", {
+ trimEmpty: true
+ });
+
+ session.selection.fromJSON([{
+ start: {row:2,column:3},
+ end: {row:4,column:4}
+ }]);
+ testOne("a\n\t b\n\n\n\t\tx\t\n\n", {
+ keepCursorPosition: true,
+ trimEmpty: true
+ });
+
+ session.selection.fromJSON([{
+ start: {row:2,column:3},
+ end: {row:4,column:4},
+ isBackwards: true
+ }]);
+ testOne("a\n\t b\n \n\n\t\tx\n\n", {
+ keepCursorPosition: true,
+ trimEmpty: true
+ });
+
+ session.selection.$initRangeList();
+ session.selection.fromJSON([{
+ start: {row:2, column:3},
+ end: {row:2,column:3}
+ }, {
+ start: {row:1, column:1},
+ end: {row:1, column:1}
+ }, {
+ start: {row:2,column:2},
+ end: {row:2,column:2}
+ }, {
+ start: {row:0,column:5},
+ end: {row:0,column:5},
+ isBackwards:false
+ }, {
+ start: {row:6,column:1},
+ end: {row:6,column:1},
+ isBackwards:false
+ }]);
+ testOne("a\n\t b\n \n\n\t\tx\n\n ", {
+ trimEmpty: true,
+ keepCursorPosition: true
+ });
+
+ session.setValue("some text");
+ session.selection.fromJSON([{
+ start: {row:0,column:4},
+ end: {row:0,column:4}
+ }]);
+ testOne("some text", {
+ keepCursorPosition: true,
+ trimEmpty: true
+ });
+
+ next();
+ },
};
});
diff --git a/node_modules/ace/lib/ace/line_widgets.js b/node_modules/ace/lib/ace/line_widgets.js
index 6eaffc88..83b0af94 100644
--- a/node_modules/ace/lib/ace/line_widgets.js
+++ b/node_modules/ace/lib/ace/line_widgets.js
@@ -214,7 +214,7 @@ function LineWidgets(session) {
if (!w.coverGutter) {
w.el.style.zIndex = 3;
}
- if (!w.pixelHeight) {
+ if (w.pixelHeight == null) {
w.pixelHeight = w.el.offsetHeight;
}
if (w.rowCount == null) {
diff --git a/node_modules/ace/lib/ace/mode/diff.js b/node_modules/ace/lib/ace/mode/diff.js
index 72671a27..f3c46a1b 100644
--- a/node_modules/ace/lib/ace/mode/diff.js
+++ b/node_modules/ace/lib/ace/mode/diff.js
@@ -38,7 +38,7 @@ var FoldMode = require("./folding/diff").FoldMode;
var Mode = function() {
this.HighlightRules = HighlightRules;
- this.foldingRules = new FoldMode(["diff", "index", "\\+{3}", "@@|\\*{5}"], "i");
+ this.foldingRules = new FoldMode(["diff", "@@|\\*{5}"], "i");
};
oop.inherits(Mode, TextMode);
diff --git a/node_modules/ace/lib/ace/mode/folding/diff.js b/node_modules/ace/lib/ace/mode/folding/diff.js
index 23c0e2d0..54185ad1 100644
--- a/node_modules/ace/lib/ace/mode/folding/diff.js
+++ b/node_modules/ace/lib/ace/mode/folding/diff.js
@@ -61,7 +61,7 @@ oop.inherits(FoldMode, BaseFoldMode);
}
if (row == start.row + 1)
return;
- return Range.fromPoints(start, {row: row - 1, column: line.length});
+ return new Range(start.row, start.column, row - 1, line.length);
};
}).call(FoldMode.prototype);
diff --git a/node_modules/ace/lib/ace/worker/worker.js b/node_modules/ace/lib/ace/worker/worker.js
index 856a6ea9..eb5bb876 100644
--- a/node_modules/ace/lib/ace/worker/worker.js
+++ b/node_modules/ace/lib/ace/worker/worker.js
@@ -200,7 +200,7 @@ window.onmessage = function(e) {
sender._signal(msg.event, msg.data);
}
else if (msg.command) {
- if (main[msg.command])
+ if (main && main[msg.command])
main[msg.command].apply(main, msg.args);
else if (window[msg.command])
window[msg.command].apply(window, msg.args);
diff --git a/node_modules/ace/lib/ace/worker/worker_client.js b/node_modules/ace/lib/ace/worker/worker_client.js
index 42c08f43..104f198c 100644
--- a/node_modules/ace/lib/ace/worker/worker_client.js
+++ b/node_modules/ace/lib/ace/worker/worker_client.js
@@ -36,7 +36,7 @@ var net = require("../lib/net");
var EventEmitter = require("../lib/event_emitter").EventEmitter;
var config = require("../config");
-var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
+var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) {
this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this);
this.changeListener = this.changeListener.bind(this);
this.onMessage = this.onMessage.bind(this);
@@ -75,6 +75,9 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
throw e;
}
}
+ if (importScripts) {
+ this.send("importScripts", importScripts);
+ }
this.$worker.postMessage({
init : true,
tlns : tlns,
@@ -94,7 +97,7 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
this.onMessage = function(e) {
var msg = e.data;
- switch(msg.type) {
+ switch (msg.type) {
case "event":
this._signal(msg.name, {data: msg.data});
break;
@@ -157,7 +160,7 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
};
this.attachToDocument = function(doc) {
- if(this.$doc)
+ if (this.$doc)
this.terminate();
this.$doc = doc;
diff --git a/node_modules/ace_tree/lib/ace_tree/data_provider.js b/node_modules/ace_tree/lib/ace_tree/data_provider.js
index 4709fe1c..9bc095e0 100644
--- a/node_modules/ace_tree/lib/ace_tree/data_provider.js
+++ b/node_modules/ace_tree/lib/ace_tree/data_provider.js
@@ -49,7 +49,7 @@ var DataProvider = function(root) {
};
this.open =
- this.expand = function(node, deep, silent, justLoaded) {
+ this.expand = function(node, deep, silent) {
if (typeof deep != "number")
deep = deep ? 100 : 0;
if (!node)
@@ -69,7 +69,7 @@ var DataProvider = function(root) {
this.collapse(node, null, true);
node.status = "loaded";
if (!err)
- this.expand(node, null, false, true);
+ this.expand(node, null, false);
}.bind(this));
this.setOpen(node, true);
return;
@@ -95,9 +95,6 @@ var DataProvider = function(root) {
}
}
- if (justLoaded)
- node.justLoaded = true;
-
this.rows = items.length;
silent || this._signal("expand", node);
};
@@ -417,7 +414,7 @@ DataProvider.variableHeightRowMixin = function() {
var items = this.visibleItems;
var top = 0, index = 0, l = items.length;
while (index < l) {
- var height = this.getItemHeight(items[index].height, index);
+ var height = this.getItemHeight(items[index], index);
top += height;
index++;
if (top >= offset) {
@@ -445,7 +442,7 @@ DataProvider.variableHeightRowMixin = function() {
var items = this.visibleItems;
var startH = 0, index = 0, l = items.length;
while (index < l) {
- var height = this.getItemHeight(items[index].height, index);
+ var height = this.getItemHeight(items[index], index);
startH += height;
index++;
if (startH >= top) {
diff --git a/node_modules/ace_tree/lib/ace_tree/edit.js b/node_modules/ace_tree/lib/ace_tree/edit.js
index 4dcc71e4..a76f115f 100644
--- a/node_modules/ace_tree/lib/ace_tree/edit.js
+++ b/node_modules/ace_tree/lib/ace_tree/edit.js
@@ -157,11 +157,12 @@ var EditableTree = function(tree) {
this.ace.commands.bindKeys({
"Esc": function(ace) {
ace.treeEditor.endRename(true);
- ace.treeEditor.tree.focus();
},
"Enter": function(ace) {
ace.treeEditor.endRename();
- ace.treeEditor.tree.focus();
+ },
+ "ctrl-s|cmd-s": function(ace) {
+ ace.treeEditor.endRename();
},
"Tab": function(ace) {
ace.treeEditor.editNext(1);
@@ -249,17 +250,26 @@ var EditableTree = function(tree) {
this._destroyEditor = function() {
if (this.lastDomNode) {
this.lastDomNode.style.color = "";
- this.lastDomNode
+ this.lastDomNode;
}
this.ace.off("blur", this._onBlur);
this.tree.renderer.off("afterRender", this._onAfterRender);
- this.ace.blur();
- this.ace.destroy();
- if (this.ace.wrapper.parentNode)
- this.ace.wrapper.parentNode.removeChild(this.ace.wrapper);
+ var ace = this.ace;
this.ace = null;
+ this.$lastAce = ace;
+ ace.renderer.freeze();
+ setTimeout(function() {
+ // doing this after timeout to allow rename event focus something else
+ var wasFocused = ace.isFocused();
+ ace.destroy();
+ if (ace.wrapper.parentNode)
+ ace.wrapper.parentNode.removeChild(ace.wrapper);
+ if (wasFocused)
+ this.tree.focus();
+ this.$lastAce = null;
+ }.bind(this));
};
this.findNextEditPoint = function(dir, node, col, keepColumn) {
@@ -384,6 +394,7 @@ var EditableTree = function(tree) {
this.tree._emit("rename", {
node: node,
value: val,
+ oldValue: this.origVal,
column: this.column
});
this.tree.provider._signal("change");
diff --git a/node_modules/ace_tree/lib/ace_tree/layer/cells.js b/node_modules/ace_tree/lib/ace_tree/layer/cells.js
index 9a25c4f8..c0eeffeb 100644
--- a/node_modules/ace_tree/lib/ace_tree/layer/cells.js
+++ b/node_modules/ace_tree/lib/ace_tree/layer/cells.js
@@ -51,7 +51,7 @@ var Cells = function(parentEl) {
this.$renderRow(html, datarow, vsize, hsize, row);
}
- if (firstRow === 0 && lastRow === 0) {
+ if (firstRow <= 0 && lastRow <= 0) {
this.renderPlaceHolder(provider, html, config);
}
@@ -130,7 +130,7 @@ var Cells = function(parentEl) {
provider.renderRow(row, html, config);
}
- if (firstRow === 0 && lastRow === 0) {
+ if (firstRow <= 0 && lastRow <= 0) {
this.renderPlaceHolder(provider, html, config);
}
@@ -187,7 +187,7 @@ var Cells = function(parentEl) {
} else if (provider.getEmptyMessage) {
html.push(
"
",
- provider.getEmptyMessage(),
+ escapeHTML(provider.getEmptyMessage()),
"
"
);
}
diff --git a/node_modules/ace_tree/lib/ace_tree/layer/heading.js b/node_modules/ace_tree/lib/ace_tree/layer/heading.js
index 834155fd..60256532 100644
--- a/node_modules/ace_tree/lib/ace_tree/layer/heading.js
+++ b/node_modules/ace_tree/lib/ace_tree/layer/heading.js
@@ -68,6 +68,7 @@ function ColumnHeader(parentEl, renderer) {
}
col.pixelWidth = 0;
}, this);
+ columns.fixedWidth = fixedWidth;
columns.$fixedWidth = fixedWidth + "px";
columns.width = null;
provider.columns = columns;
diff --git a/node_modules/architect-build/build_support/mini_require.js b/node_modules/architect-build/build_support/mini_require.js
index 004cde85..c04e9e77 100644
--- a/node_modules/architect-build/build_support/mini_require.js
+++ b/node_modules/architect-build/build_support/mini_require.js
@@ -427,7 +427,7 @@ var host = location.protocol + "//" + location.hostname + (location.port ? ":" +
var loadScript = function(path, id, callback) {
if (!config.useCache)
return loadScriptWithTag(path, id, callback);
- if (!/https?:/.test(path))
+ if (!/^https?:/.test(path))
path = host + path;
var cb = function(e, val, deps) {
if (e) return processLoadQueue({ id: id, path: path });
@@ -498,10 +498,12 @@ function checkCache() {
}).then(function(keys) {
baseUrl = host + config.baseUrl;
var val = keys.map(function(r) {
- var url = r.url;
- if (url.startsWith(baseUrl))
- url = url.slice(baseUrl.length);
- return r.headers.get("etag") + " " + url;
+ var url = r.url;
+ if (url.startsWith(baseUrl))
+ url = url.slice(baseUrl.length);
+ else if (/^\w+:/.test(url))
+ return "";
+ return r.headers.get("etag") + " " + url;
}).join("\n") + "\n";
if (val.length == 1) {
ideCachePromiss = null;
@@ -510,7 +512,7 @@ function checkCache() {
return new Promise(function(resolve) {
var checked = 0;
var buffer = "";
- var toDelete = []
+ var toDelete = [];
post("/static/__check__", val, function(t) {
var e = t.slice(checked);
checked = t.length;
@@ -539,6 +541,22 @@ function checkCache() {
return ideCachePromiss;
}
+require.clearCache = function(callback) {
+ ideCachePromiss = window.caches.open("ide").then(function(ideCache_) {
+ ideCache = ideCache_;
+ return ideCache.keys();
+ }).then(function(keys) {
+ var toDelete = keys.map(function(i) {
+ ideCache.delete(i);
+ });
+ Promise.all(toDelete).then(function() {
+ callback && callback();
+ }, function(e) {
+ callback && callback(e);
+ });
+ });
+}
+
function post(path, val, progress, cb) {
var xhr = new window.XMLHttpRequest();
xhr.open("POST", path, true);
diff --git a/node_modules/architect-build/npm_freeze.js b/node_modules/architect-build/npm_freeze.js
new file mode 100644
index 00000000..eb3a1353
--- /dev/null
+++ b/node_modules/architect-build/npm_freeze.js
@@ -0,0 +1,69 @@
+var patchTemplate = ";(" +function() {
+ // automatically generated by architect-build
+ // bundle all dependencies in the main package
+ var Module = require("module");
+ var path = require("path");
+ var _resolveFilename_orig = Module._resolveFilename
+ var root = path.join(__dirname, "{root}");
+ Module._resolveFilename = function(id, parent) {
+ if (parent && parent.paths && parent.paths[0] && parent.paths[0].indexOf(root) == 0) {
+ parent.paths = parent.paths.map(function(p) {
+ if (p.indexOf(root) != 0) return
+ p = p.slice(root.length);
+ return root + p.replace(/([\\\/]|^)node_modules([\\\/]|$)/g, "$1n_m$2");
+ }).filter(Boolean);
+ }
+ return _resolveFilename_orig.call(Module, id, parent);
+ };
+} + ")();";
+
+//////////////////////////////////////////////////////////////////////////
+
+var fs = require("fs");
+var copy = require("architect-build/copy");
+var pathLib = require("path");
+
+function freeze(path, mode) {
+ path = copy.convertPath(path);
+ var pkgs = {};
+ function freezePkg(path) {
+ if (!pkgs[path]) {
+ pkgs[path] = JSON.parse(fs.readFileSync(path + "/package.json"))
+ Object.keys(pkgs[path]).forEach(function(k) {
+ if (/Dependencies/i.test(k)) delete pkgs[path][k];
+ })
+ }
+ pkgs[path].dependencies = {};
+ var deps = fs.existsSync(path + "/node_modules") ? fs.readdirSync(path + "/node_modules") : [];
+ deps.forEach(function(n) {
+ if (n == ".bin") return;
+ var depPath = path + "/node_modules/" + n;
+ freezePkg(depPath);
+ pkgs[path].dependencies[n] = pkgs[depPath].version;
+ });
+ if (mode == "rename") {
+ if (deps.length) {
+ fs.renameSync(path + "/node_modules/", path + "/n_m")
+ delete pkgs[path].dependencies
+ if (pkgs[path].files)
+ pkgs[path].files.push("n_m")
+ }
+ } else {
+ pkgs[path].bundledDependencies = Object.keys(pkgs[path].dependencies);
+ }
+ fs.writeFileSync(path + "/package.json", JSON.stringify(pkgs[path], null, "\t"), "utf8");
+ }
+ freezePkg(path);
+ var bin = pkgs[path].bin;
+ Object.keys(bin).forEach(function(key) {
+ var p = bin[key];
+ var root = pathLib.relative(pathLib.dirname(p), "").replace(/[\\]/g, "/");
+ var src = fs.readFileSync(path + "/" + p, "utf8");
+ src = src.replace(/^(#.*|"use strict";?|\s)*/, function(a) {
+ return a.trim() + "\n\n" + patchTemplate.replace(/{root}/g, root) + "\n\n";
+ });
+ fs.writeFileSync(path + "/" + p, src, "utf8");
+ });
+}
+
+module.exports = freeze;
diff --git a/node_modules/c9/format-user-analytics.js b/node_modules/c9/format-user-analytics.js
index d420e4d2..579975f1 100644
--- a/node_modules/c9/format-user-analytics.js
+++ b/node_modules/c9/format-user-analytics.js
@@ -23,7 +23,9 @@ define(function(require, exports, module) {
name: user.fullname || user.name,
pricingPlan: user.premium ? "Premium" : "Free",
referredBy: user.referrer,
- region: user.region
+ region: user.region,
+ usertype: user.usertype,
+ purpose: user.purpose,
};
return traits;
diff --git a/node_modules/c9/is-notfound.js b/node_modules/c9/is-notfound.js
new file mode 100644
index 00000000..dcc8edba
--- /dev/null
+++ b/node_modules/c9/is-notfound.js
@@ -0,0 +1,7 @@
+"use strict";
+
+
+module.exports = function isNotFound(err) {
+ if (err && err.code === 404) return true;
+ return false;
+};
\ No newline at end of file
diff --git a/node_modules/c9/rest_client.js b/node_modules/c9/rest_client.js
index 8f42b1d0..0aec2fff 100644
--- a/node_modules/c9/rest_client.js
+++ b/node_modules/c9/rest_client.js
@@ -36,7 +36,7 @@ function RestClient(host, port, config) {
var headers = _.extend({
"Accept": "application/json",
"Content-Type": "application/json",
- "Content-Length": payload.length
+ "Content-Length": Buffer.byteLength(payload)
}, config.headers || {});
var options = {
@@ -44,7 +44,11 @@ function RestClient(host, port, config) {
port: port,
path: path,
method: method,
- headers: headers
+ headers: headers,
+ timeout: config.timeout || 60 * 1000,
+ pool: config.pool || {
+ maxSockets: 100000,
+ },
};
if (config.username)
options.auth = config.username + ":" + config.password;
diff --git a/node_modules/c9/rest_client_test.js b/node_modules/c9/rest_client_test.js
new file mode 100644
index 00000000..a0f07779
--- /dev/null
+++ b/node_modules/c9/rest_client_test.js
@@ -0,0 +1,55 @@
+#!/usr/bin/env node
+
+/*global describe it before after beforeEach afterEach */
+"use strict";
+
+"use server";
+"use mocha";
+
+require("c9/inline-mocha")(module);
+require("amd-loader");
+
+var assert = require("assert");
+var http = require("http");
+var findFreePort = require("netutil").findFreePort;
+var RestClient = require("./rest_client");
+
+describe(__filename, function() {
+
+ var port;
+ var MIN_API_PORT = 18500;
+ var MAX_API_PORT = MIN_API_PORT + 1000;
+
+ beforeEach(function(next) {
+ findFreePort(MIN_API_PORT, MAX_API_PORT, 'localhost', function(err, _port) {
+ port = _port;
+ next(err);
+ });
+ });
+
+ it("should send correct content length", function(next) {
+ var server = http.createServer(function(req, res) {
+ var body = "";
+ req.on("data", function(d) {
+ body += d;
+ });
+
+ req.on("end", function() {
+ JSON.parse(body);
+ res.end("OK");
+ });
+
+ });
+ server.listen(port, function() {
+ var client = new RestClient("localhost", port, {});
+
+ // send body with "strange" unicode character
+ var body = {"cloneFromScm":"https://github.com/saasbook/ruby-calisthenics"};
+ client.request("POST", "/", body, function(err, res) {
+ assert(!err, err);
+ assert.equal(res, "OK");
+ server.close(next);
+ });
+ });
+ });
+});
\ No newline at end of file
diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js
index 0eba62a4..6885fefa 100644
--- a/node_modules/vfs-local/localfs.js
+++ b/node_modules/vfs-local/localfs.js
@@ -200,7 +200,9 @@ module.exports = function setup(fsOptions) {
// Extending the API
extend: extend,
unextend: unextend,
- use: use
+ use: use,
+
+ workspaceDir: fsOptions.projectDir
});
function wrapDomain(api) {
@@ -1030,7 +1032,16 @@ module.exports = function setup(fsOptions) {
if (!exists || options.overwrite || isSamePath) {
// Rename the file
fs.rename(frompath, topath, function (err) {
- if (err) return callback(err);
+ if (err) {
+ if (err.code == 'ENOENT' && options.mkdirP != false) {
+ options.mkdirP = false;
+ return mkdirP(dir, {}, function(err) {
+ if (err) return callback(err);
+ rename(path, options, callback);
+ });
+ }
+ return callback(err);
+ }
// Rename metadata
if (options.metadata !== false) {
@@ -1551,7 +1562,7 @@ module.exports = function setup(fsOptions) {
// todo add resize event
proc.emit("data", {rows: rows, cols: cols});
- if (!tmuxWarned) {
+ if (!tmuxWarned && !isWin) {
if (/v0\.([123456789]\..*|10\.(0|1|2[0-7]))/.test(process.version)) {
proc.emit("data", {
message: "Wrong Node.js version: " + process.version,
@@ -1827,9 +1838,11 @@ module.exports = function setup(fsOptions) {
}
else if (options.command) {
args.push(BASH + " -l -c '"
- + options.command.replace(/'/g, "'\\''")
- + '; printf "\\e[01;30m\\n\\nProcess exited with code: $?\\e[0m\\n"'
- + "; sleep 0.1;'");
+ + (
+ 'trap \'printf "\\e[01;30m\\n\\nProcess exited with code: $?\\e[0m\\n"\' EXIT\n'
+ + options.command
+ ).replace(/'/g, "'\\''")
+ + "'");
}
args.push(
@@ -1995,15 +2008,20 @@ module.exports = function setup(fsOptions) {
};
this.destroy = function(){
- pty.destroy.apply(pty, arguments);
+ return pty.destroy.apply(pty, arguments);
};
this.end = function(){
- pty.end.apply(pty, arguments);
+ return pty.end.apply(pty, arguments);
};
this.write = function() {
- pty.write.apply(pty, arguments);
+ return pty.write.apply(pty, arguments);
+ };
+
+ this.resize = function() {
+ if (!exited)
+ return pty.resize.apply(pty, arguments);
};
// this.acknowledgeWrite = function(callback) {
diff --git a/node_modules/vfs-socket/worker.js b/node_modules/vfs-socket/worker.js
index fbf197a3..ed7a282b 100644
--- a/node_modules/vfs-socket/worker.js
+++ b/node_modules/vfs-socket/worker.js
@@ -437,6 +437,8 @@ function Worker(vfs) {
var keys = Object.keys(meta || {});
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
+ if (meta[key] == undefined)
+ continue;
switch (key) {
case "stream": token.stream = storeStream(meta.stream); break;
case "process": token.process = storeProcess(meta.process); break;
diff --git a/package.json b/package.json
index 013a3419..0d6efb58 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "c9",
"description": "New Cloud9 Client",
- "version": "3.1.1776",
+ "version": "3.1.2074",
"author": "Ajax.org B.V. ",
"private": true,
"main": "bin/c9",
@@ -26,7 +26,7 @@
"mkdirp": "~0.3.5",
"msgpack-js": "~0.1.1",
"msgpack-js-browser": "~0.1.4",
- "nak": "git://github.com/cloud9ide/nak.git#719f2188ec1d8e4ce553286e80737d7e6434d777",
+ "nak": "git://github.com/cloud9ide/nak.git#6deef931594",
"netutil": "~0.0.2",
"optimist": "~0.6.0",
"qs": "0.6.6",
@@ -55,24 +55,24 @@
"c9"
],
"c9plugins": {
- "c9.ide.language": "#b392f03a6c",
+ "c9.ide.language": "#e058ff301f",
"c9.ide.language.css": "#be07d72209",
- "c9.ide.language.generic": "#92210f5a48",
+ "c9.ide.language.generic": "#3949510863",
"c9.ide.language.html": "#22fdc74869",
"c9.ide.language.html.diff": "#24f3608d26",
- "c9.ide.language.javascript": "#d1a479805c",
+ "c9.ide.language.javascript": "#e626169643",
"c9.ide.language.javascript.immediate": "#c8b1e5767a",
- "c9.ide.language.javascript.eslint": "#3c57ed1720",
+ "c9.ide.language.javascript.eslint": "#4de5457db1",
"c9.ide.language.javascript.tern": "#64ab01f271",
"c9.ide.language.javascript.infer": "#18acb93a3a",
"c9.ide.language.jsonalyzer": "#4b329741b1",
- "c9.ide.language.codeintel": "#72157892e4",
- "c9.ide.collab": "#11a0d3c5ce",
+ "c9.ide.language.codeintel": "#44b7cb3565",
+ "c9.ide.collab": "#728ad2bde2",
"c9.ide.local": "#10eb45842a",
"c9.ide.find": "#e33fbaed2f",
"c9.ide.find.infiles": "#c0a13737ef",
- "c9.ide.find.replace": "#8cbce45290",
- "c9.ide.run.debug": "#286975f644",
+ "c9.ide.find.replace": "#810ebf8bfb",
+ "c9.ide.run.debug": "#ef40edcc3f",
"c9.automate": "#47e2c429c9",
"c9.ide.ace.emmet": "#6dc4585e02",
"c9.ide.ace.gotoline": "#a8ff07c8f4",
@@ -80,24 +80,24 @@
"c9.ide.ace.repl": "#4b88a85b7b",
"c9.ide.ace.split": "#0ae0151c78",
"c9.ide.ace.statusbar": "#3aab0b67e0",
- "c9.ide.ace.stripws": "#8885016b9e",
+ "c9.ide.ace.stripws": "#042a9936e3",
"c9.ide.behaviors": "#db32109ebc",
"c9.ide.closeconfirmation": "#cee4674141",
- "c9.ide.configuration": "#528234d97d",
+ "c9.ide.configuration": "#a936df26bb",
"c9.ide.dialog.wizard": "#7667ec79a8",
"c9.ide.fontawesome": "#781602c5d8",
"c9.ide.format": "#5ec97fb083",
- "c9.ide.help.support": "#af5c4055b2",
+ "c9.ide.help.support": "#932fbb3743",
"c9.ide.imgeditor": "#612e75ef4f",
"c9.ide.immediate": "#19758abe08",
- "c9.ide.installer": "#0fde9f0067",
+ "c9.ide.installer": "#1232d4e179",
"c9.ide.language.python": "#701bd2630a",
"c9.ide.language.go": "#6ce1c7a7ef",
"c9.ide.mount": "#4c39359b87",
- "c9.ide.navigate": "#1fbb7cd53b",
+ "c9.ide.navigate": "#0b7ec7936c",
"c9.ide.newresource": "#981a408a7b",
"c9.ide.openfiles": "#2ae85a9e33",
- "c9.ide.preview": "#70bd68740c",
+ "c9.ide.preview": "#5f5fff0185",
"c9.ide.preview.browser": "#897177be7f",
"c9.ide.preview.markdown": "#c3174d86e0",
"c9.ide.pubsub": "#a85fb27eca",
@@ -105,19 +105,19 @@
"c9.ide.recentfiles": "#7c099abf40",
"c9.ide.remote": "#301d2ab519",
"c9.ide.processlist": "#2b12cd1bdd",
- "c9.ide.run": "#4f0257bc0b",
+ "c9.ide.run": "#6bd4996a4e",
"c9.ide.run.build": "#0598fff697",
"c9.ide.run.debug.xdebug": "#9956689819",
- "c9.ide.save": "#86f0f38160",
- "c9.ide.scm": "#f1d190fa51",
- "c9.ide.terminal.monitor": "#1a4092ede2",
- "c9.ide.test": "#a282ec1619",
+ "c9.ide.save": "#4cda35bfdb",
+ "c9.ide.scm": "#637a68cd04",
+ "c9.ide.terminal.monitor": "#affa33572f",
+ "c9.ide.test": "#102942ae4e",
"c9.ide.test.mocha": "#fc053b23d2",
"c9.ide.theme.flat": "#81dadeee55",
"c9.ide.threewaymerge": "#229382aa0b",
"c9.ide.undo": "#b028bcb4d5",
- "c9.ide.upload": "#0bd010d3dc",
+ "c9.ide.upload": "#a3da59803d",
"c9.ide.welcome": "#5b86c44e92",
- "c9.ide.guide": "#16537f57cf"
+ "c9.ide.guide": "#8ab966f344"
}
}
\ No newline at end of file
diff --git a/plugins/c9.cli.bridge/bridge-client.js b/plugins/c9.cli.bridge/bridge-client.js
index f27353be..c5325542 100644
--- a/plugins/c9.cli.bridge/bridge-client.js
+++ b/plugins/c9.cli.bridge/bridge-client.js
@@ -59,7 +59,7 @@ define(function(require, exports, module) {
if (done) return;
callback(new Error("No Response"));
done = true;
- })
+ });
});
}
diff --git a/plugins/c9.cli.bridge/bridge_commands.js b/plugins/c9.cli.bridge/bridge_commands.js
index 1952f719..f078cece 100644
--- a/plugins/c9.cli.bridge/bridge_commands.js
+++ b/plugins/c9.cli.bridge/bridge_commands.js
@@ -2,7 +2,7 @@
define(function(require, exports, module) {
main.consumes = [
"Plugin", "bridge", "tabManager", "panels", "tree.favorites", "tree",
- "fs", "preferences", "settings", "c9"
+ "fs", "preferences", "settings", "c9", "commands"
];
main.provides = ["bridge.commands"];
return main;
@@ -18,6 +18,7 @@ define(function(require, exports, module) {
var fs = imports.fs;
var c9 = imports.c9;
var prefs = imports.preferences;
+ var commands = imports.commands;
var async = require("async");
@@ -36,6 +37,15 @@ define(function(require, exports, module) {
case "open":
open(message, e.respond);
break;
+ case "exec":
+ exec(message, e.respond);
+ break;
+ case "pipe":
+ createPipe(message, e.respond);
+ break;
+ case "pipeData":
+ updatePipe(message, e.respond);
+ break;
case "ping":
e.respond(null, true);
break;
@@ -66,6 +76,30 @@ define(function(require, exports, module) {
}
/***** Methods *****/
+ function createPipe(message, callback) {
+ tabManager.once("ready", function(){
+ tabManager.open({
+ focus: true,
+ editorType: "ace",
+ path: message.path && c9.toInternalPath(message.path),
+ document: { meta : { newfile: true } }
+ }, function(err, tab) {
+ if (err)
+ return callback(err);
+ callback(null, tab.path || tab.name);
+ });
+ });
+ }
+
+ function updatePipe(message, callback) {
+ tabManager.once("ready", function() {
+ var tab = tabManager.findTab(message.tab);
+ var c9Session = tab && tab.document.getSession();
+ if (c9Session && c9Session.session)
+ c9Session.session.insert({row: Number.MAX_VALUE, column: Number.MAX_VALUE} , message.data);
+ callback(null, true);
+ });
+ }
function open(message, callback) {
var i = -1;
@@ -102,12 +136,22 @@ define(function(require, exports, module) {
}
else {
tabManager.once("ready", function(){
+ var m = /:(\d*)(?::(\d*))?$/.exec(path);
+ var jump = {};
+ if (m) {
+ if (m[1])
+ jump.row = parseInt(m[1], 10) - 1;
+ if (m[2])
+ jump.column = parseInt(m[2], 10);
+ path = path.slice(0, m.index);
+ }
+
fs.exists(path, function(existing) {
var tab = tabManager.open({
path: path,
focus: i === 0,
document: existing
- ? undefined
+ ? { ace: { jump: jump } }
: { meta : { newfile: true } }
}, function(){
next();
@@ -133,6 +177,12 @@ define(function(require, exports, module) {
callback(null, true);
});
}
+
+ function exec(message, callback) {
+ var result = commands.exec(message.command, message.args);
+ var err = result ? null : "command failed";
+ callback(err, result);
+ }
/***** Lifecycle *****/
diff --git a/plugins/c9.cli.exec/exec.js b/plugins/c9.cli.exec/exec.js
new file mode 100644
index 00000000..e8a48f4b
--- /dev/null
+++ b/plugins/c9.cli.exec/exec.js
@@ -0,0 +1,92 @@
+define(function(require, exports, module) {
+ main.consumes = ["Plugin", "cli_commands", "bridge.client"];
+ main.provides = ["exec"];
+ return main;
+
+ function main(options, imports, register) {
+ var Plugin = imports.Plugin;
+ var cmd = imports.cli_commands;
+ var bridge = imports["bridge.client"];
+
+ /***** Initialization *****/
+
+ var plugin = new Plugin("Ajax.org", main.consumes);
+ // var emit = plugin.getEmitter();
+
+ var loaded;
+ function load(){
+ if (loaded) return;
+ loaded = true;
+
+ cmd.addCommand({
+ name: "exec",
+ info: " Executes remote c9 commands.",
+ usage: " [argument 1] [argument 2] ... [argument n]",
+ check: function(argv) {
+ if (argv._.length < 2)
+ throw new Error("Missing command");
+ },
+ options: {},
+ exec: function(argv) {
+ exec(
+ argv._[1],
+ argv._.slice(2),
+ function(){});
+ }
+ });
+ }
+
+ /***** Methods *****/
+
+ function exec(command, args, callback) {
+ args.unshift(process.cwd());
+ var message = {
+ type: "exec",
+ command: command,
+ args: args
+ };
+
+ bridge.send(message, function cb(err, response) {
+ if (err) {
+ console.log(err.message);
+ }
+
+ if (response !== true)
+ console.log("Could not execute", command);
+
+ process.exit(); // I don't get why this is needed
+ });
+ }
+
+ /***** Lifecycle *****/
+
+ plugin.on("load", function(){
+ load();
+ });
+ plugin.on("enable", function(){
+
+ });
+ plugin.on("disable", function(){
+
+ });
+ plugin.on("unload", function(){
+ loaded = false;
+ });
+
+ /***** Register and define API *****/
+
+ /**
+ * Finds or lists files and/or lines based on their filename or contents
+ **/
+ plugin.freezePublicAPI({
+ /**
+ *
+ */
+ exec: exec
+ });
+
+ register(null, {
+ exec: plugin
+ });
+ }
+});
\ No newline at end of file
diff --git a/plugins/c9.cli.open/open.js b/plugins/c9.cli.open/open.js
index d186f500..5b8b68da 100755
--- a/plugins/c9.cli.open/open.js
+++ b/plugins/c9.cli.open/open.js
@@ -25,19 +25,28 @@ define(function(require, exports, module) {
cmd.addCommand({
name: "open",
info: " Opens a file or directory.",
- usage: "[--wait] ",
+ usage: "[--wait] [--pipe] ",
options: {
"wait": {
description: "Wait until the file(s) are closed",
"default": false,
"boolean": true
+ },
+ "pipe": {
+ description: "Pipe data from a command into c9",
+ "default": false,
+ "boolean": true
}
},
check: function(argv) {
- if (argv._.length < 2 && !argv["path"])
+ if (argv._.length < 2 && !argv["path"] && !argv.pipe)
throw new Error("Missing path");
},
exec: function(argv) {
+ if (argv.pipe) {
+ openWithPipe(function(){});
+ return;
+ }
open(
argv._.slice(1), // Remove "open" from the paths
argv.wait,
@@ -126,6 +135,60 @@ define(function(require, exports, module) {
});
}
+ function openWithPipe(callback) {
+ bridge.send({
+ type: "pipe",
+ path: process.cwd() + "/" + "Pipe " + (new Date()).toLocaleString().replace(/:/g, "."),
+ }, function cb(err, response) {
+ if (err) {
+ if (err.code == "ECONNREFUSED") {
+ // Seems Cloud9 is not running, lets start it up
+ startCloud9Local({}, function(success) {
+ if (success)
+ bridge.send({ type: "pipe" }, cb);
+ else {
+ console.log("Could not start Cloud9. "
+ + "Please check your configuration.");
+ callback(err);
+
+ process.exit(40); // This appears to be needed; let's return something useful
+ }
+ });
+ return;
+ }
+ else {
+ console.log(err.message);
+ return;
+ }
+ }
+
+ var stdin = process.openStdin();
+ stdin.setEncoding("utf8");
+ var finished = 0;
+ stdin.on("data", function(chunk) {
+ finished++;
+ bridge.send({
+ type: "pipeData",
+ data: chunk,
+ tab: response
+ }, function(err, message) {
+ // Dunno why, but this always returns No Response...
+ // Escaping that error so end users aren't confused...
+ if (err && err.message !== "No Response")
+ console.log(err.message);
+ finished--;
+ });
+ });
+ stdin.on("end", function() {
+ (function retry() {
+ if (finished === 0)
+ process.exit();
+ setTimeout(retry, 100);
+ })();
+ });
+ });
+ }
+
function startCloud9Local(opts, callback) {
if (options.platform == "darwin") {
proc.spawn("open", {
diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js
index d3efede7..3c8551c9 100644
--- a/plugins/c9.cli.publish/publish.js
+++ b/plugins/c9.cli.publish/publish.js
@@ -653,6 +653,10 @@ define(function(require, exports, module) {
p = "/" + normalizePath(Path.relative(cwd, p));
excludeMap[p] = 1;
});
+ // keep installer in both packed and unpacked form
+ if (json.installer)
+ excludeMap["/" + normalizePath(Path.relative(cwd, json.installer))] = 0;
+
copy(cwd, cwd + "/.c9/.build", {
exclude: function(name, parent) {
if (excludeRe.test(name))
diff --git a/plugins/c9.core/ext.js b/plugins/c9.core/ext.js
index d8a1e866..5768c28a 100644
--- a/plugins/c9.core/ext.js
+++ b/plugins/c9.core/ext.js
@@ -577,7 +577,7 @@ define(function(require, exports, module) {
function setAPIKey(apikey){
// Validate Key
- if (!apikey || !apikey.match(/[\w+]{27}=/))
+ if (!apikey || !apikey.match(/^.{27}=$/))
throw new Error("Invalid API key");
return {
diff --git a/plugins/c9.error/error_handler.js b/plugins/c9.error/error_handler.js
index 1c46ee68..4e3fe2af 100644
--- a/plugins/c9.error/error_handler.js
+++ b/plugins/c9.error/error_handler.js
@@ -115,6 +115,7 @@ function plugin(options, imports, register) {
var accept = req.headers.accept || '';
if (statusCode == 500) {
+ console.error(err && err.stack);
emitter.emit("internalServerError", {
err: err,
req: req
diff --git a/plugins/c9.error/raygun.connect.js b/plugins/c9.error/raygun.connect.js
index 512be225..922eae90 100644
--- a/plugins/c9.error/raygun.connect.js
+++ b/plugins/c9.error/raygun.connect.js
@@ -90,6 +90,7 @@ function plugin(options, imports, register) {
var customData = _.clone(raygun.customData || {});
if (req.user) {
customData.user = {
+ augment: err.augment,
id: req.user.id,
name: req.user.name,
email: req.user.email
diff --git a/plugins/c9.error/raygun.js b/plugins/c9.error/raygun.js
index 6a51ce0b..ca753d4a 100644
--- a/plugins/c9.error/raygun.js
+++ b/plugins/c9.error/raygun.js
@@ -25,8 +25,8 @@ function plugin(options, imports, register) {
};
var clients = {
- error: new raygun.Client().init({ apiKey: options.keys.error }),
- warning: new raygun.Client().init({ apiKey: options.keys.warning })
+ error: new raygun.Client().init({ apiKey: options.keys.error, useHumanStringForObject: false }),
+ warning: new raygun.Client().init({ apiKey: options.keys.warning, useHumanStringForObject: false })
};
var customClients = options.customClients || {};
diff --git a/plugins/c9.error/views/error-503.html.ejs b/plugins/c9.error/views/error-503.html.ejs
index 86c37845..eb7394ba 100644
--- a/plugins/c9.error/views/error-503.html.ejs
+++ b/plugins/c9.error/views/error-503.html.ejs
@@ -1,7 +1,7 @@
- <%=error%>
+ 503 - Service Unavailable
diff --git a/plugins/c9.fs/fs.cache.xml.js b/plugins/c9.fs/fs.cache.xml.js
index 34b693b2..7922f9a0 100644
--- a/plugins/c9.fs/fs.cache.xml.js
+++ b/plugins/c9.fs/fs.cache.xml.js
@@ -82,6 +82,9 @@ define(function(require, exports, module) {
node.status = "pending";
return;
}
+ var parentPath = e.path;
+ if (!parentPath.endsWith("/"))
+ parentPath += "/";
// update cache
if (!node) {
if (!showHidden && isFileHidden(e.path))
@@ -92,97 +95,116 @@ define(function(require, exports, module) {
orphans[e.path] = node;
orphan = true;
}
+ node.$lastReadT = Date.now();
// Indicate this directory has been fully read
model.setAttribute(node, "status", "loaded");
- var wasOpen = startUpdate(node);
- node.children = null;
- var existing = node.map || {};
- node.map = {};
-
- // Fill Parent
- var ondisk = {}, toAppend = [];
+ var ondisk = Object.create(null);
+ var toRemove = [];
+ var toCreate = [];
+ var orphanAppand = [];
+ var existing = node.map || (node.map = Object.create(null));
e.result[1].forEach(function(stat) {
if (!stat.name || !showHidden && isFileHidden(stat.name))
return;
-
var name = stat.name;
- var path = (e.path + "/" + name).replace("//", "/");
+ var path = parentPath + name;
ondisk[name] = 1;
- // if (existing[name]) return;
+
if (orphans[path]) {
- toAppend.push(path);
+ if (existing[name])
+ delete orphans[path];
+ orphanAppand.push(path);
}
- createNode(path, stat, existing[name], true);
+
+ if (existing[name])
+ updateNodeStat(path, stat, existing[name]);
+ else
+ toCreate.push(stat);
});
- for (var name in existing) {
- if (!ondisk[name]) {
- // onreaddir can be called before copied nodes are written to disk
- // in this case we don't want to lose "predicted" state
- if (existing[name] && existing[name].status === "predicted")
- node.map[name] = existing[name];
- else {
- delete existing[name];
-
- emit("remove", {
- path: e.path + "/" + name,
- node: existing[name],
- parent: node
- });
- }
- }
- }
+ Object.keys(existing).forEach(function(name) {
+ // onreaddir can be called before copied nodes are written to disk
+ // in this case we don't want to lose "predicted" state
+ if (existing[name] && existing[name].status === "predicted")
+ ondisk[name] = 1;
+ if (!ondisk[name])
+ toRemove.push(name);
+ });
+
+ if (!toCreate.length && !toRemove.length && !orphanAppand.length)
+ return;
+
+ var wasOpen = startUpdate(node);
+ node.children = null;
+
+ // Fill Parent
+ toCreate.forEach(function(stat) {
+ createNode(parentPath + stat.name, stat, null, true);
+ });
+
+ toRemove.forEach(function(name) {
+ var currentNode = existing[name];
+ delete existing[name];
+ emit("remove", {
+ path: parentPath + name,
+ node: currentNode,
+ parent: node
+ });
+ });
emit("readdir", { path : e.path, parent : node, orphan: orphan });
endUpdate(node, wasOpen);
- toAppend.forEach(function(path) {
+ orphanAppand.forEach(function(path) {
emit("orphan-append", {path: path});
});
}
fs.on("afterReaddir", onreaddir, plugin);
function onstat(e) {
- var stat;
+ if (e.error) return;
- if (!e.error) {
- // update cache
- var there = true;
- var node = findNode(e.path);
- var parent = findNode(dirname(e.path));
-
- if (!showHidden && isFileHidden(e.path))
- return;
+ // update cache
+ var stat = e.result[1];
+
+ var there = true;
+ var node = findNode(e.path);
+ var parent = findNode(dirname(e.path));
+
+ if (!showHidden && isFileHidden(e.path))
+ return;
- if (!node) {
- if (!parent)
- return;
- there = false;
+ if (!node) {
+ if (!parent)
+ return;
+ there = false;
+ }
+
+ if (there != !!stat) {
+ if (there) {
+ if (!node.link)
+ deleteNode(node);
}
-
- if (there != !!e.result[1]) {
- if (there) {
- if (!node.link)
- deleteNode(node);
- }
- else {
- stat = e.result[1];
- if (typeof stat != "object")
- stat = null;
- createNode(e.path, stat);
- }
- }
- else if (there) {
- stat = e.result[1];
+ else {
if (typeof stat != "object")
stat = null;
- createNode(e.path, stat, node);
+ createNode(e.path, stat);
}
}
+ else if (there) {
+ if (typeof stat != "object")
+ stat = null;
+ if (!stat && node)
+ return;
+ if (stat && node)
+ updateNodeStat(e.path, stat, node);
+ else
+ createNode(e.path, stat, node);
+ }
}
fs.on("afterStat", onstat, plugin);
fs.on("afterReadFile", function(e) {
@@ -295,14 +317,15 @@ define(function(require, exports, module) {
// Validation
var toNode = findNode(newPath);
- deleteNode(node, true);
- if (toNode)
- deleteNode(toNode, true);
-
- createNode(newPath, null, node); // Move node
- recurPathUpdate(node, oldPath, newPath);
+ if (!toNode) {
+ deleteNode(node, true);
+ createNode(newPath, null, node); // Move node
+ recurPathUpdate(node, oldPath, newPath);
+ }
e.undo = function(){
+ if (toNode)
+ return;
if (!parent) {
var tmpParent = node;
while (node.parent && tmpParent.parent.status == "pending")
@@ -318,6 +341,12 @@ define(function(require, exports, module) {
recurPathUpdate(node, newPath, oldPath);
};
e.confirm = function() {
+ if (toNode) {
+ deleteNode(toNode, true);
+ createNode(newPath, null, node); // Move node
+ recurPathUpdate(node, oldPath, newPath);
+ }
+
if (node.status === "predicted")
node.status = "loaded";
};
@@ -511,14 +540,8 @@ define(function(require, exports, module) {
updateNode = orphans[path];
delete orphans[path];
}
- var original_stat;
- if (stat && stat.link) {
- original_stat = stat;
- stat = stat.linkStat;
- }
var parts = path.split("/");
- var name = parts[parts.length - 1];
var node = model.root.map[parts[0] == "~" ? "~" : ""];
if (!node) {
node = orphans[parts[0]];
@@ -537,7 +560,7 @@ define(function(require, exports, module) {
var map = node.map;
if (!map) {
- map = node.map = {};
+ map = node.map = Object.create(null);
}
parent = node;
node = map[p];
@@ -545,6 +568,11 @@ define(function(require, exports, module) {
modified.push(parent);
if (i !== parts.length - 1) {
node = {label: p, path: subPath, status: "pending", isFolder: true};
+ // TODO filter hidden files in getChildren instead.
+ if (!showHidden && isFileHidden(p)) {
+ orphans[node.path] = path;
+ return;
+ }
} else if (updateNode) {
deleteNode(updateNode, true);
node = updateNode;
@@ -564,8 +592,32 @@ define(function(require, exports, module) {
node = {label: parts[parts.length - 1], path: path};
orphans[path] = node;
}
+
+ updateNodeStat(path, stat, node);
+
+ node.children = null;
+
+ if (!updating) {
+ if (!modified.length)
+ modified.push(parent);
+ var wasOpen = startUpdate(modified[0]);
+ modified.forEach(function(n) {
+ if (n != model.root)
+ n.children = null;
+ });
+ endUpdate(modified[0], wasOpen);
+ }
+ model._signal("createNode", node);
+ return node;
+ }
+
+ function updateNodeStat(path, stat, node) {
node.path = path;
-
+ var original_stat;
+ if (stat && stat.link) {
+ original_stat = stat;
+ stat = stat.linkStat;
+ }
if (stat) {
var isFolder = stat && /(directory|folder)$/.test(stat.mime);
if (isFolder) {
@@ -589,25 +641,13 @@ define(function(require, exports, module) {
delete node.isFolder;
}
- if (node.isFolder && !node.map)
- node.map = {};
- else if (!node.isFolder && node.map)
+ if (node.isFolder && !node.map) {
+ node.map = Object.create(null);
+ node.children = null;
+ } else if (!node.isFolder && node.map) {
delete node.map;
-
- node.children = null;
-
- if (!updating) {
- if (!modified.length)
- modified.push(parent);
- var wasOpen = startUpdate(modified[0]);
- modified.forEach(function(n) {
- if (n != model.root)
- n.children = null;
- });
- endUpdate(modified[0], wasOpen);
+ node.children = null;
}
- model._signal("createNode", node);
- return node;
}
function deleteNode(node, silent) {
@@ -670,7 +710,7 @@ define(function(require, exports, module) {
map: {}
};
var root = {};
- root.map = {};
+ root.map = Object.create(null);
root.map[""] = model.projectDir;
model.setRoot(root);
// fs.readdir("/", function(){});
@@ -894,7 +934,12 @@ define(function(require, exports, module) {
* @param {Function} progress
* @param {Function} done
*/
- loadNodes: loadNodes
+ loadNodes: loadNodes,
+
+ /**
+ * @ignore
+ */
+ isFileHidden: isFileHidden
});
register(null, {
diff --git a/plugins/c9.fs/proc_test.js b/plugins/c9.fs/proc_test.js
index db68c57e..96be5406 100644
--- a/plugins/c9.fs/proc_test.js
+++ b/plugins/c9.fs/proc_test.js
@@ -37,7 +37,7 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
describe('proc', function() {
describe('spawn()', function() {
- this.timeout(4000);
+ this.timeout(10000);
it("should spawn a child process", function(done) {
var args = ["-e", "process.stdin.pipe(process.stdout);try{process.stdin.resume()}catch(e) {};"];
@@ -66,8 +66,8 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
});
});
- //should test the kill() method - which is broken now
- //Another test - see that cwd defaults to the root vfs dir when resolve is set to true
+ // should test the kill() method - which is broken now
+ // Another test - see that cwd defaults to the root vfs dir when resolve is set to true
});
describe('execFile()', function() {
this.timeout(10000);
@@ -101,8 +101,19 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
});
});
- //should test the kill() method - which is broken now
- //Another test - see that cwd defaults to the root vfs dir when resolve is set to true
+ it('should pass stdout and stderr', function(done) {
+ proc.execFile("node", {
+ args: ["-v"]
+ }, function(e, stdout, stderr) {
+ expect(stdout[0]).to.equal("v");
+ expect(stderr).to.equal("");
+ expect(e).to.not.ok;
+ done();
+ });
+ });
+
+ // should test the kill() method - which is broken now
+ // Another test - see that cwd defaults to the root vfs dir when resolve is set to true
});
describe('pty()', function() {
this.timeout(30000);
diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js
index ff712657..b2da9718 100644
--- a/plugins/c9.ide.ace/ace.js
+++ b/plugins/c9.ide.ace/ace.js
@@ -1444,7 +1444,7 @@ define(function(require, exports, module) {
else if (/^{/.test(firstLine)) {
syntax = "json";
}
- else if (/\.(bashrc|inputrc)$/.test(path)) {
+ else if (/\.(bash|inputrc|profile|zsh)/.test(path)) {
syntax = "sh";
}
else if (/\.(git(attributes|config|ignore)|npmrc)$/.test(path)) {
diff --git a/plugins/c9.ide.dialog.common/alert_internal.js b/plugins/c9.ide.dialog.common/alert_internal.js
index 572c48ad..98744ee1 100644
--- a/plugins/c9.ide.dialog.common/alert_internal.js
+++ b/plugins/c9.ide.dialog.common/alert_internal.js
@@ -26,6 +26,8 @@ define(function(require, module, exports) {
/***** Methods *****/
function show(title, header, msg, onhide, options) {
+ options = options || {};
+
metrics.increment("dialog.error");
return plugin.queue(function(){
@@ -37,13 +39,15 @@ define(function(require, module, exports) {
else {
plugin.title = title;
}
- plugin.heading = options && options.isHTML ? header : util.escapeXml(header);
- plugin.body = options && options.isHTML ? msg : (util.escapeXml(msg) || "")
+ plugin.heading = options.isHTML ? header : util.escapeXml(header);
+ plugin.body = options.isHTML ? msg : (util.escapeXml(msg) || "")
.replace(/\n/g, "
")
.replace(/(https?:\/\/[^\s]*\b)/g, "$1");
+ plugin.getElement("ok").setCaption(options.yes || "OK");
+
plugin.update([
- { id: "dontshow", visible: options && options.showDontShow }
+ { id: "dontshow", visible: options.showDontShow }
]);
plugin.once("hide", function(){
diff --git a/plugins/c9.ide.dialog.common/question.js b/plugins/c9.ide.dialog.common/question.js
index 7e3be92e..23d08df1 100644
--- a/plugins/c9.ide.dialog.common/question.js
+++ b/plugins/c9.ide.dialog.common/question.js
@@ -54,7 +54,7 @@ define(function(require, module, exports) {
var gotYesNo = false;
plugin.once("hide", function(){
- !gotYesNo && cancel && onNo(false, true, metadata);
+ !gotYesNo && cancel && onNo && onNo(false, true, metadata);
});
plugin.update([
@@ -63,22 +63,22 @@ define(function(require, module, exports) {
{ id: "yestoall", visible: all, onclick: function(){
gotYesNo = true;
plugin.hide();
- onYes(true, metadata);
+ onYes && onYes(true, metadata);
}},
{ id: "notoall", visible: all, onclick: function(){
gotYesNo = true;
plugin.hide();
- onNo(true, false, metadata);
+ onNo && onNo(true, false, metadata);
}},
{ id: "yes", onclick: function(){
gotYesNo = true;
plugin.hide();
- onYes(false, metadata);
+ onYes && onYes(false, metadata);
}},
{ id: "no", onclick: function(){
gotYesNo = true;
plugin.hide();
- onNo(false, false, metadata);
+ onNo && onNo(false, false, metadata);
}}
]);
}, options.queue === false);
diff --git a/plugins/c9.ide.dialog.common/upsell.js b/plugins/c9.ide.dialog.common/upsell.js
index 0200a9ba..1b5af324 100644
--- a/plugins/c9.ide.dialog.common/upsell.js
+++ b/plugins/c9.ide.dialog.common/upsell.js
@@ -27,14 +27,14 @@ define(function(require, module, exports) {
options = {isHTML: true};
return plugin.queue(function(){
- var all = options.all;
var cancel = options.cancel;
- var showDontAsk = options.showDontAsk;
var metadata = options.metadata;
title = title || "This is a Premium feature";
- header = header || "Get Premium Support Now!";
- msg = msg || 'Help is just a few clicks away. Check out our amazing premium plans.'
+ header = header || "Upgrade to Premium Now!";
+ onYes = onYes || function() {};
+ onNo = onNo || function() {};
+ msg = msg || 'A better, faster, more versatile Cloud9 is just a click away. Check out our amazing premium plans.';
plugin.title = title;
plugin.heading = options && options.isHTML ? header : util.escapeXml(header);
@@ -73,7 +73,12 @@ define(function(require, module, exports) {
plugin.freezePublicAPI({
/**
- *
+ * @param {Function} onYes Callback for when user clicks the 'yes' button
+ * @param {Function} onNo Callback for when the user clicks the 'no' button
+ * @param {String} [title] Title for the dialog
+ * @param {String} [header] Header for the dialog body
+ * @param {String} [msg] Message to show the user.
+ * @param {Object} [options] Miscellaneous options
*/
show: show
});
diff --git a/plugins/c9.ide.dialog.file/file.xml b/plugins/c9.ide.dialog.file/file.xml
index 590bd4f5..dd4b341e 100644
--- a/plugins/c9.ide.dialog.file/file.xml
+++ b/plugins/c9.ide.dialog.file/file.xml
@@ -27,7 +27,7 @@
@@ -46,7 +46,7 @@
diff --git a/plugins/c9.ide.dialog.login/login.xml b/plugins/c9.ide.dialog.login/login.xml
index 82b954e8..aff22bd0 100644
--- a/plugins/c9.ide.dialog.login/login.xml
+++ b/plugins/c9.ide.dialog.login/login.xml
@@ -28,7 +28,7 @@
@@ -41,7 +41,7 @@
diff --git a/plugins/c9.ide.dialog/dialog.js b/plugins/c9.ide.dialog/dialog.js
index bf5d15e3..77f36633 100644
--- a/plugins/c9.ide.dialog/dialog.js
+++ b/plugins/c9.ide.dialog/dialog.js
@@ -245,14 +245,16 @@ define(function(require, module, exports) {
dropdown.setAttribute("value", item.value);
break;
default:
- if ("value" in item)
- el.setAttribute('value', item.value);
- if ("onclick" in item)
- el.onclick = item.onclick;
- if ("visible" in item)
- el.setAttribute("visible", item.visible);
- if ("zindex" in item)
- el.setAttribute("zindex", item.zindex);
+ // supported attributes
+ var validAttributes = /^(value|visible|zindex|disabled|caption|tooltip|command|class|icon|src|submenu)$/;
+ Object.keys(item).forEach(function(key) {
+ // Check for onclick explictly
+ if (key === "onclick")
+ return el.onclick = item.onclick;
+ // Check for attributes we know exist and will directly set
+ if (validAttributes.test(key))
+ return el.setAttribute(key, item[key]);
+ });
break;
}
});
diff --git a/plugins/c9.ide.editors/tab.js b/plugins/c9.ide.editors/tab.js
index 5457b4c6..d1692979 100644
--- a/plugins/c9.ide.editors/tab.js
+++ b/plugins/c9.ide.editors/tab.js
@@ -291,9 +291,9 @@ define(function(require, module, exports) {
load();
});
- plugin.on("beforeUnload", function(){
+ plugin.on("beforeUnload", function(e){
if (!plugin.meta.$closing) {
- if (close())
+ if (close(e && e.animate === false))
return false;
}
});
diff --git a/plugins/c9.ide.editors/tabmanager.js b/plugins/c9.ide.editors/tabmanager.js
index da270a71..caf097d3 100644
--- a/plugins/c9.ide.editors/tabmanager.js
+++ b/plugins/c9.ide.editors/tabmanager.js
@@ -1283,7 +1283,7 @@ define(function(require, module, exports) {
// Or keep tab until the new one is loaded
else {
- previewTab.unload();
+ previewTab.unload({ animate: false });
}
}
diff --git a/plugins/c9.ide.info/info.js b/plugins/c9.ide.info/info.js
index c3ad0b6b..5df32577 100644
--- a/plugins/c9.ide.info/info.js
+++ b/plugins/c9.ide.info/info.js
@@ -74,12 +74,15 @@ define(function(require, exports, module) {
plugin.freezePublicAPI({
/**
* Returns the logged in user.
+ *
+ * @param [callback]
* @return {Object} The currently user
*/
getUser: getUser,
/**
* Return the active workspace.
+ *
* @return {Object} The currently active workspace
*/
getWorkspace: getWorkspace,
diff --git a/plugins/c9.ide.keys/commands.js b/plugins/c9.ide.keys/commands.js
index 0cab430e..5cae4001 100644
--- a/plugins/c9.ide.keys/commands.js
+++ b/plugins/c9.ide.keys/commands.js
@@ -96,9 +96,18 @@ define(function(require, exports, module) {
}
function getHotkey(command) {
+ if (!commands[command] || !commands[command].bindKey)
+ return "";
return commands[command].bindKey[platform];
}
+ function getPrettyHotkey(command) {
+ var key = getHotkey(command);
+ if (platform == "mac")
+ key = apf.hotkeys.toMacNotation(key);
+ return key;
+ }
+
var markDirty = lang.delayedCall(function(){
emit("update");
}, 500);
@@ -557,6 +566,14 @@ define(function(require, exports, module) {
*/
getHotkey: getHotkey,
+ /**
+ * returns result of getHotkey formatted for displaying in menus
+ *
+ * @param {String} name the name of the command.
+ * @return {String}
+ */
+ getPrettyHotkey: getPrettyHotkey,
+
/**
* Executes the action tied to a command. This method will call
* the `isAvailable` method for a command and will not execute if
diff --git a/plugins/c9.ide.keys/panel.js b/plugins/c9.ide.keys/panel.js
index a2d1cf0f..8f102d52 100644
--- a/plugins/c9.ide.keys/panel.js
+++ b/plugins/c9.ide.keys/panel.js
@@ -79,6 +79,9 @@ define(function(require, exports, module) {
// @TODO this is probably not sufficient
layout.on("resize", function(){ tree.resize() }, plugin);
+ var key = commands.getPrettyHotkey("commands");
+ txtFilter.setAttribute("initial-message", key);
+
tree.textInput = txtFilter.ace.textInput;
txtFilter.ace.commands.addCommands([
diff --git a/plugins/c9.ide.layout.classic/layout.js b/plugins/c9.ide.layout.classic/layout.js
index d2789759..250fbf9f 100644
--- a/plugins/c9.ide.layout.classic/layout.js
+++ b/plugins/c9.ide.layout.classic/layout.js
@@ -214,7 +214,7 @@ define(function(require, exports, module) {
}
}
- function proposeLayoutChange(kind, force, type, reset) {
+ function proposeLayoutChange(kind, force, type) {
if (!force && settings.getBool("user/general/@propose"))
return;
@@ -225,7 +225,7 @@ define(function(require, exports, module) {
ignoreTheme = true;
var theme = {"dark": "flat-dark", "light": "flat-light"}[kind];
settings.set("user/general/@skin", theme);
- updateTheme(!!reset, type);
+ updateTheme(false, type);
ignoreTheme = false;
settings.set("user/general/@propose", question.dontAsk);
},
@@ -333,15 +333,6 @@ define(function(require, exports, module) {
amlNode.$ext.className += " c9btn";
menus.addItemByPath("File/~", new apf.divider(), 1000000, plugin);
-
- if (!c9.local) {
- menus.addItemByPath("Cloud9/~", new apf.divider(), 2000000, plugin);
- menus.addItemByPath("Cloud9/Quit Cloud9", new apf.item({
- onclick: function(){
- location.href = "http://c9.io";
- }
- }), 2000100, plugin);
- }
menus.addItemByPath("View/~", new apf.divider(), 9999, plugin);
@@ -357,6 +348,14 @@ define(function(require, exports, module) {
}), 300, plugin);
}
+ function resetTheme(theme, type) {
+ ignoreTheme = true;
+ settings.set("user/general/@skin", theme);
+ updateTheme(true);
+ emit("themeDefaults", {theme: theme, type: type});
+ ignoreTheme = false;
+ }
+
function resize(){
if (c9console && tabManager) {
var tRect = tabManager.container.$ext.getBoundingClientRect();
@@ -597,7 +596,7 @@ define(function(require, exports, module) {
get theme(){
return theme;
},
-
+
/**
* Returns an AMLElement that can server as a parent.
* @param {Plugin} plugin The plugin for which to find the parent.
@@ -613,6 +612,13 @@ define(function(require, exports, module) {
*/
initMenus: initMenus,
+ /**
+ * Resets theme (without questioning user).
+ * @param {String} theme Theme to use.
+ * @param {String} type Type of editor to use.
+ */
+ resetTheme: resetTheme,
+
/**
* Sets the layout in one of two default modes:
* @param {"default"|"minimal"} type
diff --git a/plugins/c9.ide.layout.classic/less/btn-switcher.less b/plugins/c9.ide.layout.classic/less/btn-switcher.less
new file mode 100644
index 00000000..74e4a5cc
--- /dev/null
+++ b/plugins/c9.ide.layout.classic/less/btn-switcher.less
@@ -0,0 +1,52 @@
+.btn-switcher {
+ .user-select(none);
+ -webkit-display: flex;
+ display: flex;
+ -webkit-align-items: center;
+ align-items: center;
+ cursor: default;
+ font-size: @preview-chooser-font-size;
+ font-weight: @preview-chooser-font-weight;
+ color: ;
+ font-family: @preview-chooser-font-family;
+ -webkit-font-smoothing: auto;
+ -moz-osx-font-smoothing: auto;
+ background: @preview-chooser-background;
+ border-radius: 0 2px 2px 0;
+ box-shadow: @preview-chooser-box-shadow;
+ cursor: pointer;
+ border: 1px solid @textbox-border-color;
+ border-left : 0;
+ border-radius: 0 3px 3px 0;
+ position : relative;
+
+ padding: 4px 17px 4px 8px;
+ box-sizing: border-box;
+}
+.btn-switcherOver{
+ background: @preview-chooser-over-background;
+}
+.btn-switcherDown{
+ background: @preview-chooser-active-background;
+}
+.btn-switcher svg{
+ vertical-align: middle;
+ margin: -2px 4px 0 0;
+}
+
+.btn-switcher span{
+ display : block;
+ position : absolute;
+ right : 6px;
+ top : 11px;
+ width : 5px;
+ height : 5px;
+ background: url("@{image-path}/@{preview-chooser-arrow}") no-repeat;
+ opacity: 0.6;
+}
+
+.btn-switcherIcon {
+ background-repeat: no-repeat;
+ padding-left: 25px;
+ background-position: 5px 50%
+}
\ No newline at end of file
diff --git a/plugins/c9.ide.layout.classic/less/codebox.less b/plugins/c9.ide.layout.classic/less/codebox.less
index 129aeee6..357253c1 100644
--- a/plugins/c9.ide.layout.classic/less/codebox.less
+++ b/plugins/c9.ide.layout.classic/less/codebox.less
@@ -18,6 +18,9 @@
color : @textbox-disabled-color;
background: @textbox-disabled-background;
}
+.has_apf .searchTxt.tb_console.ace_searchboxDisabled .sbtb_middle .input {
+ color : @textbox-disabled-color;
+}
.ace_one-line .ace_scroller.ace_scroll-left {
box-shadow: none;
}
@@ -40,10 +43,6 @@
outline : none;
text-overflow : ellipsis;
}
-.tb_consoleFocus .sbtb_middle,
-.tb_consoleOver .sbtb_middle,
-.tb_console .sbtb_middle:hover {
-}
.topborder .sbtb_middle{
border-width : 1px 0 0 0;
@@ -63,15 +62,13 @@
padding : 0;
}
-.tb_console.tb_textboxInitial .sbtb_middle {
- padding-right : 0 !important;
+
+.ace_editor .tb_textboxInitialMsg {
+ text-indent: 5px;
+ text-shadow: none;
}
-.tb_console.tb_textboxInitial .input {
- font-size : 10px;
-}
-
-.tb_console.tb_textboxInitial .ace_cursor{
+.ace_initialMsg:not(.ace_focus) .ace_cursor {
display : none;
}
diff --git a/plugins/c9.ide.layout.classic/less/main.less b/plugins/c9.ide.layout.classic/less/main.less
index 7c158e95..a2a4dd5d 100644
--- a/plugins/c9.ide.layout.classic/less/main.less
+++ b/plugins/c9.ide.layout.classic/less/main.less
@@ -47,6 +47,7 @@ BODY.noInput *{
@import "less/button.less";
@import "less/btn_console.less";
@import "less/btn_console_open.less";
+@import "less/btn-switcher.less";
@import "less/c9-divider-double.less";
@import "less/c9-divider-hor.less";
@import "less/c9-divider.less";
diff --git a/plugins/c9.ide.layout.classic/less/searchbox.less b/plugins/c9.ide.layout.classic/less/searchbox.less
index 23147036..00f7ef2c 100644
--- a/plugins/c9.ide.layout.classic/less/searchbox.less
+++ b/plugins/c9.ide.layout.classic/less/searchbox.less
@@ -36,7 +36,7 @@
height: auto;
position: relative;
}
-.searchTxt.tb_textboxInitial .sbtb_middle .input {
+.searchTxt.tb_textboxInitial .sbtb_middle .input, .tb_textboxInitialMsg {
color: @textbox-initial-color !important;
text-shadow: @textbox-initial-text-shadow;
font-family: @find-textbox-font-family;
diff --git a/plugins/c9.ide.layout.classic/skins.xml b/plugins/c9.ide.layout.classic/skins.xml
index 4fe050bc..6e78f388 100644
--- a/plugins/c9.ide.layout.classic/skins.xml
+++ b/plugins/c9.ide.layout.classic/skins.xml
@@ -859,4 +859,16 @@
+
+
+
+
+ -
+
+
+
+
\ No newline at end of file
diff --git a/plugins/c9.ide.layout.classic/themes/default-flat-dark.less b/plugins/c9.ide.layout.classic/themes/default-flat-dark.less
index 9ba1ada6..98a1e73b 100644
--- a/plugins/c9.ide.layout.classic/themes/default-flat-dark.less
+++ b/plugins/c9.ide.layout.classic/themes/default-flat-dark.less
@@ -1711,7 +1711,7 @@
@form-bar-border-bottom: 1px solid black;
@form-bar-box-shadow: 0 1px @border-highlight;
-@panel-settings-changes-top: 46px;
+@panel-settings-changes-top: 53px;
/*******/
diff --git a/plugins/c9.ide.layout.classic/themes/default-flat-light.less b/plugins/c9.ide.layout.classic/themes/default-flat-light.less
index bc630707..74aa8f16 100644
--- a/plugins/c9.ide.layout.classic/themes/default-flat-light.less
+++ b/plugins/c9.ide.layout.classic/themes/default-flat-light.less
@@ -1066,8 +1066,8 @@
@textbox-border-color: darken(#dedede, @darken-chrome);
@textbox-initial-color: darken(#A5A5A5, @darken-chrome);
@textbox-initial-text-shadow: 0 1px 0 darken(#FFFFFF, @darken-chrome);
-@textbox-disabled-color: gray;
-@textbox-disabled-background: darken(rgb(216, 216, 216), @darken-chrome);
+@textbox-disabled-color: #C5C5C5;
+@textbox-disabled-background: #F1F1F1;
// Textbox - Simple
@tbsimple-border: 1px solid #DEDEDE;
@@ -1706,9 +1706,9 @@
@diff-toolbar-buttons-background: #F9F9F9;
@diff-toolbar-buttons-border: 1px solid @border-highlight-dark;
-@form-bar-padding: 10px 50px 10px 10px;
+@form-bar-padding: 10px 10px 0 10px;
@form-bar-background: @menu-button-active-background;
-@form-bar-border-bottom: 1px solid black;
+@form-bar-border-bottom: 1px solid #DEDEDE;
@form-bar-box-shadow: 0 1px @border-highlight;
-@panel-settings-changes-top: 46px;
\ No newline at end of file
+@panel-settings-changes-top: 53px;
\ No newline at end of file
diff --git a/plugins/c9.ide.layout.classic/themes/flat-light.less b/plugins/c9.ide.layout.classic/themes/flat-light.less
index 351b97ee..82317527 100644
--- a/plugins/c9.ide.layout.classic/themes/flat-light.less
+++ b/plugins/c9.ide.layout.classic/themes/flat-light.less
@@ -470,6 +470,9 @@ body .runner-form-header{
.cbblack.cbcontainerDisabled.cbcontainerChecked .checkbox{
background-position: 0 -142px;
}
+ .cbblack.cbcontainerDisabled.cbcontainerDisabled .checkbox{
+ background-position: 0 0;
+ }
.session_btn .tab_middle:before {
background-position : 0 -126px;
-webkit-mask-position : 0 -95px;
diff --git a/plugins/c9.ide.login/login.js b/plugins/c9.ide.login/login.js
index eb9ad2df..fc8e68f0 100644
--- a/plugins/c9.ide.login/login.js
+++ b/plugins/c9.ide.login/login.js
@@ -40,6 +40,15 @@ define(function(require, exports, module) {
});
auth.on("relogin", onReLogin);
+
+ if (!c9.local) {
+ menus.addItemByPath("Cloud9/~", new apf.divider(), 2000000, plugin);
+ menus.addItemByPath("Cloud9/Quit Cloud9", new apf.item({
+ onclick: function(){
+ signout();
+ }
+ }), 2000100, plugin);
+ }
}
/***** Methods *****/
diff --git a/plugins/c9.ide.panels/panel.js b/plugins/c9.ide.panels/panel.js
index ee7be651..f1245f4b 100644
--- a/plugins/c9.ide.panels/panel.js
+++ b/plugins/c9.ide.panels/panel.js
@@ -147,6 +147,14 @@ define(function(require, module, exports) {
mnuItem.setAttribute("hotkey",
"{commands.commandManager." + options.name + "}");
+
+
+ if (button && button.setAttribute) {
+ var key = commands.getPrettyHotkey(options.name);
+ button.setAttribute("tooltip", options.name
+ + (key ? " (" + key + ")" : ""));
+ }
+
return command;
}
@@ -382,6 +390,11 @@ define(function(require, module, exports) {
*/
get button(){ return button; },
+ /**
+ *
+ */
+ get active(){ return panels.isActive(plugin.name); },
+
_events: [
/**
* Fires when the panel is drawn.
diff --git a/plugins/c9.ide.plugins/test.html b/plugins/c9.ide.plugins/test.html
index 309727c7..328b7481 100644
--- a/plugins/c9.ide.plugins/test.html
+++ b/plugins/c9.ide.plugins/test.html
@@ -38,8 +38,8 @@
-
-
+
+
-
\ No newline at end of file
+