kopia lustrzana https://github.com/c9/core
commit
4825c60e97
|
@ -7,7 +7,7 @@ return function(vfs, base, baseProc, cli) {
|
|||
|
||||
var resolvePath = function(path, basePath) {
|
||||
if (path.charAt(0) == "~") {
|
||||
if (cli && typeof process != "undefined")
|
||||
if (cli && typeof process != "undefined" && process.env)
|
||||
return process.env.HOME + "/" + path.substr(1);
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ define(function(require, exports, module) {
|
|||
}
|
||||
|
||||
function normalize(str) {
|
||||
return str && str.replace(/(^|-| )(\w)/g, function(_, a, b) {
|
||||
return str && str.replace(/(^|-| |\|)(\w)/g, function(_, a, b) {
|
||||
return a + b.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,24 +57,14 @@ exports.ideKeymap = [
|
|||
bindKey: { mac: "cmd-t|cmd-p", win: "ctrl-p" },
|
||||
name: "navigate"
|
||||
}, {
|
||||
bindKey: { mac: "cmd-r", win: "ctrl-r" },
|
||||
bindKey: { mac: "cmd-r|cmd-shift-r", win: "ctrl-r|ctrl-shift-r" },
|
||||
name: "outline",
|
||||
args: { overlay: "goto", text: "@" }
|
||||
}, {
|
||||
bindKey: { mac: "cmd-shift-r", win: "ctrl-shift-r" },
|
||||
// todo: this should be project outline
|
||||
name: "outline"
|
||||
}, {
|
||||
bindKey: { mac: "ctrl-g", win: "ctrl-g" },
|
||||
name: "gotoline",
|
||||
args: { overlay: "goto", text: ":" }
|
||||
},
|
||||
// todo what is this?
|
||||
// {
|
||||
// bindKey: {win: "ctrl-;"},
|
||||
// name: "show_overlay",
|
||||
// args: {overlay: "goto", text: "#"}
|
||||
// },
|
||||
},
|
||||
{
|
||||
bindKey: { mac: "cmd-shift-p", win: "ctrl-shift-p" },
|
||||
name: "commands"
|
||||
|
@ -358,6 +348,9 @@ exports.ideKeymap = [
|
|||
}, {
|
||||
bindKey: { mac: "cmd-shift-f", win: "ctrl-shift-f" },
|
||||
name: "searchinfiles",
|
||||
}, {
|
||||
bindKey: { mac: "", win: "" },
|
||||
name: "restartc9",
|
||||
},
|
||||
// {
|
||||
// bindKey: {mac: "f4", win: "f4"},
|
||||
|
|
|
@ -21,6 +21,8 @@ define(function(require, exports, module) {
|
|||
var Evaluator = imports.Evaluator;
|
||||
var ui = imports.ui;
|
||||
|
||||
var escapeHTML = require("ace/lib/lang").escapeHTML;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var plugin = new Evaluator("Ajax.org", main.consumes, {
|
||||
|
@ -108,7 +110,7 @@ define(function(require, exports, module) {
|
|||
|
||||
function insert(div, markup, name) {
|
||||
if (name !== undefined)
|
||||
insert(div, "<span class='property'>" + name + ": </span>");
|
||||
insert(div, "<span class='property'>" + escapeHTML(name) + ": </span>");
|
||||
|
||||
markup = markup.replace(/([a-z]\w{1,4}:\/\/[\w:_\-\?&\/\.\#]*)/gi, "<a>$1</a>");
|
||||
div.insertAdjacentHTML("beforeend", markup);
|
||||
|
@ -279,7 +281,7 @@ define(function(require, exports, module) {
|
|||
var count = Math.min(Math.min(props.length, 5),
|
||||
Math.max(0, 100 - object.length));
|
||||
for (var i = 0; i < count; i++) {
|
||||
insert(preview, (found || i !== 0 ? ", " : "") + props[i] + ": ");
|
||||
insert(preview, (found || i !== 0 ? ", " : "") + escapeHTML(props[i]) + ": ");
|
||||
renderType(object[props[i]], preview, false, 2);
|
||||
}
|
||||
if (props.length > count)
|
||||
|
|
|
@ -113,7 +113,7 @@ define(function(require, exports, module) {
|
|||
|
||||
function insert(div, markup, name) {
|
||||
if (name !== undefined)
|
||||
insert(div, "<span class='property'>" + name + ": </span>");
|
||||
insert(div, "<span class='property'>" + escapeHTML(name) + ": </span>");
|
||||
|
||||
markup = markup.replace(/([a-z]\w{1,4}:\/\/[\w:_\-\?&\/\.\#]*)/gi, "<a>$1</a>");
|
||||
div.insertAdjacentHTML("beforeend", markup);
|
||||
|
@ -319,7 +319,7 @@ define(function(require, exports, module) {
|
|||
var count = Math.min(Math.min(props.length, 5),
|
||||
Math.max(0, 100 - object.length));
|
||||
for (var i = 0; i < count; i++) {
|
||||
insert(preview, (i !== 0 ? ", " : "") + props[i] + ": ");
|
||||
insert(preview, (i !== 0 ? ", " : "") + escapeHTML(props[i]) + ": ");
|
||||
renderType(props[i], preview, false, 2);
|
||||
}
|
||||
if (props.length > count)
|
||||
|
|
|
@ -653,7 +653,11 @@ define(function(require, exports, module) {
|
|||
/**
|
||||
*
|
||||
*/
|
||||
addOutlinePlugin: addOutlinePlugin
|
||||
addOutlinePlugin: addOutlinePlugin,
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
get tree() { return tree },
|
||||
});
|
||||
|
||||
register(null, {
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*global describe it before after bar*/
|
||||
|
||||
"use client";
|
||||
|
||||
require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) {
|
||||
var expect = chai.expect;
|
||||
|
||||
expect.setupArchitectTest([
|
||||
{
|
||||
packagePath: "plugins/c9.core/c9",
|
||||
workspaceId: "ubuntu/ip-10-35-77-180",
|
||||
startdate: new Date(),
|
||||
debug: true,
|
||||
hosted: true,
|
||||
local: false,
|
||||
},
|
||||
|
||||
"plugins/c9.core/ext",
|
||||
"plugins/c9.core/http-xhr",
|
||||
"plugins/c9.core/util",
|
||||
"plugins/c9.ide.ui/lib_apf",
|
||||
"plugins/c9.ide.ui/menus",
|
||||
{
|
||||
packagePath: "plugins/c9.core/settings",
|
||||
settings: "default",
|
||||
testing: true
|
||||
},
|
||||
"plugins/c9.core/api.js",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.ui/ui",
|
||||
staticPrefix: "plugins/c9.ide.ui"
|
||||
},
|
||||
"plugins/c9.ide.editors/document",
|
||||
"plugins/c9.ide.editors/undomanager",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.editors/editors",
|
||||
defaultEditor: "ace"
|
||||
},
|
||||
"plugins/c9.ide.editors/editor",
|
||||
"plugins/c9.ide.editors/tabmanager",
|
||||
"plugins/c9.ide.ui/focus",
|
||||
"plugins/c9.ide.editors/pane",
|
||||
"plugins/c9.ide.editors/tab",
|
||||
"plugins/c9.ide.keys/commands",
|
||||
"plugins/c9.fs/proc",
|
||||
"plugins/c9.vfs.client/vfs_client",
|
||||
"plugins/c9.vfs.client/endpoint",
|
||||
"plugins/c9.ide.auth/auth",
|
||||
"plugins/c9.fs/fs",
|
||||
|
||||
"plugins/c9.ide.dialog/dialog",
|
||||
"plugins/c9.ide.dialog.common/alert",
|
||||
"plugins/c9.ide.dialog.common/alert_internal",
|
||||
// Previewer
|
||||
{
|
||||
packagePath: "plugins/c9.ide.preview/preview",
|
||||
staticPrefix: "/static" + "/plugins/c9.ide.preview",
|
||||
defaultPreviewer: "preview.browser",
|
||||
previewUrl: "/preview",
|
||||
},
|
||||
"plugins/c9.ide.preview/previewer",
|
||||
"plugins/c9.ide.preview/previewers/raw",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.preview.browser/browser",
|
||||
staticPrefix: "/static" + "/plugins/c9.ide.preview.browser"
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.preview.markdown/markdown",
|
||||
staticPrefix: "/static",
|
||||
htmlPath: "/plugins/c9.ide.preview.markdown/markdown.html",
|
||||
},
|
||||
"plugins/c9.ide.remote/manager",
|
||||
"plugins/c9.ide.remote/documents/htmldocument",
|
||||
"plugins/c9.ide.remote/documents/cssdocument",
|
||||
"plugins/c9.ide.remote/documents/jsdocument",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.remote/transports/postmessage",
|
||||
// previewBaseUrl: options.previewBaseUrl
|
||||
},
|
||||
|
||||
{
|
||||
consumes: ["tabManager", "ace", "commands", "fs", "preview"],
|
||||
provides: [],
|
||||
setup: main
|
||||
}
|
||||
], architect);
|
||||
|
||||
function main(options, imports, register) {
|
||||
var fs = imports.fs;
|
||||
var ace = imports.ace;
|
||||
var tabs = imports.tabManager;
|
||||
var preview = imports.preview;
|
||||
var commands = imports.commands;
|
||||
|
||||
describe('ace', function() {
|
||||
before(function(done) {
|
||||
bar.$ext.style.background = "rgba(220, 220, 220, 0.93)";
|
||||
bar.$ext.style.position = "fixed";
|
||||
bar.$ext.style.left = "20px";
|
||||
bar.$ext.style.width = "1000px";
|
||||
bar.$ext.style.bottom = "20px";
|
||||
bar.$ext.style.height = "33%";
|
||||
|
||||
document.body.style.marginBottom = "33%";
|
||||
|
||||
tabs.once("ready", function() {
|
||||
tabs.getPanes()[0].focus();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("open", function() {
|
||||
this.timeout(10000);
|
||||
|
||||
it('should open html preview', function(done) {
|
||||
fs.writeFile("/dir/preview.md", [
|
||||
"ok",
|
||||
"<img onerror='top.xss=1' src>"
|
||||
].join("\n"), function(err) {
|
||||
expect(err).to.not.ok;
|
||||
preview.openPreview("/dir/preview.md", null, true, function(err, tab) {
|
||||
expect(err).to.not.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (!onload.remain) {
|
||||
after(function(done) {
|
||||
tabs.unload();
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
register();
|
||||
}
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
/*global describe it before after bar =*/
|
||||
/*global describe it before after bar*/
|
||||
|
||||
"use client";
|
||||
|
||||
|
@ -69,9 +69,6 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"], function (arc
|
|||
|
||||
describe('terminal', function() {
|
||||
before(function(done) {
|
||||
apf.config.setProperty("allow-select", false);
|
||||
apf.config.setProperty("allow-blur", false);
|
||||
|
||||
bar.$ext.style.background = "rgba(220, 220, 220, 0.93)";
|
||||
bar.$ext.style.position = "fixed";
|
||||
bar.$ext.style.left = "20px";
|
||||
|
@ -153,16 +150,24 @@ require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"], function (arc
|
|||
|
||||
it('should handle multiple terminals in the same pane', function(done) {
|
||||
tabs.openEditor("terminal", function(err, tab) {
|
||||
expect(err).to.not.ok;
|
||||
expect(tabs.getTabs()).length(2);
|
||||
|
||||
tab.activate();
|
||||
|
||||
var doc = tab.document;
|
||||
doc.on("setTitle", function c1() {
|
||||
// expect(doc.title).match(new RegExp("^bash - "));
|
||||
|
||||
doc.off("setTitle", c1);
|
||||
done();
|
||||
doc.once("setTitle", function() {
|
||||
var terminal = tab.editor.ace.session.term;
|
||||
terminal.once("afterWrite", function() {
|
||||
expect(window.xss).to.not.ok;
|
||||
terminal.write("echo \"<img onerror='window.xss=1' src=':error'>\"");
|
||||
tab.editor.ace.resize(true);
|
||||
expect(tab.editor.ace.container.textContent.indexOf("<img")).to.not.equal(-1);
|
||||
setTimeout(function() {
|
||||
expect(window.xss).to.not.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
/*global localStorage*/
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
main.consumes = ["Plugin"];
|
||||
main.provides = ["vfs", "vfs.ping", "vfs.log", "vfs.endpoint"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports.Plugin;
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
|
||||
var id;
|
||||
var vfsBaseUrl;
|
||||
var serviceUrl;
|
||||
|
||||
var fsData = {};
|
||||
|
||||
var Stream = require("stream").Stream;
|
||||
var noop = function() { console.error("not implemented"); };
|
||||
var silent = function() {};
|
||||
var connection = {};
|
||||
|
||||
function load() {
|
||||
// initialize mock fsData
|
||||
findNode("/README.md", true, [
|
||||
"# Welcome to Cloud9 offline demo!",
|
||||
"",
|
||||
"This is a demo of Cloud9 ui, with a mock vfs server working with localStorage",
|
||||
"Some features that need a real server have been disabled",
|
||||
"So be sure to try the real thing at https://c9.io!"
|
||||
].join("\n"));
|
||||
findNode("~", true);
|
||||
if (options.storage != false) {
|
||||
// Try loading data from localStorage
|
||||
try {
|
||||
fsData = JSON.parse(localStorage.fsData);
|
||||
} catch (e) {}
|
||||
window.addEventListener("beforeunload", function(e) {
|
||||
localStorage.fsData = JSON.stringify(fsData);
|
||||
});
|
||||
}
|
||||
}
|
||||
function unload() {
|
||||
fsData = {};
|
||||
}
|
||||
|
||||
function findNode(path, create, val) {
|
||||
if (!path) path = "/";
|
||||
var parts = path.split("/");
|
||||
if (!parts[parts.length - 1])
|
||||
parts.pop();
|
||||
var data = fsData;
|
||||
var prev = null;
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
prev = data;
|
||||
data = data["!" + parts[i]];
|
||||
if (data == null) {
|
||||
if (create && typeof prev != "string")
|
||||
data = prev["!" + parts[i]] = {};
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (val)
|
||||
data = prev["!" + parts[parts.length - 1]] = val;
|
||||
return data;
|
||||
}
|
||||
|
||||
function ENOENT() {
|
||||
var err = new Error("ENOENT");
|
||||
err.code = "ENOENT";
|
||||
return err;
|
||||
}
|
||||
|
||||
function sendStream(data, callback) {
|
||||
var stream = new Stream();
|
||||
stream.readable = true;
|
||||
callback(null, { stream: stream });
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(function(x) {
|
||||
stream.emit("data", x);
|
||||
});
|
||||
} else {
|
||||
stream.emit("data", data);
|
||||
}
|
||||
stream.emit("end");
|
||||
}
|
||||
|
||||
plugin.on("load", load);
|
||||
plugin.on("unload", unload);
|
||||
|
||||
plugin.freezePublicAPI({
|
||||
on: function() {},
|
||||
once: function() {},
|
||||
|
||||
get connection() { return connection; },
|
||||
get connecting() { return false; },
|
||||
get connected() { return true },
|
||||
|
||||
get previewUrl() { throw new Error("gone"); },
|
||||
get serviceUrl() { return serviceUrl; },
|
||||
get id() { return id; },
|
||||
get baseUrl() { return vfsBaseUrl; },
|
||||
get region() { return ""; },
|
||||
|
||||
rest: noop,
|
||||
download: noop,
|
||||
url: noop,
|
||||
reconnect: noop,
|
||||
|
||||
vfsUrl: noop,
|
||||
|
||||
// File management
|
||||
resolve: noop,
|
||||
stat: function(path, options, callback) {
|
||||
var data = findNode(path);
|
||||
var name = path.split("/").pop();
|
||||
setTimeout(function() {
|
||||
if (data == null)
|
||||
return callback(ENOENT());
|
||||
var isFile = typeof data == "string";
|
||||
var stat = {
|
||||
name: name.substr(1),
|
||||
size: isFile ? data.length : 1,
|
||||
mtime: 0,
|
||||
ctime: 0,
|
||||
mime: isFile ? "" : "folder"
|
||||
};
|
||||
callback(null, stat);
|
||||
}, 20);
|
||||
},
|
||||
readfile: function(path, options, callback) {
|
||||
var data = findNode(path);
|
||||
setTimeout(function() {
|
||||
if (typeof data != "string")
|
||||
return callback(ENOENT());
|
||||
sendStream(data, callback);
|
||||
}, 20);
|
||||
},
|
||||
readdir: function(path, options, callback) {
|
||||
var data = findNode(path);
|
||||
setTimeout(function() {
|
||||
if (!data || typeof data == "string")
|
||||
return callback(ENOENT());
|
||||
var stats = Object.keys(data).map(function(n) {
|
||||
var isFile = typeof data[n] == "string";
|
||||
return {
|
||||
name: n.substr(1),
|
||||
size: isFile ? data[n].length : 1,
|
||||
mtime: 0,
|
||||
ctime: 0,
|
||||
mime: isFile ? "" : "folder"
|
||||
};
|
||||
});
|
||||
sendStream(stats, callback);
|
||||
});
|
||||
},
|
||||
mkfile: function(path, options, callback) {
|
||||
var parts = path.split("/");
|
||||
var name = "!" + parts.pop();
|
||||
var parent = findNode(parts.join("/"), true);
|
||||
var val = "";
|
||||
options.stream.on("data", function(e) {
|
||||
if (e) val += e;
|
||||
});
|
||||
options.stream.on("end", function(e) {
|
||||
if (e) val += e;
|
||||
setTimeout(function() {
|
||||
if (!parent || typeof parent[name] == "object")
|
||||
return callback(ENOENT());
|
||||
parent[name] = val;
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
},
|
||||
mkdir: function(path, options, callback) {
|
||||
var data = findNode(path, true);
|
||||
setTimeout(function() {
|
||||
if (!data)
|
||||
return callback(ENOENT());
|
||||
callback();
|
||||
});
|
||||
},
|
||||
mkdirP: function(path, options, callback) {
|
||||
var data = findNode(path, true);
|
||||
setTimeout(function() {
|
||||
if (!data)
|
||||
return callback(ENOENT());
|
||||
callback();
|
||||
});
|
||||
},
|
||||
appendfile: noop,
|
||||
rmfile: function(path, options, callback) {
|
||||
var parts = path.split("/");
|
||||
var name = "!" + parts.pop();
|
||||
setTimeout(function() {
|
||||
var parent = findNode(parts.join("/"));
|
||||
if (!parent || !parent[name])
|
||||
return callback(ENOENT());
|
||||
if (typeof parent[name] != "string")
|
||||
return callback(new Error("EISDIR"));
|
||||
delete parent[name];
|
||||
callback();
|
||||
});
|
||||
},
|
||||
rmdir: function(path, options, callback) {
|
||||
var parts = path.split("/");
|
||||
var name = "!" + parts.pop();
|
||||
setTimeout(function() {
|
||||
var parent = findNode(parts.join("/"));
|
||||
if (!parent || !parent[name])
|
||||
return callback(ENOENT());
|
||||
if (typeof parent[name] == "string")
|
||||
return callback(new Error("EISFILE"));
|
||||
delete parent[name];
|
||||
callback();
|
||||
});
|
||||
},
|
||||
rename: function(to, options, callback) {
|
||||
setTimeout(function() {
|
||||
var from = options.from;
|
||||
var overwrite = options.overwrite;
|
||||
|
||||
var parts = to.split("/");
|
||||
var toName = "!" + parts.pop();
|
||||
var toParent = findNode(parts.join("/"));
|
||||
|
||||
parts = from.split("/");
|
||||
var fromName = "!" + parts.pop();
|
||||
var fromParent = findNode(parts.join("/"));
|
||||
if (toParent[toName] != null && !overwrite)
|
||||
return callback(ENOENT());
|
||||
|
||||
toParent[toName] = fromParent[fromName];
|
||||
delete fromParent[fromName];
|
||||
callback(null);
|
||||
});
|
||||
},
|
||||
copy: function(from, options, callback) {
|
||||
setTimeout(function() {
|
||||
var to = options.to;
|
||||
var overwrite = options.overwrite;
|
||||
|
||||
var toParts = to.split("/");
|
||||
var toName = "!" + toParts.pop();
|
||||
var toParent = findNode(toParts.join("/"));
|
||||
|
||||
var parts = from.split("/");
|
||||
var fromName = "!" + parts.pop();
|
||||
var fromParent = findNode(parts.join("/"));
|
||||
var counter = 0;
|
||||
var name = toName;
|
||||
while (toParent[toName] != null && !options.overwrite)
|
||||
toName = name + "." + (++counter);
|
||||
|
||||
toParent[toName] = fromParent[fromName];
|
||||
toParts.push(toName.substr(1));
|
||||
callback(null, {to: toParts.join("/")});
|
||||
});
|
||||
},
|
||||
chmod: noop,
|
||||
symlink: noop,
|
||||
|
||||
// Save and retrieve Metadata
|
||||
metadata: function(path, value, sync, callback) {
|
||||
var parts = ("/.c9/metadata" + path).split("/");
|
||||
var name = "!" + parts.pop();
|
||||
var parent = findNode(parts.join("/"), true);
|
||||
if (sync) {
|
||||
parent[name] = JSON.stringify(value);
|
||||
return callback();
|
||||
}
|
||||
setTimeout(function() {
|
||||
parent[name] = JSON.stringify(value);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
readFileWithMetadata: function(path, options, callback) {
|
||||
var data = findNode(path);
|
||||
var metadata = findNode("/.c9/metadata" + path);
|
||||
setTimeout(function() {
|
||||
if (typeof data != "string")
|
||||
return callback(ENOENT());
|
||||
// TODO metadata
|
||||
callback(null, data, metadata);
|
||||
});
|
||||
return { abort: function() {} };
|
||||
},
|
||||
|
||||
// Wrapper around fs.watch or fs.watchFile
|
||||
watch: silent,
|
||||
|
||||
// Network connection
|
||||
connect: noop,
|
||||
|
||||
// Process Management
|
||||
spawn: silent,
|
||||
pty: silent,
|
||||
tmux: silent,
|
||||
execFile: silent,
|
||||
killtree: silent,
|
||||
|
||||
// Extending the API
|
||||
use: silent,
|
||||
extend: silent,
|
||||
unextend: silent,
|
||||
|
||||
isIdle: function() { return true },
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"vfs": plugin,
|
||||
"vfs.ping": {},
|
||||
"vfs.log": {
|
||||
log: function() {}
|
||||
},
|
||||
"vfs.endpoint": {
|
||||
clearCache: function() {}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,169 @@
|
|||
/*global describe it before after bar*/
|
||||
|
||||
"use client";
|
||||
|
||||
require(["lib/architect/architect", "lib/chai/chai", "configs/ide/default"], function(architect, chai) {
|
||||
var expect = chai.expect;
|
||||
|
||||
function offlineConfig() {
|
||||
var plugins = require("configs/ide/default")({
|
||||
staticPrefix: "/static",
|
||||
workspaceDir: "/",
|
||||
workspaceId: "/",
|
||||
workspaceName: "/",
|
||||
home: "/",
|
||||
platform: "linux",
|
||||
installPath: "/",
|
||||
manifest: {},
|
||||
project: {},
|
||||
user: {},
|
||||
standalone: true,
|
||||
previewUrl: "",
|
||||
dashboardUrl: "",
|
||||
themePrefix: "/static/standalone/skin/default",
|
||||
});
|
||||
var excludes = [
|
||||
"plugins/c9.ide.immediate/evaluators/debugnode",
|
||||
"plugins/c9.ide.test.mocha/mocha",
|
||||
"plugins/c9.ide.find/find.nak",
|
||||
"plugins/c9.ide.terminal/terminal",
|
||||
"plugins/c9.ide.test/all",
|
||||
"plugins/c9.ide.find/find",
|
||||
"plugins/c9.ide.terminal/link_handler",
|
||||
"plugins/c9.ide.test/coverage",
|
||||
"plugins/c9.ide.test/coverage",
|
||||
"plugins/c9.ide.test/results",
|
||||
"plugins/c9.ide.test/testrunner",
|
||||
|
||||
"plugins/c9.ide.find.infiles/findinfiles",
|
||||
"plugins/c9.ide.language.codeintel/codeintel",
|
||||
"plugins/c9.ide.language.go/go",
|
||||
"plugins/c9.ide.language.python/python",
|
||||
"plugins/c9.ide.test/coverageview",
|
||||
"plugins/c9.cli.bridge/bridge_commands",
|
||||
"plugins/c9.ide.ace.keymaps/cli",
|
||||
"plugins/c9.ide.configuration/configure",
|
||||
"plugins/c9.ide.plugins/manager",
|
||||
"plugins/c9.ide.ace.keymaps/keymaps",
|
||||
"plugins/c9.ide.ace/themes",
|
||||
];
|
||||
plugins = plugins.filter(function(p) {
|
||||
var packagePath = typeof p == "string" ? p : p.packagePath;
|
||||
if (/\/c9.ide.run/.test(packagePath)) return false;
|
||||
if (/\/c9.ide.collab/.test(packagePath)) return false;
|
||||
if (/\/c9.ide.installer/.test(packagePath)) return false;
|
||||
if (/\/c9.vfs.client/.test(packagePath)) return false;
|
||||
if (/\/c9.ide.plugins/.test(packagePath)) return false;
|
||||
if (/\/c9.ide.scm/.test(packagePath)) return false;
|
||||
if (/\/c9.ide.welcome/.test(packagePath)) return false;
|
||||
if (excludes.indexOf(packagePath) != -1) return false;
|
||||
|
||||
if (packagePath == "plugins/c9.fs/fs")
|
||||
p.cli = true;
|
||||
if (packagePath == "plugins/c9.core/settings")
|
||||
p.testing = 1;
|
||||
|
||||
if (packagePath == "plugins/c9.ide.console/console")
|
||||
p.defaultState = { type: "pane", nodes: [] }; // prevent console from opening terminal
|
||||
|
||||
return true;
|
||||
});
|
||||
plugins.push({
|
||||
packagePath: "plugins/c9.vfs.client/vfs_client_mock",
|
||||
storage: false
|
||||
});
|
||||
plugins.push({
|
||||
provides: ["find", "installer"],
|
||||
consumes: [],
|
||||
setup: function(options, imports, register) {
|
||||
function noop() {}
|
||||
register(null, {
|
||||
find: { on: noop, once: noop, getFileList: noop },
|
||||
installer: {},
|
||||
});
|
||||
}
|
||||
});
|
||||
window.plugins = plugins;
|
||||
return plugins;
|
||||
}
|
||||
|
||||
expect.setupArchitectTest(offlineConfig().concat([
|
||||
{
|
||||
consumes: ["tabManager", "ace", "commands", "outline", "language", "ui", "menus"],
|
||||
provides: [],
|
||||
setup: main
|
||||
}
|
||||
]), architect);
|
||||
|
||||
function main(options, imports, register) {
|
||||
var tabs = imports.tabManager;
|
||||
var commands = imports.commands;
|
||||
var outline = imports.outline;
|
||||
var language = imports.language;
|
||||
var menus = imports.menus;
|
||||
var ui = imports.ui;
|
||||
|
||||
var img = "<img onerror='window.xss=1' src=':error'>";
|
||||
|
||||
describe("xss", function() {
|
||||
this.timeout(10000);
|
||||
|
||||
it("should open a markdown file with outline", function(done) {
|
||||
tabs.openFile("/README.md", function(err, tab) {
|
||||
expect(err).to.not.ok;
|
||||
expect(tabs.getTabs()).length(1);
|
||||
expect(window.xss).to.not.ok;
|
||||
|
||||
tab.editor.ace.setValue("# " + img);
|
||||
tab.editor.ace.resize(true);
|
||||
expect(tab.editor.ace.renderer.scroller.textContent).to.equal("# " + img);
|
||||
language.getWorker(function(err, worker) {
|
||||
expect(err).to.not.ok;
|
||||
worker.once("outline", function() {
|
||||
setTimeout(function() {
|
||||
outline.tree.resize(true);
|
||||
expect(outline.tree.container.textContent.trim()).to.equal(img);
|
||||
expect(window.xss).to.not.ok;
|
||||
setTimeout(function() {
|
||||
expect(window.xss).to.not.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
outline.show();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should open immediate window", function(done) {
|
||||
tabs.open({ focus: true, editorType: "immediate" }, function(err, tab) {
|
||||
expect(err).to.not.ok;
|
||||
expect(window.xss).to.not.ok;
|
||||
tab.editor.ace.insert("top.a = {" + JSON.stringify(img) + ":" + JSON.stringify(img) + "};");
|
||||
tab.editor.ace.repl.eval(true);
|
||||
setTimeout(function() {
|
||||
expect(window.xss).to.not.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should add menu item", function(done) {
|
||||
commands.addCommand({
|
||||
name: img,
|
||||
bindKey: img
|
||||
}, menus);
|
||||
menus.setRootMenu(img, 16000, menus);
|
||||
menus.addItemByPath(img + "/" + img, new ui.item({
|
||||
command: img
|
||||
}), 16, menus);
|
||||
setTimeout(function() {
|
||||
expect(window.xss).to.not.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
register();
|
||||
}
|
||||
});
|
|
@ -47,303 +47,6 @@
|
|||
<!--dev}-->
|
||||
|
||||
<script>
|
||||
var vfsPlugin = {
|
||||
consumes: [],
|
||||
provides: ["vfs", "vfs.ping", "vfs.log", "vfs.endpoint"],
|
||||
setup: function(options, imports, register) {
|
||||
var Stream = require("stream").Stream;
|
||||
var noop = function() { debugger; };
|
||||
var silent = function() {};
|
||||
var connection = {};
|
||||
// initialize mock fsData
|
||||
var fsData = {};
|
||||
findNode("/README.md", true, [
|
||||
"# Welcome to Cloud9 offline demo!",
|
||||
"",
|
||||
"This is a demo of Cloud9 ui, with a mock vfs server working with localStorage",
|
||||
"Some features that need a real server have been disabled",
|
||||
"So be sure to try the real thing at https://c9.io!"
|
||||
].join("\n"));
|
||||
findNode("~", true);
|
||||
// Try loading data from localStorage
|
||||
try {
|
||||
fsData = JSON.parse(localStorage.fsData);
|
||||
} catch (e) {}
|
||||
window.addEventListener("beforeunload", function(e) {
|
||||
localStorage.fsData = JSON.stringify(fsData);
|
||||
});
|
||||
|
||||
var vfsApi = {
|
||||
on: function() {},
|
||||
once: function() {},
|
||||
connected: true,
|
||||
|
||||
get connection() { return connection; },
|
||||
get connecting() { return false; },
|
||||
get connected() { return true },
|
||||
|
||||
get previewUrl() { throw new Error("gone"); },
|
||||
get serviceUrl() { return serviceUrl; },
|
||||
get id() { return id; },
|
||||
get baseUrl() { return vfsBaseUrl; },
|
||||
get region() { return ""; },
|
||||
|
||||
rest: noop,
|
||||
download: noop,
|
||||
url: noop,
|
||||
reconnect: noop,
|
||||
|
||||
vfsUrl: noop,
|
||||
|
||||
// File management
|
||||
resolve: noop,
|
||||
stat: function(path, options, cb) {
|
||||
var data = findNode(path);
|
||||
var name = path.split("/").pop();
|
||||
setTimeout(function() {
|
||||
if (data == null)
|
||||
return cb(ENOENT());
|
||||
var isFile = typeof data == "string";
|
||||
var stat = {
|
||||
name: name.substr(1),
|
||||
size: isFile ? data.length : 1,
|
||||
mtime: 0,
|
||||
ctime: 0,
|
||||
mime: isFile ? "" : "folder"
|
||||
};
|
||||
cb(null, stat);
|
||||
}, 20);
|
||||
},
|
||||
readfile: function(path, options, cb) {
|
||||
var data = findNode(path);
|
||||
setTimeout(function() {
|
||||
if (typeof data != "string")
|
||||
return cb(ENOENT());
|
||||
sendStream(data, cb);
|
||||
}, 20);
|
||||
},
|
||||
readdir: function(path, options, cb) {
|
||||
var data = findNode(path);
|
||||
setTimeout(function() {
|
||||
if (!data || typeof data == "string")
|
||||
return cb(ENOENT());
|
||||
var stats = Object.keys(data).map(function(n) {
|
||||
var isFile = typeof data[n] == "string";
|
||||
return {
|
||||
name: n.substr(1),
|
||||
size: isFile ? data[n].length : 1,
|
||||
mtime: 0,
|
||||
ctime: 0,
|
||||
mime: isFile ? "" : "folder"
|
||||
};
|
||||
});
|
||||
sendStream(stats, cb);
|
||||
});
|
||||
},
|
||||
mkfile: function(path, options, cb) {
|
||||
var parts = path.split("/")
|
||||
var name = "!" + parts.pop();
|
||||
var parent = findNode(parts.join("/"), true);
|
||||
var val = "";
|
||||
options.stream.on("data", function(e) {
|
||||
if (e) val += e;
|
||||
});
|
||||
options.stream.on("end", function(e) {
|
||||
if (e) val += e;
|
||||
setTimeout(function() {
|
||||
if (!parent || typeof parent[name] == "object")
|
||||
return cb(ENOENT());
|
||||
parent[name] = val;
|
||||
cb(null);
|
||||
});
|
||||
});
|
||||
},
|
||||
mkdir: function(path, options, cb) {
|
||||
var data = findNode(path, true);
|
||||
setTimeout(function() {
|
||||
if (!data)
|
||||
return cb(ENOENT());
|
||||
cb();
|
||||
});
|
||||
},
|
||||
mkdirP: function(path, options, cb) {
|
||||
var data = findNode(path, true);
|
||||
setTimeout(function() {
|
||||
if (!data)
|
||||
return cb(ENOENT());
|
||||
cb();
|
||||
});
|
||||
},
|
||||
appendfile: noop,
|
||||
rmfile: function(path, options, cb) {
|
||||
var parts = path.split("/")
|
||||
var name = "!" + parts.pop();
|
||||
setTimeout(function() {
|
||||
var parent = findNode(parts.join("/"));
|
||||
if (!parent || !parent[name])
|
||||
return cb(ENOENT());
|
||||
if (typeof parent[name] != "string")
|
||||
return cb(new Error("EISDIR"))
|
||||
delete parent[name];
|
||||
cb();
|
||||
});
|
||||
},
|
||||
rmdir: function(path, options, cb) {
|
||||
var parts = path.split("/")
|
||||
var name = "!" + parts.pop();
|
||||
setTimeout(function() {
|
||||
var parent = findNode(parts.join("/"));
|
||||
if (!parent || !parent[name])
|
||||
return cb(ENOENT());
|
||||
if (typeof parent[name] == "string")
|
||||
return cb(new Error("EISFILE"))
|
||||
delete parent[name];
|
||||
cb();
|
||||
});
|
||||
},
|
||||
rename: function(to, options, cb) {
|
||||
setTimeout(function() {
|
||||
var from = options.from;
|
||||
var overwrite = options.overwrite;
|
||||
|
||||
var parts = to.split("/")
|
||||
var toName = "!" + parts.pop();
|
||||
var toParent = findNode(parts.join("/"));
|
||||
|
||||
parts = from.split("/")
|
||||
var fromName = "!" + parts.pop();
|
||||
var fromParent = findNode(parts.join("/"));
|
||||
if (toParent[toName] != null && !overwrite)
|
||||
return cb(ENOENT());
|
||||
|
||||
toParent[toName] = fromParent[fromName];
|
||||
delete fromParent[fromName];
|
||||
cb(null);
|
||||
})
|
||||
},
|
||||
copy: function(from, options, cb) {
|
||||
setTimeout(function() {
|
||||
var to = options.to;
|
||||
var overwrite = options.overwrite;
|
||||
|
||||
var toParts = to.split("/")
|
||||
var toName = "!" + toParts.pop();
|
||||
var toParent = findNode(toParts.join("/"));
|
||||
|
||||
var parts = from.split("/")
|
||||
var fromName = "!" + parts.pop();
|
||||
var fromParent = findNode(parts.join("/"));
|
||||
var counter = 0;
|
||||
var name = toName;
|
||||
while (toParent[toName] != null && !options.overwrite)
|
||||
toName = name + "." + (++counter);
|
||||
|
||||
toParent[toName] = fromParent[fromName];
|
||||
toParts.push(toName.substr(1))
|
||||
cb(null, {to: toParts.join("/")});
|
||||
})
|
||||
},
|
||||
chmod: noop,
|
||||
symlink: noop,
|
||||
|
||||
// Save and retrieve Metadata
|
||||
metadata: function(path, value, sync, cb) {
|
||||
var parts = ("/.c9/metadata" + path).split("/")
|
||||
var name = "!" + parts.pop();
|
||||
var parent = findNode(parts.join("/"), true);
|
||||
if (sync) {
|
||||
parent[name] = JSON.stringify(value);
|
||||
return cb();
|
||||
}
|
||||
setTimeout(function() {
|
||||
parent[name] = JSON.stringify(value);
|
||||
cb();
|
||||
});
|
||||
},
|
||||
readFileWithMetadata: function(path, options, cb) {
|
||||
var data = findNode(path);
|
||||
var metadata = findNode("/.c9/metadata" + path);
|
||||
setTimeout(function() {
|
||||
if (typeof data != "string")
|
||||
return cb(ENOENT());
|
||||
// TODO metadata
|
||||
cb(null, data, metadata)
|
||||
});
|
||||
return { abort: function() {} };
|
||||
},
|
||||
|
||||
// Wrapper around fs.watch or fs.watchFile
|
||||
watch: silent,
|
||||
|
||||
// Network connection
|
||||
connect: noop,
|
||||
|
||||
// Process Management
|
||||
spawn: silent,
|
||||
pty: silent,
|
||||
tmux: silent,
|
||||
execFile: silent,
|
||||
killtree: silent,
|
||||
|
||||
// Extending the API
|
||||
use: silent,
|
||||
extend: silent,
|
||||
unextend: silent,
|
||||
|
||||
isIdle: function() { return true },
|
||||
}
|
||||
|
||||
function findNode(path, create, val) {
|
||||
if (!path) path = "/";
|
||||
var parts = path.split("/");
|
||||
if (!parts[parts.length - 1])
|
||||
parts.pop();
|
||||
var data = fsData;
|
||||
var prev = null;
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
prev = data;
|
||||
data = data["!" + parts[i]];
|
||||
if (data == null) {
|
||||
if (create && typeof prev != "string")
|
||||
data = prev["!" + parts[i]] = {};
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (val)
|
||||
data = prev["!" + parts[parts.length - 1]] = val;
|
||||
return data;
|
||||
}
|
||||
function ENOENT() {
|
||||
var err = new Error("ENOENT");
|
||||
err.code = "ENOENT";
|
||||
return err;
|
||||
}
|
||||
function sendStream(data, cb) {
|
||||
var stream = new Stream();
|
||||
stream.readable = true;
|
||||
cb(null, { stream: stream });
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(function(x) {
|
||||
stream.emit("data", x);
|
||||
});
|
||||
} else {
|
||||
stream.emit("data", data);
|
||||
}
|
||||
stream.emit("end");
|
||||
}
|
||||
register(null, {
|
||||
"vfs": vfsApi,
|
||||
"vfs.ping": {},
|
||||
"vfs.log": {
|
||||
log: function() {}
|
||||
},
|
||||
"vfs.endpoint": {
|
||||
clearCache: function() {}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
function offlineConfig(plugins) {
|
||||
var excludes = [
|
||||
"plugins/c9.ide.immediate/evaluators/debugnode",
|
||||
|
@ -390,7 +93,7 @@
|
|||
|
||||
return true;
|
||||
});
|
||||
plugins.push(vfsPlugin);
|
||||
plugins.push("plugins/c9.vfs.client/vfs_client_mock");
|
||||
plugins.push({
|
||||
provides: ["find", "installer"],
|
||||
consumes: [],
|
||||
|
|
Ładowanie…
Reference in New Issue