mirror of
https://github.com/linuxserver/core.git
synced 2026-02-20 05:07:19 +08:00
Merge pull request +15232 from c9/ide-plugins
Cleanup plugin manager
This commit is contained in:
commit
4a44154fc6
@ -99,7 +99,7 @@ describe("client config consistency", function() {
|
||||
}
|
||||
});
|
||||
|
||||
var provides = {"auth.bootstrap": 1, "hub": 1};
|
||||
var provides = { "auth.bootstrap": 1, "hub": 1, "app": 1 };
|
||||
var paths = {};
|
||||
clientPlugins.forEach(function(p) {
|
||||
if (paths[p.packagePath]) {
|
||||
|
||||
@ -19,6 +19,7 @@ module.exports = function(options) {
|
||||
options.workspaceDir = normalize(options.workspaceDir);
|
||||
options.installPath = normalize(options.installPath);
|
||||
options.home = normalize(options.home);
|
||||
options.sourceDir = options.sourceDir && normalize(options.sourceDir);
|
||||
|
||||
var workspaceDir = options.workspaceDir;
|
||||
var debug = options.debug !== undefined ? options.debug : false;
|
||||
@ -63,7 +64,8 @@ module.exports = function(options) {
|
||||
projectName: options.projectName || "Project",
|
||||
configName: options.configName,
|
||||
standalone: options.standalone,
|
||||
dashboardUrl: options.dashboardUrl
|
||||
dashboardUrl: options.dashboardUrl,
|
||||
sourceDir: options.sourceDir,
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.core/settings",
|
||||
@ -81,30 +83,16 @@ module.exports = function(options) {
|
||||
// baseUrl: options.apiUrl
|
||||
// },
|
||||
"plugins/c9.core/util",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/loader",
|
||||
plugins: options.plugins || [],
|
||||
loadFromDisk: options.standalone
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/installer",
|
||||
updates: options.pluginUpdates || []
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/manager",
|
||||
staticPrefix: staticPrefix + "/plugins/c9.ide.plugins",
|
||||
devel: devel
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/debug"
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/packages"
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.plugins/test",
|
||||
staticPrefix: staticPrefix + "/plugins/c9.ide.plugins"
|
||||
},
|
||||
"plugins/c9.ide.plugins/gui",
|
||||
// {
|
||||
// packagePath: "plugins/c9.ide.plugins/test",
|
||||
// staticPrefix: staticPrefix + "/plugins/c9.ide.plugins"
|
||||
// },
|
||||
|
||||
// VFS
|
||||
"plugins/c9.vfs.client/vfs.ping",
|
||||
|
||||
@ -78,6 +78,9 @@ module.exports = function(config, optimist) {
|
||||
if (argv.hosted)
|
||||
config.client_config = "default-hosted";
|
||||
|
||||
if (!argv.hosted)
|
||||
config.sourceDir = path.dirname(__dirname);
|
||||
|
||||
config.workspaceDir = baseProc;
|
||||
config.settingDir = argv["setting-path"];
|
||||
config.projectName = path.basename(baseProc);
|
||||
@ -88,7 +91,7 @@ module.exports = function(config, optimist) {
|
||||
config.startBridge = startBridge;
|
||||
|
||||
if (testing && argv.k)
|
||||
require("child_process").exec("tmux -L cloud91.9 kill-server", function(){});
|
||||
require("child_process").exec("tmux -L cloud91.9 kill-server", function() {});
|
||||
|
||||
var isLocalhost = host == "localhost" || host == "127.0.0.1";
|
||||
if (!/:/.test(argv.auth) && !isLocalhost) {
|
||||
|
||||
12
node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js
generated
vendored
12
node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js
generated
vendored
@ -137,13 +137,15 @@ function DefaultHandlers(mouseHandler) {
|
||||
}
|
||||
this.$clickNode = null;
|
||||
} else if (dom.hasCssClass(target, "checkbox")) {
|
||||
var nodes = inSelection && editor.selection.getSelectedNodes();
|
||||
provider._signal("toggleCheckbox", { target: node, selectedNodes: nodes });
|
||||
// consider deprecating this
|
||||
node.isChecked = !node.isChecked;
|
||||
if (inSelection) {
|
||||
var nodes = editor.selection.getSelectedNodes();
|
||||
nodes.forEach(function(n){ n.isChecked = node.isChecked });
|
||||
if (nodes) {
|
||||
nodes.forEach(function(n) { n.isChecked = node.isChecked });
|
||||
}
|
||||
provider._signal(node.isChecked ? "check" : "uncheck", inSelection ? nodes : [node]);
|
||||
provider._signal("change")
|
||||
provider._signal(node.isChecked ? "check" : "uncheck", nodes || [node]);
|
||||
provider._signal("change");
|
||||
} else if (dom.hasCssClass(target, "icon-ok")) {
|
||||
if (ev.getShiftKey()) {
|
||||
editor.selection.expandSelection(node, null, true);
|
||||
|
||||
53
node_modules/architect/architect.js
generated
vendored
53
node_modules/architect/architect.js
generated
vendored
@ -20,10 +20,10 @@ if (typeof module === "object") (function () {
|
||||
// This is assumed to be used at startup and uses sync I/O as well as can
|
||||
// throw exceptions. It loads and parses a config file.
|
||||
function loadConfig(configPath, callback) {
|
||||
var config = require(configPath);
|
||||
var base = dirname(configPath);
|
||||
var config = require(configPath);
|
||||
var base = dirname(configPath);
|
||||
|
||||
return resolveConfig(config, base, callback);
|
||||
return resolveConfig(config, base, callback);
|
||||
}
|
||||
|
||||
function resolveConfig(config, base, callback) {
|
||||
@ -126,15 +126,21 @@ else (function () {
|
||||
// Mass-Load path-based plugins using amd's require
|
||||
require(paths, function () {
|
||||
var args = arguments;
|
||||
var err = [];
|
||||
paths.forEach(function (name, i) {
|
||||
var module = args[i];
|
||||
var plugin = config[pluginIndexes[name]];
|
||||
if (!module || !plugin) return err.push(name);
|
||||
plugin.setup = module;
|
||||
plugin.provides = module.provides || [];
|
||||
plugin.consumes = module.consumes || [];
|
||||
});
|
||||
if (err.length)
|
||||
return callback(new Error("Missing plugins: " + err));
|
||||
callback(null, config);
|
||||
}, errback);
|
||||
}, errback || function(err) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
@ -173,7 +179,8 @@ function checkCycles(config, lookup) {
|
||||
});
|
||||
|
||||
var resolved = {
|
||||
hub: true
|
||||
hub: true,
|
||||
app: true
|
||||
};
|
||||
var changed = true;
|
||||
var sorted = [];
|
||||
@ -209,7 +216,6 @@ function checkCycles(config, lookup) {
|
||||
if (plugins.length) {
|
||||
var unresolved = {};
|
||||
plugins.forEach(function(plugin) {
|
||||
delete plugin.config;
|
||||
plugin.consumes.forEach(function(name) {
|
||||
if (unresolved[name] === false)
|
||||
return;
|
||||
@ -244,16 +250,12 @@ function checkCycles(config, lookup) {
|
||||
function Architect(config) {
|
||||
var app = this;
|
||||
app.config = config;
|
||||
app.packages = {};
|
||||
app.pluginToPackage = {};
|
||||
app.serviceToPlugin = {};
|
||||
|
||||
var isAdditionalMode;
|
||||
var services = app.services = {
|
||||
hub: {
|
||||
on: function (name, callback) {
|
||||
app.on(name, callback);
|
||||
}
|
||||
}
|
||||
hub: app,
|
||||
app: app
|
||||
};
|
||||
|
||||
// Check the config
|
||||
@ -275,10 +277,6 @@ function Architect(config) {
|
||||
});
|
||||
}
|
||||
|
||||
var m = /^plugins\/([^\/]+)|\/plugins\/[^\/]+\/([^\/]+)/.exec(plugin.packagePath);
|
||||
var packageName = m && (m[1] || m[2]);
|
||||
if (!app.packages[packageName]) app.packages[packageName] = [];
|
||||
|
||||
if (DEBUG) {
|
||||
recur++;
|
||||
plugin.setup(plugin, imports, register);
|
||||
@ -315,13 +313,8 @@ function Architect(config) {
|
||||
return app.emit("error", err);
|
||||
}
|
||||
services[name] = provided[name];
|
||||
app.pluginToPackage[name] = {
|
||||
path: plugin.packagePath,
|
||||
package: packageName,
|
||||
version: plugin.version,
|
||||
isAdditionalMode: isAdditionalMode
|
||||
};
|
||||
app.packages[packageName].push(name);
|
||||
app.serviceToPlugin[name] = plugin;
|
||||
plugin.__isAdditionalMode = isAdditionalMode;
|
||||
|
||||
app.emit("service", name, services[name], plugin);
|
||||
});
|
||||
@ -338,18 +331,18 @@ function Architect(config) {
|
||||
// Give createApp some time to subscribe to our "ready" event
|
||||
(typeof process === "object" ? process.nextTick : setTimeout)(startPlugins);
|
||||
|
||||
this.loadAdditionalPlugins = function(additionalConfig, callback){
|
||||
this.loadAdditionalPlugins = function(additionalConfig, callback) {
|
||||
isAdditionalMode = true;
|
||||
|
||||
exports.resolveConfig(additionalConfig, function (err, additionalConfig) {
|
||||
if (err) return callback(err);
|
||||
|
||||
app.once(ready ? "ready-additional" : "ready", function(app){
|
||||
app.once(ready ? "ready-additional" : "ready", function(app) {
|
||||
callback(null, app);
|
||||
}); // What about error state?
|
||||
|
||||
// Check the config - hopefully this works
|
||||
var _sortedPlugins = checkConfig(additionalConfig, function(name){
|
||||
var _sortedPlugins = checkConfig(additionalConfig, function(name) {
|
||||
return services[name];
|
||||
});
|
||||
|
||||
@ -359,7 +352,7 @@ function Architect(config) {
|
||||
startPlugins(true);
|
||||
}
|
||||
else {
|
||||
_sortedPlugins.forEach(function(item){
|
||||
_sortedPlugins.forEach(function(item) {
|
||||
sortedPlugins.push(item);
|
||||
});
|
||||
}
|
||||
@ -394,7 +387,7 @@ function createApp(config, callback) {
|
||||
var app;
|
||||
try {
|
||||
app = new Architect(config);
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
if (!callback) throw err;
|
||||
return callback(err, app);
|
||||
}
|
||||
@ -416,8 +409,6 @@ function createApp(config, callback) {
|
||||
app.removeListener("ready", onReady);
|
||||
callback(err, app);
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
return exports;
|
||||
|
||||
@ -81,7 +81,8 @@ define(function(require, exports, module) {
|
||||
/***** Methods *****/
|
||||
|
||||
plugin.on("load", function() {
|
||||
c9.on("connect", load, plugin);
|
||||
if (c9.connected) load();
|
||||
else c9.on("connect", load, plugin);
|
||||
});
|
||||
|
||||
plugin.on("unload", function() {
|
||||
|
||||
@ -196,9 +196,9 @@ define(function(require, exports, module) {
|
||||
// Write the package.json file
|
||||
var indent = data.match(/{\n\r?^ {4}"/) ? 4 : 2;
|
||||
var newData = JSON.stringify(json, null, indent);
|
||||
fs.writeFile(cwd + "/.build/package.json", newData, function() {
|
||||
fs.writeFile(cwd + "/c9build/package.json", newData, function() {
|
||||
if (dryRun)
|
||||
return next(); // if dry-run is passed only update path in .build
|
||||
return next(); // if dry-run is passed only update path in c9build
|
||||
fs.writeFile(packagePath, newData, function(err) {
|
||||
if (err) return callback(err);
|
||||
return next();
|
||||
@ -230,97 +230,59 @@ define(function(require, exports, module) {
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf("builders") != -1) {
|
||||
forEachFile(cwd + "/builders", function(filename, data) {
|
||||
packedFiles.push(cwd + "/builders/" + filename);
|
||||
function parseHeader(data, filename) {
|
||||
var firstLine = data.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim();
|
||||
var info = {};
|
||||
firstLine.split(";").forEach(function(n) {
|
||||
var key = n.split(":");
|
||||
if (key.length != 2)
|
||||
return console.error("Ignoring invalid key " + n + " in " + filename);
|
||||
info[key[0].trim()] = key[1].trim();
|
||||
});
|
||||
info.data = firstLine;
|
||||
return info;
|
||||
}
|
||||
|
||||
function addResource(type) {
|
||||
forEachFile(cwd + "/" + type, function(filename, data) {
|
||||
packedFiles.push(cwd + "/"+ type + "/" + filename);
|
||||
extraCode.push({
|
||||
type: "builders",
|
||||
type: type,
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("keymaps") != -1) {
|
||||
forEachFile(cwd + "/keymaps", function(filename, data) {
|
||||
packedFiles.push(cwd + "/keymaps/" + filename);
|
||||
extraCode.push({
|
||||
type: "keymaps",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("modes") != -1) {
|
||||
forEachFile(cwd + "/modes", function(filename, data) {
|
||||
function addMode(type) {
|
||||
forEachFile(cwd + "/modes", function(filename, data) {
|
||||
if (/(?:_highlight_rules|_test|_worker|_fold|_behaviou?r)\.js$/.test(filename))
|
||||
return;
|
||||
if (!/\.js$/.test(filename))
|
||||
return;
|
||||
var firstLine = data.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim();
|
||||
var info = parseHeader(data, cwd + "/modes/" + filename);
|
||||
|
||||
if (!/caption\s*:[^;]+/i.test(firstLine)) {
|
||||
packedFiles.push(cwd + "/modes/" + filename);
|
||||
console.error("Ignoring mode with invalid header: ", firstLine);
|
||||
console.error(" at " + cwd + "/modes/" + filename);
|
||||
return;
|
||||
}
|
||||
extraCode.push({
|
||||
type: "modes",
|
||||
filename: filename,
|
||||
data: firstLine
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("outline") != -1) {
|
||||
forEachFile(cwd + "/outline", function(filename, data) {
|
||||
packedFiles.push(cwd + "/outline/" + filename);
|
||||
extraCode.push({
|
||||
type: "outline",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("runners") != -1) {
|
||||
forEachFile(cwd + "/runners", function(filename, data) {
|
||||
packedFiles.push(cwd + "/runners/" + filename);
|
||||
extraCode.push({
|
||||
type: "runners",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("snippets") != -1) {
|
||||
forEachFile(cwd + "/snippets", function(filename, data) {
|
||||
packedFiles.push(cwd + "/snippets/" + filename);
|
||||
extraCode.push({
|
||||
type: "snippets",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("themes") != -1) {
|
||||
forEachFile(cwd + "/themes", function(filename, data) {
|
||||
packedFiles.push(cwd + "/themes/" + filename);
|
||||
extraCode.push({
|
||||
type: "themes",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
}
|
||||
if (files.indexOf("templates") != -1) {
|
||||
forEachFile(cwd + "/templates", function(filename, data) {
|
||||
packedFiles.push(cwd + "/templates/" + filename);
|
||||
extraCode.push({
|
||||
type: "templates",
|
||||
filename: filename,
|
||||
data: data
|
||||
});
|
||||
if (!info.caption) info.caption = filename;
|
||||
|
||||
info.type = "modes";
|
||||
info.filename = filename;
|
||||
extraCode.push(info);
|
||||
});
|
||||
}
|
||||
var handlers = {
|
||||
templates: addResource,
|
||||
snippets: addResource,
|
||||
builders: addResource,
|
||||
keymaps: addResource,
|
||||
outline: addResource,
|
||||
runners: addResource,
|
||||
themes: addResource,
|
||||
modes: addMode,
|
||||
};
|
||||
files.forEach(function(type) {
|
||||
if (handlers.hasOwnProperty(type))
|
||||
handlers[type](type);
|
||||
});
|
||||
|
||||
|
||||
packedFiles.push(cwd + "/package." + packageName + ".js");
|
||||
|
||||
@ -348,7 +310,7 @@ define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Plugin", "plugin.debug"
|
||||
];
|
||||
main.provides = [];
|
||||
main.provides = ["PACKAGE_NAME.bundle"];
|
||||
return main;
|
||||
function main(options, imports, register) {
|
||||
var debug = imports["plugin.debug"];
|
||||
@ -363,7 +325,7 @@ define(function(require, exports, module) {
|
||||
|
||||
plugin.load("PACKAGE_NAME.bundle");
|
||||
|
||||
register(null, {});
|
||||
register(null, {"PACKAGE_NAME.bundle": plugin});
|
||||
}
|
||||
});
|
||||
}).toString();
|
||||
@ -382,7 +344,7 @@ define(function(require, exports, module) {
|
||||
|
||||
staticPlugin = {
|
||||
source: code,
|
||||
id: "plugins/" + packageName + "/__static__",
|
||||
id: "plugins/" + packageName + "/" + packageName + ".bundle",
|
||||
path: ""
|
||||
};
|
||||
next();
|
||||
@ -448,17 +410,17 @@ define(function(require, exports, module) {
|
||||
},
|
||||
function(next) {
|
||||
proc.execFile("rm", {
|
||||
args: ["-rf", ".c9/.build"],
|
||||
args: ["-rf", "c9build"],
|
||||
cwd: cwd
|
||||
}, function() {
|
||||
mkdirP(cwd + "/.build");
|
||||
fs.writeFile(cwd + "/.build/package." + packageName + ".js", result.code, "utf8", next);
|
||||
mkdirP(cwd + "/c9build");
|
||||
fs.writeFile(cwd + "/c9build/package." + packageName + ".js", result.code, "utf8", next);
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
var copy = require("architect-build/copy");
|
||||
|
||||
var excludeRe = /^\.(\w*ignore|git|c9|hg|build)$/;
|
||||
var excludeRe = /^\.(\w*ignore|git|c9|hg|build)$|^(c9)?build$|_test\.js$/;
|
||||
var excludeMap = Object.create(null);
|
||||
|
||||
packedFiles.push(cwd + "/package." + packageName + ".js");
|
||||
@ -470,7 +432,7 @@ define(function(require, exports, module) {
|
||||
if (json.installer)
|
||||
excludeMap["/" + normalizePath(Path.relative(cwd, json.installer))] = 0;
|
||||
|
||||
copy(cwd, cwd + "/.build", {
|
||||
copy(cwd, cwd + "/c9build", {
|
||||
exclude: function(name, parent) {
|
||||
if (excludeRe.test(name))
|
||||
return true;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
* @main c9.core
|
||||
*/
|
||||
define(function(require, module, exports) {
|
||||
main.consumes = ["Plugin", "ext", "vfs"];
|
||||
main.consumes = ["Plugin", "vfs"];
|
||||
main.provides = ["c9"];
|
||||
return main;
|
||||
|
||||
@ -20,8 +20,6 @@ define(function(require, module, exports) {
|
||||
var emit = plugin.getEmitter();
|
||||
emit.setMaxListeners(500);
|
||||
|
||||
imports.ext.vfs = imports.vfs;
|
||||
|
||||
var loaded = false;
|
||||
var loggedIn = false;
|
||||
var isReady = false;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [];
|
||||
main.consumes = ["app"];
|
||||
main.provides = ["ext", "Plugin"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Emitter = require("events").EventEmitter;
|
||||
var architectApp = imports.app;
|
||||
|
||||
|
||||
var plugins = [];
|
||||
var lut = {};
|
||||
@ -18,12 +20,7 @@ define(function(require, exports, module) {
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
var emit = plugin.getEmitter();
|
||||
var vfs, settings, api;
|
||||
|
||||
plugin.__defineSetter__("vfs", function(remote) {
|
||||
vfs = remote;
|
||||
delete plugin.vfs;
|
||||
});
|
||||
var settings, api;
|
||||
|
||||
plugin.__defineSetter__("settings", function(remote) {
|
||||
settings = remote;
|
||||
@ -80,17 +77,8 @@ define(function(require, exports, module) {
|
||||
if (!plugin.registered)
|
||||
return;
|
||||
|
||||
if (!ignoreDeps && getDependencies(plugin.name).length) {
|
||||
//@todo this should be moved to whoever is calling this.
|
||||
// if (!silent)
|
||||
// util.alert(
|
||||
// "Could not disable extension",
|
||||
// "Extension is still in use",
|
||||
// "This extension cannot be disabled, because it is still in use by the following plugins:<br /><br />"
|
||||
// + " - " + usedBy.join("<br /> - ")
|
||||
// + "<br /><br /> Please disable those plugins first.");
|
||||
if (!ignoreDeps && getDependents(plugin.name).length)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keep)
|
||||
plugins.splice(plugins.indexOf(plugin), 1);
|
||||
@ -108,7 +96,7 @@ define(function(require, exports, module) {
|
||||
emit("unregister", { plugin: plugin });
|
||||
}
|
||||
|
||||
function getDependencies(pluginName) {
|
||||
function getDependents(pluginName) {
|
||||
var usedBy = [];
|
||||
|
||||
// Check for dependencies needing this plugin
|
||||
@ -155,12 +143,14 @@ define(function(require, exports, module) {
|
||||
}
|
||||
|
||||
function loadRemotePlugin(id, options, callback) {
|
||||
var vfs = architectApp.services.vfs;
|
||||
vfs.extend(id, options, function(err, meta) {
|
||||
callback(err, meta && meta.api);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchRemoteApi(id, callback) {
|
||||
var vfs = architectApp.services.vfs;
|
||||
vfs.use(id, {}, function(err, meta) {
|
||||
callback(err, meta && meta.api);
|
||||
});
|
||||
@ -284,7 +274,7 @@ define(function(require, exports, module) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getDependencies: getDependencies,
|
||||
getDependents: getDependents,
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@ -153,7 +153,7 @@ define(function(require, exports, module) {
|
||||
var data = strJson.replace(/(^|\n)\s*\/\/.*/g, "");
|
||||
|
||||
try { return JSON.parse(data); }
|
||||
catch (e) { cb(e); return false; }
|
||||
catch (e) { cb && cb(e); return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -38,7 +38,7 @@ define(function(require, exports, module) {
|
||||
var cycleKeyPressed, changedTabs, unchangedTabs, dirtyNextTab, dirtyNextPane;
|
||||
|
||||
var ACTIVEPAGE = function() { return tabs.focussedTab; };
|
||||
var ACTIVEPATH = function() { var tab = tabs.focussedTab; return tab && (tab.path || tab.relatedPath || tab.editor.getPathAsync); };
|
||||
var ACTIVEPATH = function() { var tab = mnuContext.$tab || tabs.focussedTab; return tab && (tab.path || tab.relatedPath || tab.editor.getPathAsync); };
|
||||
var MORETABS = function() { return tabs.getTabs().length > 1; };
|
||||
var MORETABSINPANE = function() { return tabs.focussedTab && tabs.focussedTab.pane.getTabs().length > 1; };
|
||||
var MOREPANES = function() { return tabs.getPanes().length > 1; };
|
||||
|
||||
@ -380,9 +380,9 @@ define(function(require, exports, module) {
|
||||
get myUserId() { return myUserId; },
|
||||
/**
|
||||
* Specifies wether the collab workspace was previously loaded and collab was connected - or not
|
||||
* @property {Boolean} loaded
|
||||
* @property {Boolean} isReady
|
||||
*/
|
||||
get loaded() { return loadedWorkspace; },
|
||||
get isReady() { return loadedWorkspace; },
|
||||
/**
|
||||
* Gets my filesystem access to this workspace:
|
||||
* Values can be either "r" or "rw"
|
||||
|
||||
@ -3,7 +3,7 @@ define(function(require, exports, module) {
|
||||
"Plugin", "dialog.error", "ui", "settings", "tabManager", "save",
|
||||
"menus", "preferences.keybindings", "preferences.general",
|
||||
"preferences.project", "c9", "commands", "watcher", "fs",
|
||||
"tree.favorites", "preferences", "util"
|
||||
"tree.favorites", "util", "app"
|
||||
];
|
||||
main.provides = ["configure"];
|
||||
return main;
|
||||
@ -16,13 +16,13 @@ define(function(require, exports, module) {
|
||||
var menus = imports.menus;
|
||||
var watcher = imports.watcher;
|
||||
var tabManager = imports.tabManager;
|
||||
var preferences = imports.preferences;
|
||||
var ui = imports.ui;
|
||||
var c9 = imports.c9;
|
||||
var fs = imports.fs;
|
||||
var kbprefs = imports["preferences.keybindings"];
|
||||
var genprefs = imports["preferences.general"];
|
||||
var prjprefs = imports["preferences.project"];
|
||||
var services = imports.app.services;
|
||||
var showError = imports["dialog.error"].show;
|
||||
var favs = imports["tree.favorites"];
|
||||
var util = imports.util;
|
||||
@ -35,7 +35,7 @@ define(function(require, exports, module) {
|
||||
// var emit = plugin.getEmitter();
|
||||
|
||||
var cssSession = new Plugin("Ajax.org", main.consumes);
|
||||
var services, initPlugin;
|
||||
var initPlugin;
|
||||
|
||||
var pathFromFavorite = options.pathFromFavorite;
|
||||
|
||||
@ -288,24 +288,27 @@ define(function(require, exports, module) {
|
||||
var script = settings.get("user/config/init.js") || "";
|
||||
openTab("~/.c9/init.js", script, "javascript",
|
||||
"// You can access plugins via the 'services' global variable\n" +
|
||||
"/*global services, plugin*/\n");
|
||||
"/*global services, plugin*/\n" +
|
||||
"\n" +
|
||||
"// to load plugins use\n" +
|
||||
"// services.pluginManager.loadPackage([\n" +
|
||||
"// \"https://<user>.github.io/<project>/build/package.<name>.js\",\n" +
|
||||
"// \"~/.c9/plugins/<name>/package.json\",\n" +
|
||||
"// ]);\n");
|
||||
}
|
||||
|
||||
function editStylesCss() {
|
||||
// preferences.hide();
|
||||
var css = settings.get("user/config/styles.css") || "";
|
||||
openTab("~/.c9/styles.css", css, "css");
|
||||
}
|
||||
|
||||
function editProjectSettings() {
|
||||
// preferences.hide();
|
||||
var value = JSON.stringify(settings.model.project, 0, " ")
|
||||
.replace(/"true"/g, "true")
|
||||
.replace(/"false"/g, "false");
|
||||
openTab(settings.paths.project, value, "javascript");
|
||||
}
|
||||
function editUserSettings() {
|
||||
// preferences.hide();
|
||||
var value = JSON.stringify(settings.model.user, 0, " ")
|
||||
.replace(/"true"/g, "true")
|
||||
.replace(/"false"/g, "false");
|
||||
@ -353,9 +356,6 @@ define(function(require, exports, module) {
|
||||
*
|
||||
**/
|
||||
plugin.freezePublicAPI({
|
||||
get services() { return services; },
|
||||
set services(value) { services = value; },
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
define(function(require, module, exports) {
|
||||
main.consumes = ["Plugin", "ui", "Document", "dialog.alert", "settings"];
|
||||
main.consumes = ["Plugin", "ui", "Document", "dialog.alert"];
|
||||
main.provides = ["Tab"];
|
||||
return main;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Plugin", "c9", "util", "settings", "ui", "layout", "findreplace",
|
||||
"Plugin", "c9", "util", "settings", "ui", "layout",
|
||||
"find", "anims", "menus", "tabManager", "commands", "tooltip",
|
||||
"tree", "apf", "console", "preferences", "dialog.question",
|
||||
"tree.favorites", "save"
|
||||
@ -27,6 +27,7 @@ define(function(require, exports, module) {
|
||||
var find = imports.find;
|
||||
var save = imports.save;
|
||||
var question = imports["dialog.question"].show;
|
||||
var apf = imports.apf;
|
||||
|
||||
var markup = require("text!./findinfiles.xml");
|
||||
var lib = require("plugins/c9.ide.find.replace/libsearch");
|
||||
|
||||
@ -1,554 +0,0 @@
|
||||
/*global requirejs*/
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Plugin", "vfs", "fs", "plugin.loader", "c9", "ext", "watcher",
|
||||
"dialog.notification", "dialog.info", "ui", "menus", "commands", "settings", "auth",
|
||||
"installer", "find", "util", "preferences.experimental"
|
||||
];
|
||||
main.provides = ["plugin.debug"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports.Plugin;
|
||||
var vfs = imports.vfs;
|
||||
var watcher = imports.watcher;
|
||||
var ext = imports.ext;
|
||||
var util = imports.util;
|
||||
var find = imports.find;
|
||||
var ui = imports.ui;
|
||||
var menus = imports.menus;
|
||||
var installer = imports.installer;
|
||||
var settings = imports.settings;
|
||||
var commands = imports.commands;
|
||||
var fs = imports.fs;
|
||||
var c9 = imports.c9;
|
||||
var auth = imports.auth;
|
||||
var loader = imports["plugin.loader"];
|
||||
var notify = imports["dialog.notification"].show;
|
||||
var experimental = imports["preferences.experimental"];
|
||||
var showInfo = imports["dialog.info"].show;
|
||||
|
||||
var dirname = require("path").dirname;
|
||||
var basename = require("path").basename;
|
||||
var join = require("path").join;
|
||||
var async = require("async");
|
||||
|
||||
var architect;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
var emit = plugin.getEmitter();
|
||||
|
||||
var plugins = [];
|
||||
|
||||
var ENABLED = c9.location.indexOf("debug=2") > -1;
|
||||
var HASSDK = ENABLED || experimental.addExperiment("sdk", false, "SDK/Load Custom Plugins");
|
||||
|
||||
var reParts = /^(builders|keymaps|modes|outline|runners|snippets|themes|templates)\/(.*)/;
|
||||
var reModule = /(?:_highlight_rules|_test|_worker|_fold|_behaviou?r)\.js$/;
|
||||
var jsExtRe = /\.js$/;
|
||||
|
||||
var loaded = false;
|
||||
function load() {
|
||||
if (loaded) return false;
|
||||
loaded = true;
|
||||
|
||||
if (!HASSDK) return;
|
||||
|
||||
menus.addItemByPath("Tools/~", new ui.divider(), 100000, plugin);
|
||||
menus.addItemByPath("Tools/Developer", null, 100100, plugin);
|
||||
|
||||
if (!ENABLED) {
|
||||
menus.addItemByPath("Tools/Developer/Start in Debug Mode", new ui.item({
|
||||
onclick: function() {
|
||||
var url = location.href + (location.href.indexOf("?") > -1
|
||||
? "&debug=2"
|
||||
: "?debug=2");
|
||||
window.open(url);
|
||||
}
|
||||
}), 900, plugin);
|
||||
}
|
||||
|
||||
if (!ENABLED) return;
|
||||
|
||||
notify("<div class='c9-readonly'>You are in <span style='color:rgb(245, 234, 15)'>Debug</span> Mode. "
|
||||
+ "Don't forget to open the browser's dev tools to see any errors.",
|
||||
false);
|
||||
|
||||
// Insert relevant LESS libraries
|
||||
var theme = settings.get("user/general/@skin");
|
||||
|
||||
ui.defineLessLibrary(require("text!../c9.ide.layout.classic/themes/default-" + theme + ".less"), plugin);
|
||||
ui.defineLessLibrary(require("text!../c9.ide.layout.classic/less/lesshat.less"), plugin);
|
||||
|
||||
fs.readdir("~/.c9/plugins", function(err, list) {
|
||||
if (err) return console.error(err);
|
||||
|
||||
var names = loader.plugins;
|
||||
var toLoad = [];
|
||||
|
||||
list.forEach(function(stat) {
|
||||
var name = stat.name;
|
||||
// If the plugin doesn't exist
|
||||
if (names.indexOf(name) == -1 && name.charAt(0) != "." && name.charAt(0) != "_")
|
||||
toLoad.push(name);
|
||||
});
|
||||
|
||||
loadPlugins(toLoad);
|
||||
});
|
||||
|
||||
commands.addCommand({
|
||||
name: "reloadCustomPlugin",
|
||||
group: "Plugins",
|
||||
bindKey: {
|
||||
mac: "Command-Enter",
|
||||
win: "Ctrl-Enter"
|
||||
},
|
||||
exec: function() {
|
||||
reloadPluginUI();
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
menus.addItemByPath("Tools/Developer/Reload Custom Plugin", new ui.item({
|
||||
command: "reloadCustomPlugin"
|
||||
}), 1000, plugin);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
function loadPlugins(list) {
|
||||
if (!vfs.connected) {
|
||||
vfs.once("connect", loadPlugins.bind(this, config));
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof list == "string")
|
||||
list = [list];
|
||||
|
||||
var config = [];
|
||||
var loadConfig = function() {
|
||||
architect.loadAdditionalPlugins(config, function(err) {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
async.each(list, function(name, next) {
|
||||
var resourceHolder = new Plugin();
|
||||
var resourceVersion = "";
|
||||
|
||||
resourceHolder.on("load", function() {
|
||||
if (inited) load();
|
||||
});
|
||||
|
||||
resourceHolder.freezePublicAPI({
|
||||
get version() { return resourceVersion; },
|
||||
set version(v) { resourceVersion = v; }
|
||||
});
|
||||
|
||||
var inited = false;
|
||||
function load() {
|
||||
async.parallel([
|
||||
function(next) {
|
||||
// Fetch package.json
|
||||
fs.readFile("~/.c9/plugins/" + name + "/package.json", function(err, data) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
try {
|
||||
var options = JSON.parse(data);
|
||||
if (!options.plugins)
|
||||
throw new Error("Missing plugins property in package.json of " + name);
|
||||
}
|
||||
catch (e) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var host = vfs.baseUrl + "/";
|
||||
var base = join(String(c9.projectId),
|
||||
"plugins", auth.accessToken);
|
||||
|
||||
// Configure Require.js
|
||||
var pathConfig = {};
|
||||
pathConfig["plugins/" + name] = host + join(base, name);
|
||||
requirejs.config({ paths: pathConfig });
|
||||
|
||||
// Add the plugin to the config
|
||||
Object.keys(options.plugins).forEach(function(path) {
|
||||
var pluginPath = name + "/" + path;
|
||||
|
||||
// Watch project path
|
||||
watch("~/.c9/plugins/" + pluginPath);
|
||||
var cfg = options.plugins[path];
|
||||
cfg.packagePath = "plugins/" + name + "/" + path;
|
||||
cfg.staticPrefix = host + join(base, name);
|
||||
cfg.apikey = "0000000000000000000000000000=";
|
||||
|
||||
// Set version for package manager
|
||||
cfg.version = options.version;
|
||||
|
||||
config.push(cfg);
|
||||
plugins.push(name + "/" + path);
|
||||
});
|
||||
|
||||
// Set version for package manager
|
||||
resourceHolder.version = options.version;
|
||||
|
||||
// Start the installer if one is included
|
||||
if (options.installer) {
|
||||
addStaticPlugin("installer", name, options.installer,
|
||||
null, resourceHolder);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
var path = join("~/.c9/plugins", name);
|
||||
var rePath = new RegExp("^" + util.escapeRegExp(path.replace(/^~/, c9.home) + "/"), "gm");
|
||||
find.getFileList({
|
||||
path: path,
|
||||
nocache: true,
|
||||
buffer: true
|
||||
}, function(err, data) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
// Remove the base path
|
||||
data = data.replace(rePath, "");
|
||||
|
||||
if (data.match(/^__installed__.js/))
|
||||
return next("installed");
|
||||
|
||||
// Process all the submodules
|
||||
var parallel = processModules(path, data, resourceHolder);
|
||||
async.parallel(parallel, function(err, data) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!inited)
|
||||
resourceHolder.load(name + ".bundle");
|
||||
|
||||
// Done
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
], function(err, results) {
|
||||
if (err) console.error(err);
|
||||
|
||||
if (!inited) {
|
||||
next();
|
||||
inited = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
load();
|
||||
}, function() {
|
||||
emit.sticky("ready");
|
||||
|
||||
if (!config.length) return;
|
||||
|
||||
// Load config
|
||||
if (installer.sessions.length) {
|
||||
installer.on("stop", function listen(err) {
|
||||
if (err)
|
||||
return console.error(err);
|
||||
|
||||
if (!installer.sessions.length) {
|
||||
loadConfig();
|
||||
installer.off("stop", listen);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
}
|
||||
|
||||
function processModules(path, data, plugin) {
|
||||
var parallel = [];
|
||||
|
||||
data.split("\n").forEach(function(line) {
|
||||
if (!line.match(reParts)) return;
|
||||
|
||||
var type = RegExp.$1;
|
||||
var filename = RegExp.$2;
|
||||
if (filename.indexOf("/") > -1) return;
|
||||
|
||||
if (type == "modes" && (reModule.test(filename) || !jsExtRe.test(filename)))
|
||||
return;
|
||||
|
||||
if (type == "snippets") {
|
||||
if (jsExtRe.test(filename)) {
|
||||
var snippetPath = join("plugins", basename(path), type, filename).replace(jsExtRe, "");
|
||||
require([snippetPath], function(m) {
|
||||
architect.services["language.complete"].addSnippet(m, plugin);
|
||||
});
|
||||
}
|
||||
if (!/\.snippets$/.test(filename))
|
||||
return;
|
||||
}
|
||||
|
||||
parallel.push(function(next) {
|
||||
fs.readFile(join(path, type, filename), function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return next(err);
|
||||
}
|
||||
|
||||
addStaticPlugin(type, basename(path), filename, data, plugin);
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return parallel;
|
||||
}
|
||||
|
||||
function addStaticPlugin(type, pluginName, filename, data, plugin) {
|
||||
var services = architect.services;
|
||||
var path = "plugins/" + pluginName + "/"
|
||||
+ (type == "installer" ? "" : type + "/")
|
||||
+ filename.replace(/\.js$/, "");
|
||||
|
||||
var bundleName = pluginName + ".bundle";
|
||||
if (!services[bundleName] && type !== "installer") {
|
||||
services[bundleName] = plugin;
|
||||
architect.lut["~/.c9/plugins/" + pluginName] = {
|
||||
provides: []
|
||||
};
|
||||
architect.pluginToPackage[bundleName] = {
|
||||
path: "~/.c9/plugins/" + pluginName,
|
||||
package: pluginName,
|
||||
version: plugin.version,
|
||||
isAdditionalMode: true
|
||||
};
|
||||
if (!architect.packages[pluginName])
|
||||
architect.packages[pluginName] = [];
|
||||
architect.packages[pluginName].push(name);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "builders":
|
||||
data = util.safeParseJson(data, function() {});
|
||||
if (!data) return;
|
||||
|
||||
services.build.addBuilder(filename, data, plugin);
|
||||
break;
|
||||
case "keymaps":
|
||||
data = util.safeParseJson(data, function() {});
|
||||
if (!data) return;
|
||||
|
||||
services["preferences.keybindings"].addCustomKeymap(filename, data, plugin);
|
||||
break;
|
||||
case "modes":
|
||||
var mode = {};
|
||||
var firstLine = data.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim();
|
||||
firstLine.split(";").forEach(function(n) {
|
||||
if (!n) return;
|
||||
var info = n.split(":");
|
||||
mode[info[0].trim()] = info[1].trim();
|
||||
});
|
||||
|
||||
services.ace.defineSyntax({
|
||||
name: path,
|
||||
caption: mode.caption,
|
||||
extensions: (mode.extensions || "").trim()
|
||||
.replace(/\s*,\s*/g, "|").replace(/(^|\|)\./g, "$1")
|
||||
});
|
||||
break;
|
||||
case "outline":
|
||||
if (!data) return;
|
||||
|
||||
services.outline.addOutlinePlugin(path, data, plugin);
|
||||
break;
|
||||
case "runners":
|
||||
data = util.safeParseJson(data, function() {});
|
||||
if (!data) return;
|
||||
|
||||
services.run.addRunner(data.caption || filename, data, plugin);
|
||||
break;
|
||||
case "snippets":
|
||||
services["language.complete"].addSnippet(data, plugin);
|
||||
break;
|
||||
case "themes":
|
||||
services.ace.addTheme(data, plugin);
|
||||
break;
|
||||
case "templates":
|
||||
services.newresource.addFileTemplate(data, plugin);
|
||||
break;
|
||||
case "installer":
|
||||
if (data) {
|
||||
installer.createSession(pluginName, data, function(v, o) {
|
||||
require([path], function(fn) {
|
||||
fn(v, o);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
require([path], function(fn) {
|
||||
installer.createSession(pluginName, fn.version, function(v, o) {
|
||||
fn(v, o);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if require.s.contexts._ can help watching all dependencies
|
||||
function watch(path) {
|
||||
watcher.watch(path);
|
||||
|
||||
watcher.on("change", function(e) {
|
||||
if (e.path == path)
|
||||
reloadPackage(path.replace(/^~\/\.c9\//, ""));
|
||||
});
|
||||
watcher.on("delete", function(e) {
|
||||
if (e.path == path)
|
||||
reloadPackage(path.replace(/^~\/\.c9\//, ""));
|
||||
});
|
||||
watcher.on("failed", function(e) {
|
||||
if (e.path == path) {
|
||||
setTimeout(function() {
|
||||
watcher.watch(path); // Retries once after 1s
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function reloadPackage(path) {
|
||||
var unloaded = [];
|
||||
|
||||
function recurUnload(name) {
|
||||
var plugin = architect.services[name];
|
||||
unloaded.push(name);
|
||||
|
||||
// Find all the dependencies
|
||||
var deps = ext.getDependencies(plugin.name);
|
||||
|
||||
// Unload all the dependencies (and their deps)
|
||||
deps.forEach(function(name) {
|
||||
recurUnload(name);
|
||||
});
|
||||
|
||||
// Unload plugin
|
||||
plugin.unload();
|
||||
}
|
||||
|
||||
// Recursively unload plugin
|
||||
var p = architect.lut[path];
|
||||
if (p.provides) { // Plugin might not been initialized all the way
|
||||
p.provides.forEach(function(name) {
|
||||
recurUnload(name);
|
||||
});
|
||||
}
|
||||
|
||||
// create reverse lookup table
|
||||
var rlut = {};
|
||||
for (var packagePath in architect.lut) {
|
||||
var provides = architect.lut[packagePath].provides;
|
||||
if (provides) { // Plugin might not been initialized all the way
|
||||
provides.forEach(function(name) {
|
||||
rlut[name] = packagePath;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Build config of unloaded plugins
|
||||
var config = [], done = {};
|
||||
unloaded.forEach(function(name) {
|
||||
var packagePath = rlut[name];
|
||||
|
||||
// Make sure we include each plugin only once
|
||||
if (done[packagePath]) return;
|
||||
done[packagePath] = true;
|
||||
|
||||
var options = architect.lut[packagePath];
|
||||
delete options.provides;
|
||||
delete options.consumes;
|
||||
delete options.setup;
|
||||
|
||||
config.push(options);
|
||||
|
||||
// Clear require cache
|
||||
requirejs.undef(options.packagePath); // global
|
||||
});
|
||||
|
||||
// Load all plugins again
|
||||
architect.loadAdditionalPlugins(config, function(err) {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
function reloadPluginUI() {
|
||||
var list = [];
|
||||
Object.keys(architect.pluginToPackage).forEach(function(name) {
|
||||
if (architect.pluginToPackage[name].isAdditionalMode)
|
||||
list.push(architect.pluginToPackage[name].path);
|
||||
});
|
||||
|
||||
var path = list[list.length - 1];
|
||||
reloadPackage(path.replace(/^~\/\.c9\//, ""));
|
||||
|
||||
// Avoid confusion with "Reload Last Plugin"
|
||||
var href = document.location.href.replace(/[?&]reload=[^&]+/, "");
|
||||
window.history.replaceState(window.history.state, null, href);
|
||||
showInfo("Reloaded " + path + ".", 1000);
|
||||
}
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("load", function() {
|
||||
load();
|
||||
});
|
||||
plugin.on("unload", function() {
|
||||
loaded = false;
|
||||
});
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
plugin.freezePublicAPI({
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get architect() { throw new Error(); },
|
||||
set architect(v) { architect = v; },
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get plugins() { return plugins; },
|
||||
|
||||
_events: [
|
||||
/**
|
||||
* @event ready
|
||||
*/
|
||||
"ready"
|
||||
],
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
addStaticPlugin: addStaticPlugin,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
reloadPackage: reloadPackage,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
loadPackage: loadPlugins
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"plugin.debug": plugin
|
||||
});
|
||||
}
|
||||
});
|
||||
959
plugins/c9.ide.plugins/gui.js
Normal file
959
plugins/c9.ide.plugins/gui.js
Normal file
@ -0,0 +1,959 @@
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"app", "ext", "c9", "PreferencePanel", "settings", "ui", "util",
|
||||
"layout", "menus", "commands", "pluginManager",
|
||||
"dialog.error", "dialog.info", "tree.favorites", "fs", "tree", "vfs",
|
||||
"preferences.experimental", "apf","dialog.notification"
|
||||
];
|
||||
main.provides = ["pluginManagerUi"];
|
||||
return main;
|
||||
|
||||
|
||||
function main(options, imports, register) {
|
||||
var PreferencePanel = imports.PreferencePanel;
|
||||
var settings = imports.settings;
|
||||
var layout = imports.layout;
|
||||
var commands = imports.commands;
|
||||
var menus = imports.menus;
|
||||
var ui = imports.ui;
|
||||
var c9 = imports.c9;
|
||||
var fs = imports.fs;
|
||||
var ext = imports.ext;
|
||||
var util = imports.util;
|
||||
var apf = imports.apf;
|
||||
var showError = imports["dialog.error"].show;
|
||||
var showInfo = imports["dialog.info"].show;
|
||||
var notify = imports["dialog.notification"].show;
|
||||
var experimental = imports["preferences.experimental"];
|
||||
var pluginManager = imports.pluginManager;
|
||||
var architectApp = imports.app;
|
||||
|
||||
var search = require("../c9.ide.navigate/search");
|
||||
var Tree = require("ace_tree/tree");
|
||||
var TreeData = require("./managerdp");
|
||||
var qs = require("querystring");
|
||||
|
||||
var escapeHTML = require("ace/lib/lang").escapeHTML;
|
||||
|
||||
var CORE = {};
|
||||
var TEMPLATES = {
|
||||
"plugin.simple": "Empty Plugin",
|
||||
"plugin.default": "Full Plugin",
|
||||
"plugin.installer": "Installer Plugin",
|
||||
"plugin.bundle": "Cloud9 Bundle"
|
||||
};
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var DEBUG = c9.location.indexOf("debug=2") > -1;
|
||||
var ENABLED = DEBUG || experimental.addExperiment(
|
||||
"plugin-manager",
|
||||
options.devel,
|
||||
"SDK/Plugin Manager"
|
||||
);
|
||||
|
||||
var plugin = new PreferencePanel("Ajax.org", main.consumes, {
|
||||
caption: "Plugin Explorer",
|
||||
className: "plugins",
|
||||
form: false,
|
||||
noscroll: true,
|
||||
index: 200,
|
||||
visible: ENABLED,
|
||||
});
|
||||
var emit = plugin.getEmitter();
|
||||
|
||||
var model;
|
||||
var datagrid;
|
||||
var filterbox;
|
||||
var btnInstall;
|
||||
var btnUninstall;
|
||||
var btnServices;
|
||||
var btnReadme;
|
||||
var btnReloadLast;
|
||||
var localPlugins;
|
||||
var btnSettings;
|
||||
|
||||
var loaded = false;
|
||||
function load() {
|
||||
if (loaded) return false;
|
||||
loaded = true;
|
||||
|
||||
menus.addItemByPath("Tools/~", new ui.divider(), 100000, plugin);
|
||||
menus.addItemByPath("Tools/Developer", null, 100100, plugin);
|
||||
|
||||
if (!DEBUG) {
|
||||
menus.addItemByPath("Tools/Developer/Start in Debug Mode", new ui.item({
|
||||
onclick: function() {
|
||||
var url = location.href + (location.href.indexOf("?") > -1
|
||||
? "&debug=2"
|
||||
: "?debug=2");
|
||||
util.openNewWindow(url);
|
||||
}
|
||||
}), 900, plugin);
|
||||
}
|
||||
if (!ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
commands.addCommand({
|
||||
name: "openPluginManager",
|
||||
group: "Plugins",
|
||||
exec: function() {
|
||||
commands.exec("openpreferences", null, { panel: plugin });
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
menus.addItemByPath("Tools/Developer/Open Plugin Explorer", new ui.item({
|
||||
command: "openPluginManager"
|
||||
}), 1100, plugin);
|
||||
|
||||
if (DEBUG) {
|
||||
notify("<div class='c9-readonly'>You are in <span style='color:rgb(245, 234, 15)'>Debug</span> Mode. "
|
||||
+ "<button id='.pm_btn1'>Open Plugin Explorer</button>"
|
||||
+ "<button id='.pm_btn2' style='float:right'>Reload last Plugin</button>",
|
||||
false);
|
||||
|
||||
document.getElementById(".pm_btn1").onclick = function() { commands.exec("openPluginManager") };
|
||||
btnReloadLast = document.getElementById(".pm_btn2");
|
||||
btnReloadLast.onclick = function() { commands.exec("reloadLastPlugin") };
|
||||
updateReloadLastButton();
|
||||
|
||||
pluginManager.readAvailablePlugins(function(err, available) {
|
||||
if (err) return console.error(err);
|
||||
localPlugins = available;
|
||||
reloadModel();
|
||||
if (sessionStorage.localPackages) {
|
||||
pluginManager.loadPackage(
|
||||
util.safeParseJson(sessionStorage.localPackages) || []
|
||||
);
|
||||
}
|
||||
var updateSessionStorage = function() {
|
||||
var packages = pluginManager.packages;
|
||||
sessionStorage.localPackages = JSON.stringify(Object.keys(packages).map(function(x) {
|
||||
if (packages[x] && packages[x].fromVfs && packages[x].enabled)
|
||||
return packages[x].filePath;
|
||||
}).filter(Boolean));
|
||||
};
|
||||
pluginManager.on("enablePackage", updateSessionStorage);
|
||||
pluginManager.on("disablePackage", updateSessionStorage);
|
||||
});
|
||||
|
||||
commands.addCommand({
|
||||
name: "reloadLastPlugin",
|
||||
bindKey: { mac: "F4", win: "F4" },
|
||||
hint: "reload plugin last reloaded in plugin manager",
|
||||
exec: function() {
|
||||
var names = getLastReloaded();
|
||||
if (!names)
|
||||
return commands.exec("openPluginManager", null, { panel: plugin });
|
||||
reload(names);
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
menus.addItemByPath("Tools/Developer/Reload Last Plugin", new ui.item({
|
||||
command: "reloadLastPlugin",
|
||||
isAvailable: getLastReloaded
|
||||
}), 1300, plugin);
|
||||
}
|
||||
|
||||
menus.addItemByPath("File/New Plugin", null, 210, plugin);
|
||||
Object.keys(TEMPLATES).forEach(function(name) {
|
||||
menus.addItemByPath("File/New Plugin/" + TEMPLATES[name], new ui.item({
|
||||
onclick: function() {
|
||||
pluginManager.createNewPlugin(name);
|
||||
}
|
||||
}), 210, plugin);
|
||||
});
|
||||
}
|
||||
|
||||
var drawn;
|
||||
function draw(e) {
|
||||
if (drawn) return;
|
||||
drawn = true;
|
||||
|
||||
function scheduleReloadModel() {
|
||||
if (scheduleReloadModel.timer) return;
|
||||
scheduleReloadModel.timer = setTimeout(function() {
|
||||
scheduleReloadModel.timer = null;
|
||||
reloadModel();
|
||||
});
|
||||
}
|
||||
ext.on("register", scheduleReloadModel);
|
||||
pluginManager.on("change", scheduleReloadModel);
|
||||
pluginManager.on("enablePackage", scheduleReloadModel);
|
||||
pluginManager.on("disablePackage", scheduleReloadModel);
|
||||
|
||||
ui.insertCss(require("text!./style.css"), plugin);
|
||||
|
||||
model = new TreeData();
|
||||
model.emptyMessage = "No plugins found";
|
||||
|
||||
model.columns = [{
|
||||
caption: "Name",
|
||||
value: "name",
|
||||
width: "250",
|
||||
type: "tree"
|
||||
}, {
|
||||
caption: "Startup Time",
|
||||
// value: "time",
|
||||
width: "100",
|
||||
getText: function(p) {
|
||||
if (p.time !== undefined)
|
||||
return (p.time || 0) + "ms";
|
||||
|
||||
var total = 0;
|
||||
function recur(p) {
|
||||
if (p.time != undefined)
|
||||
return total += p.time;
|
||||
if (p.items)
|
||||
p.items.forEach(recur);
|
||||
}
|
||||
recur(p);
|
||||
return (p.time = total) + "ms";
|
||||
}
|
||||
}, {
|
||||
caption: "Enabled",
|
||||
value: "enabled",
|
||||
width: "100"
|
||||
}];
|
||||
model.columns = null;
|
||||
|
||||
layout.on("eachTheme", function(e) {
|
||||
var height = parseInt(ui.getStyleRule(".bar-preferences .blackdg .tree-row", "height"), 10) || 24;
|
||||
model.rowHeightInner = height;
|
||||
model.rowHeight = height;
|
||||
|
||||
if (e.changed) datagrid.resize(true);
|
||||
});
|
||||
|
||||
architectApp.on("ready-additional", function() {
|
||||
reloadModel();
|
||||
});
|
||||
reloadModel();
|
||||
|
||||
var hbox = new ui.hbox({
|
||||
htmlNode: e.html,
|
||||
padding: 5,
|
||||
edge: "10 10 0 10",
|
||||
childNodes: [
|
||||
filterbox = new apf.codebox({
|
||||
realtime: true,
|
||||
skin: "codebox",
|
||||
"class": "dark",
|
||||
clearbutton: true,
|
||||
focusselect: true,
|
||||
height: 27,
|
||||
width: 250,
|
||||
singleline: true,
|
||||
"initial-message": "Search installed plugins"
|
||||
}),
|
||||
btnReadme = new ui.button({
|
||||
skin: "c9-toolbarbutton-glossy",
|
||||
caption: "Readme",
|
||||
class: "serviceButton",
|
||||
onclick: function() {
|
||||
mode = "readme";
|
||||
scheduleRedraw();
|
||||
}
|
||||
}),
|
||||
btnServices = new ui.button({
|
||||
skin: "c9-toolbarbutton-glossy",
|
||||
caption: "services",
|
||||
class: "serviceButton",
|
||||
onclick: function() {
|
||||
mode = "services";
|
||||
scheduleRedraw();
|
||||
}
|
||||
}),
|
||||
new ui.filler({}),
|
||||
btnInstall = new ui.button({
|
||||
skin: "c9-toolbarbutton-glossy",
|
||||
caption: "Enable",
|
||||
class: "btn-red",
|
||||
onclick: function() {
|
||||
reloadGridSelection(true);
|
||||
}
|
||||
}),
|
||||
btnUninstall = new ui.button({
|
||||
skin: "c9-toolbarbutton-glossy",
|
||||
caption: "Disable",
|
||||
class: "btn-red",
|
||||
onclick: function() {
|
||||
reloadGridSelection(false);
|
||||
}
|
||||
}),
|
||||
new ui.button({
|
||||
skin: "c9-toolbarbutton-glossy",
|
||||
caption: "Reload",
|
||||
onclick: function() {
|
||||
reloadGridSelection();
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
var treeBar;
|
||||
var descriptionBar;
|
||||
var hboxInner = new ui.hsplitbox({
|
||||
anchor: "0 0 0 0",
|
||||
htmlNode: e.html,
|
||||
class: "bar-preferences",
|
||||
splitter: true,
|
||||
childNodes: [
|
||||
treeBar = new ui.bar({ width: 250 }),
|
||||
descriptionBar = new ui.bar({ textselect: true }),
|
||||
]
|
||||
});
|
||||
|
||||
var div = treeBar.$ext.appendChild(document.createElement("div"));
|
||||
div.style.position = "absolute";
|
||||
div.style.left = "0px";
|
||||
div.style.right = "0px";
|
||||
div.style.bottom = "0px";
|
||||
div.style.top = "0px";
|
||||
hboxInner.$ext.style.position = "absolute";
|
||||
hboxInner.$ext.style.left = "10px";
|
||||
hboxInner.$ext.style.right = "10px";
|
||||
hboxInner.$ext.style.bottom = "10px";
|
||||
hboxInner.$ext.style.top = "50px";
|
||||
|
||||
datagrid = new Tree(div);
|
||||
datagrid.setTheme({ cssClass: "blackdg" });
|
||||
datagrid.setDataProvider(model);
|
||||
|
||||
layout.on("resize", function() { datagrid.resize() }, plugin);
|
||||
|
||||
function setTheme(e) {
|
||||
filterbox.setAttribute("class",
|
||||
e.theme.indexOf("dark") > -1 ? "dark" : "");
|
||||
}
|
||||
layout.on("themeChange", setTheme);
|
||||
setTheme({ theme: settings.get("user/general/@skin") });
|
||||
|
||||
filterbox.ace.commands.addCommands([
|
||||
{
|
||||
bindKey: "Enter",
|
||||
exec: function() { }
|
||||
}, {
|
||||
bindKey: "Esc",
|
||||
exec: function(ace) { ace.setValue(""); }
|
||||
}
|
||||
]);
|
||||
|
||||
filterbox.ace.on("input", function(e) {
|
||||
applyFilter();
|
||||
});
|
||||
|
||||
// when tab is restored datagrids size might be wrong
|
||||
// todo: remove this when apf bug is fixed
|
||||
datagrid.once("mousemove", function() {
|
||||
datagrid.resize(true);
|
||||
});
|
||||
|
||||
datagrid.on("changeSelection", scheduleRedraw);
|
||||
model.on("change", scheduleRedraw);
|
||||
|
||||
plugin.on("reloadModel", scheduleRedraw);
|
||||
|
||||
model.getCheckboxHTML = function(node) {
|
||||
var enabled = node.enabled;
|
||||
if (enabled == null || node.isGroup) return "";
|
||||
return "<span class='checkbox "
|
||||
+ (node.loading ? "loading" : "")
|
||||
+ (enabled == -1
|
||||
? "half-checked "
|
||||
: (enabled ? "checked " : ""))
|
||||
+ "'></span>";
|
||||
};
|
||||
|
||||
var mode = "services";
|
||||
var readmeCache = {};
|
||||
function renderDetails() {
|
||||
var items = datagrid.selection.getSelectedNodes();
|
||||
var hasEnabled = 0;
|
||||
var hasDisabled = 0;
|
||||
items.forEach(function(x) {
|
||||
if (x.enabled != 0)
|
||||
hasEnabled = true;
|
||||
if (x.enabled != 1)
|
||||
hasDisabled = true;
|
||||
});
|
||||
btnUninstall.setProperty("visible", hasEnabled);
|
||||
btnInstall.setProperty("visible", hasDisabled);
|
||||
|
||||
if (mode == "services") {
|
||||
renderServiceDetails(items);
|
||||
btnServices.$ext.classList.add("serviceButtonActive");
|
||||
btnReadme.$ext.classList.remove("serviceButtonActive");
|
||||
}
|
||||
else if (mode == "readme") {
|
||||
renderReadmeDetails(items);
|
||||
btnReadme.$ext.classList.add("serviceButtonActive");
|
||||
btnServices.$ext.classList.remove("serviceButtonActive");
|
||||
}
|
||||
else {
|
||||
descriptionBar.$ext.innerHTML = "";
|
||||
btnReadme.$ext.classList.remove("serviceButtonActive");
|
||||
btnServices.$ext.classList.remove("serviceButtonActive");
|
||||
}
|
||||
|
||||
if (items.length == 1 && items[0].__error) {
|
||||
var errorContainer = document.createElement("div");
|
||||
errorContainer.style.cssText = "padding: 5px; white-space: pre-wrap";
|
||||
errorContainer.textContent = items[0].__error.message;
|
||||
descriptionBar.$ext.insertBefore(errorContainer, descriptionBar.$ext.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
function renderReadmeDetails(items) {
|
||||
if (items.length > 1) {
|
||||
descriptionBar.$ext.textContent = "Multipe items selected.";
|
||||
return;
|
||||
}
|
||||
var item = items[0];
|
||||
while (item && !item.packageConfig) {
|
||||
item = item.parent;
|
||||
}
|
||||
if (!item) {
|
||||
descriptionBar.$ext.textContent = "Readme is not available.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (readmeCache[item.name]) {
|
||||
var div = document.createElement("div");
|
||||
div.textContent = readmeCache[item.name];
|
||||
div.style.cssText = "padding: 5px; white-space: pre-wrap";
|
||||
descriptionBar.$ext.textContent = "";
|
||||
descriptionBar.$ext.appendChild(div);
|
||||
return;
|
||||
}
|
||||
descriptionBar.$ext.textContent = "Loading...";
|
||||
if (item.packageConfig.filePath) {
|
||||
var parts = item.packageConfig.filePath.split("/");
|
||||
parts.pop();
|
||||
parts.push("README.md");
|
||||
var path = parts.join("/");
|
||||
fs.readFile(path, function(e, v) {
|
||||
if (e)
|
||||
return readmeCache[item.name] = "Readme is not available.";
|
||||
readmeCache[item.name] = v;
|
||||
renderDetails();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderServiceDetails(items) {
|
||||
function addUnique(item, array) {
|
||||
if (array.indexOf(item) == -1) array.push(item);
|
||||
}
|
||||
|
||||
var provided = [];
|
||||
|
||||
items.forEach(function addProvides(x) {
|
||||
if (x.map) {
|
||||
Object.keys(x.map).forEach(function(n) {
|
||||
addProvides(x.map[n]);
|
||||
});
|
||||
}
|
||||
if (x.provides) {
|
||||
x.provides.forEach(function(p) {
|
||||
addUnique(p, provided);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var consumedMap = Object.create(null);
|
||||
provided.forEach(function(service) {
|
||||
consumedMap[service] = 0;
|
||||
});
|
||||
pluginManager.addAllProviders(consumedMap);
|
||||
var consumedList = Object.keys(consumedMap);
|
||||
var consumedGroups = splitToGroups(consumedList, consumedMap);
|
||||
|
||||
var dependents = Object.create(null);
|
||||
provided.forEach(function(service) {
|
||||
dependents[service] = 0;
|
||||
});
|
||||
pluginManager.addAllDependents(dependents);
|
||||
var depList = Object.keys(dependents);
|
||||
var depGroups = splitToGroups(depList, dependents);
|
||||
|
||||
function splitToGroups(list, map) {
|
||||
var groups = [];
|
||||
list.forEach(function(n) {
|
||||
var level = Math.abs(map[n]);
|
||||
if (!groups[level])
|
||||
groups[level] = [];
|
||||
groups[level].push(n);
|
||||
});
|
||||
groups = groups.filter(Boolean).slice(1);
|
||||
return groups;
|
||||
}
|
||||
|
||||
function formatServices(list, style) {
|
||||
return "[" + list.map(function(x) {
|
||||
return '<span class="serviceButton">' + escapeHTML(x) + '</span>';
|
||||
}).join(", ") + "]";
|
||||
}
|
||||
|
||||
descriptionBar.$ext.style.overflow = "auto";
|
||||
var serviceDesc = '<h1 class="pluginManagerHeader">Provided services [' + provided.length + ']</h1>\
|
||||
<p type="provided">' + (provided.length ? formatServices(provided) : "") + '</p>\
|
||||
<h1 class="pluginManagerHeader">Consumed services [' + (consumedList.length - provided.length) + ']</h1>\
|
||||
<p type="consumed">' + consumedGroups.map(formatServices).join("<br/>") + '</p>\
|
||||
<h1 class="pluginManagerHeader">Dependent services [' + (depList.length - provided.length) + ']</h1>\
|
||||
<p type="dependent">' + depGroups.map(formatServices).join("<br/>") + '</p>\
|
||||
<br/>';
|
||||
descriptionBar.$ext.innerHTML = '<div class="basic intro" \
|
||||
style="padding:12px 0 12px 12px;white-space:pre-line">\
|
||||
<p>' + (items.length == 1
|
||||
? '<span class="serviceButton">' + escapeHTML(items[0].path) + '</span>'
|
||||
: (items.length || "no") + " plugins selected") + '</p>\
|
||||
<hr></hr>'
|
||||
+ (items.length ? serviceDesc : "")
|
||||
+ '</div>';
|
||||
|
||||
}
|
||||
descriptionBar.$ext.addEventListener("click", function(e) {
|
||||
if (e.button) return;
|
||||
var el = e.target;
|
||||
var isButton = el.classList.contains("serviceButton");
|
||||
var text = el.textContent;
|
||||
var serviceToPlugin = architectApp.serviceToPlugin;
|
||||
if (e.detail == 1 && isButton && text) {
|
||||
var path = serviceToPlugin[text] ? serviceToPlugin[text].packagePath : text;
|
||||
var node = function search(node) {
|
||||
if (node.path == path)
|
||||
return node;
|
||||
if (node.items) {
|
||||
for (var i = 0; i < node.items.length; i++) {
|
||||
var result = search(node.items[i]);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}(model.cachedRoot);
|
||||
|
||||
if (node)
|
||||
datagrid.reveal(node);
|
||||
}
|
||||
});
|
||||
var hoverDetails = { hovered: "", highlighted: "" };
|
||||
descriptionBar.$ext.addEventListener("mousemove", function(e) {
|
||||
if (e.button) return;
|
||||
var el = e.target;
|
||||
var isButton = el.classList.contains("serviceButton");
|
||||
var text = el.textContent;
|
||||
hoverDetails.parent = el.parentNode;
|
||||
hoverDetails.hovered = isButton ? text : "";
|
||||
hoverDetails.type = isButton ? el.parentNode.getAttribute("type") : "";
|
||||
if (hoverDetails.hovered != hoverDetails.highlighted)
|
||||
requestAnimationFrame(updateHighlights);
|
||||
});
|
||||
function updateHighlights() {
|
||||
if (hoverDetails.hovered == hoverDetails.highlighted) return;
|
||||
var serviceToPlugin = architectApp.serviceToPlugin;
|
||||
if (!serviceToPlugin) return;
|
||||
|
||||
var nodes = descriptionBar.$ext.querySelectorAll(".serviceButton");
|
||||
|
||||
var deps = Object.create(null);
|
||||
deps[hoverDetails.hovered] = 0;
|
||||
pluginManager.addAllDependents(deps);
|
||||
pluginManager.addAllProviders(deps);
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
var val = node.textContent;
|
||||
var highlight1 = false;
|
||||
var highlight2 = false;
|
||||
if (hoverDetails.type == "dependent") {
|
||||
if (hoverDetails.parent == node.parentNode || node.parentNode.getAttribute("type") == "provided") {
|
||||
highlight1 = deps[val] < 0;
|
||||
highlight2 = deps[val] > 0;
|
||||
}
|
||||
} else if (hoverDetails.type == "consumed") {
|
||||
if (hoverDetails.parent == node.parentNode || node.parentNode.getAttribute("type") == "provided") {
|
||||
highlight1 = deps[val] > 0;
|
||||
highlight2 = deps[val] < 0;
|
||||
}
|
||||
}
|
||||
|
||||
nodes[i].style.borderBottom = highlight1 ? "1px solid" : "";
|
||||
if (!highlight1) {
|
||||
nodes[i].style.borderBottom = highlight2 ? "1px dashed rgba(125, 125, 125, 0.9)" : "";
|
||||
}
|
||||
}
|
||||
hoverDetails.highlighted = hoverDetails.hovered;
|
||||
}
|
||||
|
||||
function scheduleRedraw() {
|
||||
window.requestAnimationFrame(renderDetails);
|
||||
}
|
||||
|
||||
var mnuCtxTree = new ui.menu({
|
||||
id: "mnuChat",
|
||||
}, plugin);
|
||||
menus.decorate(mnuCtxTree);
|
||||
plugin.addElement(mnuCtxTree);
|
||||
|
||||
|
||||
btnSettings = new ui.button({
|
||||
skin: "header-btn",
|
||||
class: "panel-settings",
|
||||
submenu: mnuCtxTree
|
||||
});
|
||||
treeBar.appendChild(btnSettings);
|
||||
datagrid.renderer.on("scrollbarVisibilityChanged", updateScrollBarSize);
|
||||
function updateScrollBarSize() {
|
||||
var scrollBarV = datagrid.renderer.scrollBarV;
|
||||
var w = scrollBarV.isVisible ? scrollBarV.getWidth() : 0;
|
||||
btnSettings.$ext.style.marginRight = Math.max(w - 2, 0) + "px";
|
||||
}
|
||||
|
||||
menus.addItemByPath("context/pluginManager/", mnuCtxTree, 0, plugin);
|
||||
menus.addItemByPath("context/pluginManager/Reveal in File Tree", new ui.item({
|
||||
isAvailable: function() {
|
||||
var selected = datagrid.selection.getCursor();
|
||||
return selected && selected.packageConfig && selected.packageConfig.filePath
|
||||
|| c9.sourceDir && selected && selected.path;
|
||||
},
|
||||
onclick: function() {
|
||||
var selected = datagrid.selection.getCursor();
|
||||
var tabbehavior = architectApp.services.tabbehavior;
|
||||
var filePath = selected.packageConfig && selected.packageConfig.filePath;
|
||||
if (!filePath && c9.sourceDir)
|
||||
filePath = c9.sourceDir + "/" + selected.path + (selected.items ? "" : ".js");
|
||||
if (filePath)
|
||||
tabbehavior.revealtab({ path: util.normalizePath(filePath) });
|
||||
else
|
||||
showInfo("Path is not available.");
|
||||
},
|
||||
}), plugin);
|
||||
menus.addItemByPath("context/pluginManager/Refresh List", new ui.item({
|
||||
onclick: function() {
|
||||
pluginManager.readAvailablePlugins(function(err, available) {
|
||||
if (err) return console.error(err);
|
||||
localPlugins = available;
|
||||
reloadModel();
|
||||
});
|
||||
},
|
||||
}), plugin);
|
||||
menus.addItemByPath("context/pluginManager/~", new ui.divider({}), plugin);
|
||||
menus.addItemByPath("context/pluginManager/Disable", new ui.item({
|
||||
isAvailable: function() {
|
||||
var selected = datagrid.selection.getCursor();
|
||||
return selected && selected.enabled != 0;
|
||||
},
|
||||
onclick: function() { reloadGridSelection(false); },
|
||||
}), plugin);
|
||||
menus.addItemByPath("context/pluginManager/Enable", new ui.item({
|
||||
isAvailable: function() {
|
||||
var selected = datagrid.selection.getCursor();
|
||||
return selected && selected.enabled != 1;
|
||||
},
|
||||
onclick: function() { reloadGridSelection(true); },
|
||||
}), plugin);
|
||||
menus.addItemByPath("context/pluginManager/Reload", new ui.item({
|
||||
isAvailable: function() {
|
||||
var selected = datagrid.selection.getCursor();
|
||||
return selected;
|
||||
},
|
||||
onclick: function() { reloadGridSelection(); },
|
||||
}), plugin);
|
||||
treeBar.setAttribute("contextmenu", mnuCtxTree);
|
||||
|
||||
model.on("toggleCheckbox", function(e) {
|
||||
reloadGridSelection(!e.target.enabled, e.selectedNodes || [e.target]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
function reloadModel() {
|
||||
if (!model) return;
|
||||
|
||||
var packages = pluginManager.packages;
|
||||
|
||||
if (!CORE.pluginManagerUi) {
|
||||
CORE.pluginManagerUi = 1;
|
||||
pluginManager.addAllProviders(CORE);
|
||||
Object.keys(CORE).forEach(function(n) {
|
||||
if (architectApp.serviceToPlugin[n])
|
||||
CORE[architectApp.serviceToPlugin[n].packagePath] = 1;
|
||||
});
|
||||
}
|
||||
|
||||
var GROUPS = {
|
||||
// "changed": "Recently Changed",
|
||||
"remote": "Remote Plugins",
|
||||
"vfs": "Locally Installed Plugins",
|
||||
"pre": "Pre-installed Plugins",
|
||||
"core": "Core Plugins",
|
||||
};
|
||||
|
||||
var groups = model.groups || Object.create(null);
|
||||
if (!model.groups) {
|
||||
var root = [];
|
||||
model.cachedRoot = { items: root };
|
||||
model.groups = groups;
|
||||
Object.keys(GROUPS).forEach(function(name) {
|
||||
root.push(groups[name] = {
|
||||
map: Object.create(null),
|
||||
isOpen: name != "runtime",
|
||||
className: "group",
|
||||
isGroup: true,
|
||||
isType: name,
|
||||
noSelect: true,
|
||||
name: GROUPS[name]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addPlugin(plugin, node) {
|
||||
if (!plugin.provides || !plugin.consumes)
|
||||
return;
|
||||
if (plugin.packagePath) {
|
||||
var parts = plugin.packagePath.split("/");
|
||||
|
||||
var path = parts.shift();
|
||||
parts.forEach(function(p, i) {
|
||||
path = path + "/" + p;
|
||||
if (!node.map)
|
||||
node.map = Object.create(null);
|
||||
if (!node.map[p]) {
|
||||
node.map[p] = {
|
||||
path: path,
|
||||
parent: node,
|
||||
};
|
||||
}
|
||||
node.map[p].name = p;
|
||||
if (i == parts.length - 1) {
|
||||
var enabled = 1;
|
||||
node.map[p].provides = plugin.provides;
|
||||
plugin.provides.forEach(function(x) {
|
||||
var service = architectApp.services[x];
|
||||
if (!service || (!service.loaded && service.unload)) {
|
||||
enabled = 0;
|
||||
}
|
||||
});
|
||||
node.map[p].enabled = enabled;
|
||||
}
|
||||
node = node.map[p];
|
||||
node.className = plugin.__error ? "load-error" : "";
|
||||
node.__error = plugin.__error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addPackage(name) {
|
||||
var pkg = packages[name];
|
||||
var parent = pkg.filePath ? groups.vfs : groups.remote;
|
||||
|
||||
var node = parent.map[name] = parent.map[name] || {
|
||||
path: "plugins/" + name,
|
||||
name: name,
|
||||
enabled: 0,
|
||||
parent: parent,
|
||||
};
|
||||
|
||||
node.packageConfig = pkg;
|
||||
node.className = pkg.__error ? "load-error" : "";
|
||||
node.__error = pkg.__error;
|
||||
node.loading = pkg.loading;
|
||||
}
|
||||
|
||||
architectApp.config.forEach(function(plugin) {
|
||||
var node = CORE[plugin.packagePath] ? groups.core : groups.pre;
|
||||
addPlugin(plugin, node);
|
||||
});
|
||||
|
||||
if (localPlugins) {
|
||||
localPlugins.forEach(function(name) {
|
||||
if (!packages[name]) {
|
||||
packages[name] = {
|
||||
name: name,
|
||||
filePath: "~/.c9/plugins/" + name + "/package.json",
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(packages).forEach(function(n) {
|
||||
var pkg = packages[n];
|
||||
var node = pkg.filePath ? groups.vfs : groups.remote;
|
||||
|
||||
addPackage(n);
|
||||
|
||||
if (pkg.c9 && pkg.c9.plugins) {
|
||||
pkg.c9.plugins.forEach(function(plugin) {
|
||||
addPlugin(plugin, node);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function flatten(node, index) {
|
||||
if (node.map) {
|
||||
node.items = node.children = Object.keys(node.map).map(function(x) {
|
||||
return node.map[x];
|
||||
});
|
||||
}
|
||||
if (node.items) {
|
||||
node.items.forEach(flatten);
|
||||
if (node.items.length == 1 && !node.isGroup) {
|
||||
var other = node.items[0];
|
||||
if (node.parent && node.parent.items[index] == node) {
|
||||
node.parent.items[index] = other;
|
||||
other.name = node.name + "/" + other.name;
|
||||
other.packageConfig = node.packageConfig;
|
||||
other.filePath = node.filePath;
|
||||
other.url = node.url;
|
||||
other.loading = node.loading;
|
||||
}
|
||||
}
|
||||
if (!node.isGroup) {
|
||||
node.enabled = null;
|
||||
node.items.some(function(i) {
|
||||
if (node.enabled == null) {
|
||||
node.enabled = i.enabled;
|
||||
}
|
||||
if (i.enabled != node.enabled) {
|
||||
node.enabled = -1;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flatten(model.cachedRoot);
|
||||
|
||||
applyFilter();
|
||||
|
||||
emit("reloadModel");
|
||||
}
|
||||
|
||||
function applyFilter() {
|
||||
model.keyword = filterbox && filterbox.getValue();
|
||||
|
||||
if (!model.keyword) {
|
||||
model.reKeyword = null;
|
||||
model.setRoot(model.cachedRoot);
|
||||
|
||||
// model.isOpen = function(node) { return node.isOpen; }
|
||||
}
|
||||
else {
|
||||
model.reKeyword = new RegExp("("
|
||||
+ util.escapeRegExp(model.keyword) + ")", 'i');
|
||||
var root = search.treeSearch(model.cachedRoot.items, model.keyword, true);
|
||||
model.setRoot(root);
|
||||
|
||||
// model.isOpen = function(node) { return true; };
|
||||
}
|
||||
}
|
||||
|
||||
function reload(names) {
|
||||
var nodes = names.split(/\s*,\s*/).map(function(name) {
|
||||
if (pluginManager.packages[name])
|
||||
return { packageConfig: pluginManager.packages[name] };
|
||||
return { path: name };
|
||||
});
|
||||
|
||||
reloadGridSelection(null, nodes);
|
||||
}
|
||||
|
||||
function reloadGridSelection(mode, nodes) {
|
||||
if (!nodes)
|
||||
nodes = datagrid.selection.getSelectedNodes();
|
||||
|
||||
var reloadLast = pluginManager.reload(nodes, mode);
|
||||
if (reloadLast.length) {
|
||||
var href = document.location.href.replace(/[?&]reload=[^&]+/, "");
|
||||
href += (href.match(/\?/) ? "&" : "?") + "reload=" + reloadLast.join(",");
|
||||
window.history.replaceState(window.history.state, null, href);
|
||||
if (mode !== false) {
|
||||
showReloadTip(reloadLast.join(","), mode);
|
||||
updateReloadLastButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateReloadLastButton() {
|
||||
var last = getLastReloaded();
|
||||
if (last) {
|
||||
btnReloadLast.visible = true;
|
||||
btnReloadLast.textContent = "Reload " + last;
|
||||
} else {
|
||||
btnReloadLast.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
function showReloadTip(name, mode) {
|
||||
if (options.devel) {
|
||||
var key = commands.getPrettyHotkey("reloadLastPlugin");
|
||||
if (!getLastReloaded()) {
|
||||
showInfo("Loaded " + name + ". Press " + key + " to reload again.", 3000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
showInfo("Loaded " + name + " for the duration of current browser session.", 3000);
|
||||
}
|
||||
|
||||
function getLastReloaded() {
|
||||
return qs.parse(document.location.search.substr(1)).reload;
|
||||
}
|
||||
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("load", function() {
|
||||
load();
|
||||
});
|
||||
plugin.on("draw", function(e) {
|
||||
draw(e);
|
||||
});
|
||||
plugin.on("activate", function(e) {
|
||||
datagrid && datagrid.resize();
|
||||
});
|
||||
plugin.on("resize", function(e) {
|
||||
datagrid && datagrid.resize();
|
||||
});
|
||||
plugin.on("enable", function() {
|
||||
|
||||
});
|
||||
plugin.on("disable", function() {
|
||||
|
||||
});
|
||||
plugin.on("unload", function() {
|
||||
loaded = false;
|
||||
drawn = false;
|
||||
btnServices = null;
|
||||
btnReadme = null;
|
||||
btnReloadLast = null;
|
||||
model = null;
|
||||
datagrid = null;
|
||||
filterbox = null;
|
||||
btnInstall = null;
|
||||
btnUninstall = null;
|
||||
localPlugins = null;
|
||||
});
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
plugin.freezePublicAPI({
|
||||
|
||||
/*
|
||||
* @ignore
|
||||
*/
|
||||
get datagrid() { return datagrid; },
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"pluginManagerUi": plugin,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,196 +0,0 @@
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Plugin", "proc", "c9", "pubsub", "auth", "util", "installer",
|
||||
"preferences.experimental"
|
||||
];
|
||||
main.provides = ["plugin.installer"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports.Plugin;
|
||||
var c9 = imports.c9;
|
||||
var util = imports.util;
|
||||
var proc = imports.proc;
|
||||
var auth = imports.auth;
|
||||
var pubsub = imports.pubsub;
|
||||
var installer = imports.installer;
|
||||
var experimental = imports["preferences.experimental"];
|
||||
|
||||
var async = require("async");
|
||||
|
||||
var escapeShell = util.escapeShell;
|
||||
var updates = options.updates;
|
||||
var architect;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
var emit = plugin.getEmitter();
|
||||
|
||||
var DEBUG_MODE = c9.location.indexOf("debug=2") > -1;
|
||||
var HASSDK = DEBUG_MODE || experimental.addExperiment("sdk", false, "SDK/Load Custom Plugins");
|
||||
|
||||
var installing;
|
||||
|
||||
var loaded = false;
|
||||
function load() {
|
||||
if (loaded) return false;
|
||||
loaded = true;
|
||||
|
||||
if (!HASSDK) return;
|
||||
|
||||
pubsub.on("message", function(message) {
|
||||
if (message.type != "package")
|
||||
return;
|
||||
|
||||
console.log("PubSub package API message", message);
|
||||
var action = message.action;
|
||||
var body = message.body;
|
||||
|
||||
// Only accept packages that are installed for this project
|
||||
if (body.pid && body.pid != c9.projectId)
|
||||
return;
|
||||
|
||||
// Only accept packages that are installed for this user
|
||||
if (body.uid && body.uid != c9.uid)
|
||||
return;
|
||||
|
||||
if (action == "install") {
|
||||
installPlugins([body.config], function() {});
|
||||
}
|
||||
else if (action == "uninstall") {
|
||||
uninstallPlugin(body.name, function() {});
|
||||
}
|
||||
});
|
||||
|
||||
installPlugins(updates);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
function installPlugins(config, callback) {
|
||||
// if (!vfs.connected) {
|
||||
// vfs.once("connect", loadPackages.bind(this, config));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (!config.length)
|
||||
return callback && callback();
|
||||
|
||||
// Only run one installer at a time
|
||||
if (installing) {
|
||||
return plugin.once("finished", function() {
|
||||
installPlugins(config, callback);
|
||||
});
|
||||
}
|
||||
|
||||
installing = true;
|
||||
|
||||
var found = {}, packages = [];
|
||||
config.forEach(function(item) {
|
||||
if (typeof item === "string") {
|
||||
item = { name: item, version: null };
|
||||
}
|
||||
|
||||
if (found[item.name]) return;
|
||||
found[item.name] = true;
|
||||
|
||||
packages.push({ name: item.name, version: item.version });
|
||||
});
|
||||
|
||||
async.eachSeries(packages, function(pkg, next) {
|
||||
installPlugin(pkg.name, pkg.version, next);
|
||||
}, function(err) {
|
||||
installing = false;
|
||||
emit("finished");
|
||||
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
architect.loadAdditionalPlugins(config, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function installPlugin(name, version, callback) {
|
||||
// Headless installation of the plugin
|
||||
installer.createSession(name, version, function(session, options) {
|
||||
var cmd = [
|
||||
"c9",
|
||||
"install",
|
||||
"--local",
|
||||
"--force",
|
||||
"--accessToken=" + auth.accessToken,
|
||||
];
|
||||
|
||||
if (version == null)
|
||||
cmd.push(escapeShell(name));
|
||||
else
|
||||
cmd.push(escapeShell(name + "@" + version));
|
||||
|
||||
session.install({
|
||||
"bash": cmd.join(" ")
|
||||
});
|
||||
|
||||
// Force to start immediately
|
||||
session.start(callback, true);
|
||||
}, function() {}, 2); // Force to not be administered
|
||||
}
|
||||
|
||||
function uninstallPlugin(name, callback) {
|
||||
// Headless uninstallation of the plugin
|
||||
installer.createSession(name, -1, function(session, options) {
|
||||
session.install({
|
||||
"bash": "c9 remove --local --force --accessToken=" + auth.accessToken
|
||||
+ " " + escapeShell(name)
|
||||
});
|
||||
|
||||
// Force to start immediately
|
||||
session.start(callback, true);
|
||||
}, function() {}, 2); // Force to not be administered
|
||||
}
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("load", function() {
|
||||
load();
|
||||
});
|
||||
plugin.on("unload", function() {
|
||||
loaded = false;
|
||||
installing = false;
|
||||
});
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
plugin.freezePublicAPI({
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get architect() { throw new Error(); },
|
||||
set architect(v) { architect = v; },
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
installPlugins: installPlugins,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
installPlugin: installPlugin,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
uninstallPlugin: uninstallPlugin
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"plugin.installer": plugin
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,340 +0,0 @@
|
||||
/*global requirejs*/
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Plugin", "vfs", "c9", "plugin.installer", "fs", "auth",
|
||||
"preferences.experimental"
|
||||
];
|
||||
main.provides = ["plugin.loader"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports.Plugin;
|
||||
var vfs = imports.vfs;
|
||||
var c9 = imports.c9;
|
||||
var fs = imports.fs;
|
||||
var auth = imports.auth;
|
||||
var installer = imports["plugin.installer"];
|
||||
var experimental = imports["preferences.experimental"];
|
||||
|
||||
var dirname = require("path").dirname;
|
||||
var join = require("path").join;
|
||||
var async = require("async");
|
||||
var _ = require("lodash");
|
||||
|
||||
var architect;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
// var emit = plugin.getEmitter();
|
||||
|
||||
var DEBUG_MODE = c9.location.indexOf("debug=2") > -1;
|
||||
var ENABLED = DEBUG_MODE || experimental.addExperiment("plugins", false, "SDK/Load Plugins From Workspace");
|
||||
var HASSDK = DEBUG_MODE || experimental.addExperiment("sdk", false, "SDK/Load Custom Plugins");
|
||||
|
||||
var plugins = options.plugins;
|
||||
var loadFromDisk = options.loadFromDisk;
|
||||
|
||||
var names = [];
|
||||
|
||||
function load() {
|
||||
if (!HASSDK) return;
|
||||
if (!ENABLED) return;
|
||||
|
||||
loadPlugins(plugins);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
// TODO the resolution alghoritm used here is very inefficient
|
||||
// ideally we will use a simpler method that doesn't need to scan directories
|
||||
function loadPlugins(loaderConfig) {
|
||||
if (!vfs.connected) {
|
||||
vfs.once("connect", loadPlugins.bind(this, loaderConfig));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loaderConfig.length && !loadFromDisk)
|
||||
return;
|
||||
|
||||
listAllPackages(function(err, resolved) {
|
||||
if (err) return console.error(err);
|
||||
|
||||
var extraPackages = {};
|
||||
// convert old format from db to the new one
|
||||
loaderConfig.forEach(function(p) {
|
||||
if (!extraPackages[p.packageName]) {
|
||||
var path = "plugins/" + p.packageName;
|
||||
extraPackages[path] = {
|
||||
apikey: p.apikey,
|
||||
packagePath: path,
|
||||
version: p.version,
|
||||
name: p.packageName
|
||||
};
|
||||
}
|
||||
});
|
||||
if (!loadFromDisk) {
|
||||
// filter packages by config instead of loading
|
||||
// everything from disk
|
||||
resolved = resolved.filter(function(config) {
|
||||
if (extraPackages[config.packagePath])
|
||||
return true;
|
||||
|
||||
console.warn("[c9.ide.loader] Not loading package "
|
||||
+ config.path + " because it is not installed, "
|
||||
+ "according to the database");
|
||||
return false;
|
||||
});
|
||||
}
|
||||
resolved.filter(function(config) {
|
||||
if (extraPackages[config.packagePath]) {
|
||||
_.assign(config, extraPackages[config.packagePath], function(x, y) { return x || y; });
|
||||
delete extraPackages[config.packagePath];
|
||||
}
|
||||
});
|
||||
Object.keys(extraPackages).forEach(function(packagePath) {
|
||||
console.warn("[c9.ide.loader] Package "
|
||||
+ packagePath + " should be installed, according "
|
||||
+ "to the database, but was not found on the filesystem. "
|
||||
+ "Try reinstalling it.");
|
||||
});
|
||||
|
||||
async.each(resolved, loadPackage, function(err) {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List all packages on disk by scanning `~/.c9` and resolve the
|
||||
* detected packages by order of override priority:
|
||||
*
|
||||
* - Developer plugins in `~/.c9/dev/plugins` have the highest
|
||||
* priority to allow local development of new functionality without
|
||||
* the risk of having your changes overwritten by any update
|
||||
* mechanism.
|
||||
*
|
||||
* - Managed plugins in `~/.c9/managed/plugins` are pre-installed and
|
||||
* updated by the Cloud9 system and have a higher priority that
|
||||
* possibly outdated or unknown packages installed by the user.
|
||||
*
|
||||
* - User-installed in `~/.c9/plugins` plugins installed plugins are
|
||||
* the default priority have the lowest priority.
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
*/
|
||||
function listAllPackages(callback) {
|
||||
async.parallel({
|
||||
"plugins": async.apply(listPackages, "~/.c9/plugins"),
|
||||
"managed": async.apply(listPackages, "~/.c9/managed/plugins"),
|
||||
"dev": async.apply(listPackages, "~/.c9/dev/plugins"),
|
||||
}, function(err, packages) {
|
||||
if (err && err.code === "EDISCONNECT") {
|
||||
c9.once("connect", function() {
|
||||
listAllPackages(callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) return callback(err);
|
||||
|
||||
var resolved = {};
|
||||
|
||||
// default: ~/.c9/plugins
|
||||
packages.plugins.forEach(function(config) {
|
||||
if (!config) return;
|
||||
resolved[config.name] = config;
|
||||
});
|
||||
|
||||
// high: ~/.c9/managed/plugins
|
||||
packages.managed.forEach(function(config) {
|
||||
if (!config) return;
|
||||
resolved[config.name] = config;
|
||||
});
|
||||
|
||||
// higher: ~/.c9/dev/plugins
|
||||
packages.dev.forEach(function(config) {
|
||||
if (!config) return;
|
||||
resolved[config.name] = config;
|
||||
});
|
||||
|
||||
callback(null, _.values(resolved));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List packages in the given directory
|
||||
*
|
||||
* @param {String} dirPath Path to the directory to scan
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
* @param {Object[]} callback.packages
|
||||
*/
|
||||
function listPackages(dirPath, callback) {
|
||||
fs.readdir(dirPath, function(err, stats) {
|
||||
if (err && err.code === "ENOENT")
|
||||
return callback(null, []);
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
async.map(stats, function(stat, done) {
|
||||
// check for folder or symlink with folder target
|
||||
if (stat.mime !== "inode/directory"
|
||||
&& (stat.mime === "inode/symlink" && stat.linkStat.mime !== "inode/directory")
|
||||
) {
|
||||
return done();
|
||||
}
|
||||
|
||||
// check folers not prefixed with [._]
|
||||
if (stat.name[0] === "." || stat.name[0] === "_") {
|
||||
return done();
|
||||
}
|
||||
|
||||
// check and load package.json
|
||||
var config = {
|
||||
name: stat.name,
|
||||
path: absolutePath([dirPath, stat.name].join("/")),
|
||||
packagePath: ["plugins", stat.name].join("/"),
|
||||
staticPrefix: vfs.url([dirPath, stat.name].join("/")),
|
||||
};
|
||||
done(null, config);
|
||||
}, callback);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a the `package.json` metadata of the given package
|
||||
*
|
||||
* @param {Object} config The package configuration
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
* @param {Object} callback.metadata
|
||||
*/
|
||||
function loadPackageMetadata(config, callback) {
|
||||
fs.readfile([config.path, "package.json" ].join("/"), function(metadataStr) {
|
||||
var metadata;
|
||||
|
||||
try {
|
||||
metadata = JSON.parse(metadataStr);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
callback(null, metadata);
|
||||
}, function(err) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a the `__installed__.js` definition of the given package
|
||||
*
|
||||
* @param {Object} config The package configuration
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
* @param {Array<String|Object>} callback.installed
|
||||
*/
|
||||
function loadPackageInstalledJs(config, callback) {
|
||||
var paths = {};
|
||||
paths[config.packagePath] = config.staticPrefix;
|
||||
|
||||
requirejs.config({ paths: paths });
|
||||
requirejs.undef(config.packagePath, true);
|
||||
|
||||
require([[config.packagePath, "__installed__"].join("/")], function(installed) {
|
||||
callback(null, installed);
|
||||
}, function(err) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given package by checking its `__installed__.js` file or
|
||||
* its `package.json#plugins`, then call `Architect#loadAdditionalPlugins()`.
|
||||
*
|
||||
* @param {Object} config The package configuration
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
*/
|
||||
function loadPackage(config, callback) {
|
||||
loadPackageInstalledJs(config, function addToArchitect(err, installed) {
|
||||
var plugins = installed;
|
||||
if (err) {
|
||||
return callback(err);
|
||||
// TODO disbled since this doesn't handle bundles and breaks debug=2
|
||||
// loadPackageMetadata(config, function(err, metadata) {
|
||||
// if (err) return callback(err);
|
||||
// config.metadata = metadata;
|
||||
// var plugins = _.map(config.metadata.plugins, function(value, key) {
|
||||
// return [ "plugins", config.name, key ].join("/");
|
||||
// });
|
||||
// addToArchitect(err, plugins);
|
||||
// });
|
||||
}
|
||||
|
||||
var architectConfig = plugins.map(function(plugin) {
|
||||
if (typeof plugin == "string")
|
||||
plugin = { packagePath: plugin };
|
||||
|
||||
plugin.staticPrefix = config.staticPrefix;
|
||||
|
||||
plugin.packageName = config.name;
|
||||
plugin.packageMetadata = config.metadata;
|
||||
plugin.packageDir = config.path;
|
||||
|
||||
plugin.apikey = config.apikey;
|
||||
plugin.version = config.version;
|
||||
|
||||
return plugin;
|
||||
});
|
||||
|
||||
names.push(config.name);
|
||||
|
||||
architect.loadAdditionalPlugins(architectConfig, function(err) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function absolutePath(fromPath) {
|
||||
var toPath = fromPath.replace(/^~/, c9.home);
|
||||
return toPath;
|
||||
}
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("load", function() {
|
||||
load();
|
||||
});
|
||||
plugin.on("unload", function() {
|
||||
});
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
plugin.freezePublicAPI({
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get architect() { throw new Error(); },
|
||||
set architect(v) { architect = v; },
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get plugins() { return names; }
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"plugin.loader": plugin
|
||||
});
|
||||
}
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@ -9,32 +9,6 @@ define(function(require, exports, module) {
|
||||
oop.inherits(DataProvider, TreeData);
|
||||
|
||||
(function() {
|
||||
|
||||
this.getChildren = function(node) {
|
||||
var children = node.items;
|
||||
var ch = children && children[0] && children[0];
|
||||
if (ch) {
|
||||
var d = (node.$depth + 1) || 0;
|
||||
children.forEach(function(n) {
|
||||
n.$depth = d;
|
||||
n.parent = node;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.$sortNodes && !node.$sorted) {
|
||||
children && this.sort(children);
|
||||
}
|
||||
return children;
|
||||
};
|
||||
|
||||
// this.getRowIndent = function(p){
|
||||
// return !p.className ? 2 : p.className == "package" ? 1 : 0;
|
||||
// }
|
||||
|
||||
this.hasChildren = function(node) {
|
||||
return node.items && node.items.length;
|
||||
};
|
||||
|
||||
this.getCaptionHTML = function(node) {
|
||||
if (!node.name) return "";
|
||||
return node.name.replace(this.reKeyword, "<strong>$1</strong>");
|
||||
|
||||
@ -1,202 +0,0 @@
|
||||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"Editor", "editors", "ui", "commands", "menus", "layout",
|
||||
"tabManager", "util", "settings", "api", "c9",
|
||||
"preferences.experimental"
|
||||
];
|
||||
main.provides = ["plugin.packages"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Editor = imports.Editor;
|
||||
var editors = imports.editors;
|
||||
var tabs = imports.tabManager;
|
||||
var commands = imports.commands;
|
||||
var settings = imports.settings;
|
||||
var api = imports.api;
|
||||
var c9 = imports.c9;
|
||||
var menus = imports.menus;
|
||||
var util = imports.util;
|
||||
var layout = imports.layout;
|
||||
var ui = imports.ui;
|
||||
var experimental = imports["preferences.experimental"];
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var extensions = [];
|
||||
var packages = {};
|
||||
|
||||
var handle = editors.register("plugin.packages", "Package Browser",
|
||||
PackageBrowser, extensions);
|
||||
var emit = handle.getEmitter();
|
||||
emit.setMaxListeners(1000);
|
||||
|
||||
var DEBUG_MODE = c9.location.indexOf("debug=2") > -1;
|
||||
var HASSDK = DEBUG_MODE || experimental.addExperiment("sdk", false, "SDK/Load Custom Plugins");
|
||||
|
||||
function focusOpenPackages() {
|
||||
var pages = tabs.getTabs();
|
||||
for (var i = 0, tab = pages[i]; tab; tab = pages[i++]) {
|
||||
if (tab.editorType == "plugin.packages") {
|
||||
tabs.focusTab(tab);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle.on("load", function() {
|
||||
if (!HASSDK) return;
|
||||
|
||||
settings.on("read", function() {
|
||||
settings.setDefaults("user/general", [["animateui", true]]);
|
||||
});
|
||||
|
||||
commands.addCommand({
|
||||
name: "openpackagebrowser",
|
||||
hint: "open the package browser",
|
||||
group: "General",
|
||||
// bindKey: { mac: "Command-,", win: "Ctrl-," },
|
||||
exec: function () {
|
||||
var tab = tabs.focussedTab;
|
||||
if (tab && tab.editor.type == "plugin.packages") {
|
||||
tab.close();
|
||||
return;
|
||||
}
|
||||
if (focusOpenPackages())
|
||||
return;
|
||||
|
||||
tabs.open({
|
||||
editorType: "plugin.packages",
|
||||
active: true
|
||||
}, function() {});
|
||||
}
|
||||
}, handle);
|
||||
|
||||
// menus.addItemByPath("Cloud9/~", new ui.divider(), 1000, handle);
|
||||
// menus.addItemByPath("Cloud9/Package Browser", new ui.item({
|
||||
// command: "openpackagebrowser"
|
||||
// }), 1100, handle);
|
||||
});
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
function installPlugin(name, target, callback) {
|
||||
var config = packages[name];
|
||||
if (!config)
|
||||
return callback(new Error("Could not find plugin: " + name));
|
||||
|
||||
if (target != "project" && target != "user")
|
||||
return callback(new Error("Invalid installation target: " + target));
|
||||
|
||||
api[target].put("install/" + name, function(err, state) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
function uninstallPlugin(name, target, callback) {
|
||||
var config = packages[name];
|
||||
if (!config)
|
||||
return callback(new Error("Could not find plugin: " + name));
|
||||
|
||||
if (target != "project" && target != "user")
|
||||
return callback(new Error("Invalid installation target: " + target));
|
||||
|
||||
api[target].put("uninstall/" + name, function(err, state) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
* @extends Plugin
|
||||
* @singleton
|
||||
*/
|
||||
handle.freezePublicAPI({
|
||||
/**
|
||||
*
|
||||
*/
|
||||
installPlugin: installPlugin,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
uninstallPlugin: uninstallPlugin
|
||||
});
|
||||
|
||||
/***** Editor *****/
|
||||
|
||||
function PackageBrowser() {
|
||||
var plugin = new Editor("Ajax.org", main.consumes, extensions);
|
||||
//var emit = plugin.getEmitter();
|
||||
var tab, iframe;
|
||||
|
||||
plugin.on("resize", function(e) {
|
||||
emit("resize", e);
|
||||
});
|
||||
|
||||
plugin.on("draw", function(e) {
|
||||
tab = e.tab;
|
||||
var htmlNode = e.htmlNode;
|
||||
|
||||
htmlNode.style.paddingTop = 0;
|
||||
|
||||
iframe = htmlNode.appendChild(document.createElement("iframe"));
|
||||
iframe.style.width = "100%";
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.border = 0;
|
||||
iframe.style.backgroundColor = "#fbfbfb";
|
||||
|
||||
iframe.src = location.origin.replace("ide.", "") + "/profile/packages?nobar=1&pid=" + c9.projectId;
|
||||
});
|
||||
|
||||
plugin.on("getState", function(e) {
|
||||
});
|
||||
plugin.on("setState", function(e) {
|
||||
});
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("documentLoad", function(e) {
|
||||
var doc = e.doc;
|
||||
doc.title = "Package Browser";
|
||||
|
||||
function setTheme() {
|
||||
var bg = "#fbfbfb";
|
||||
doc.tab.backgroundColor = bg;
|
||||
|
||||
if (util.shadeColor(bg, 1).isLight)
|
||||
doc.tab.classList.remove("dark");
|
||||
else
|
||||
doc.tab.classList.add("dark");
|
||||
}
|
||||
|
||||
layout.on("themeChange", setTheme, e.doc);
|
||||
setTheme();
|
||||
});
|
||||
|
||||
plugin.on("documentActivate", function(e) {
|
||||
|
||||
});
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
/**
|
||||
*
|
||||
* @extends Editor
|
||||
*/
|
||||
plugin.freezePublicAPI({
|
||||
|
||||
});
|
||||
|
||||
plugin.load(null, "plugin.packages");
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
register(null, {
|
||||
"plugin.packages": handle
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -4,3 +4,17 @@
|
||||
.bk-window.dialog-updater .bk-win-footer {
|
||||
display: none;
|
||||
}
|
||||
.serviceButton {
|
||||
cursor: default;
|
||||
}
|
||||
.serviceButton:hover, .serviceButtonActive {
|
||||
color: @preferences-intro-link-color;
|
||||
text-decoration : underline;
|
||||
}
|
||||
.tree-row.load-error {
|
||||
color: #f99145;
|
||||
}
|
||||
h1.pluginManagerHeader:after {
|
||||
background: none;
|
||||
content: "-";
|
||||
}
|
||||
@ -1,417 +0,0 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
main.consumes = [
|
||||
"Plugin",
|
||||
"c9", "proc", "Dialog", "ui",
|
||||
];
|
||||
main.provides = ["plugin.updater.npm"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports["Plugin"];
|
||||
var c9 = imports["c9"];
|
||||
var proc = imports["proc"];
|
||||
var Dialog = imports["Dialog"];
|
||||
var ui = imports["ui"];
|
||||
|
||||
var async = require("async");
|
||||
var path = require("path");
|
||||
var semverCompare = require("semver-compare");
|
||||
|
||||
var NPM_MIN_VERSION = "2.6.0";
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var npmBin = options.npmBin || "/home/ubuntu/.nvm/nvm-exec";
|
||||
var managedPath = options.managedPath || "/home/ubuntu/.c9/managed";
|
||||
|
||||
var managedRcPath = [managedPath, ".npmrc"].join("/");
|
||||
var managedNpmPath = [managedPath, "npm"].join("/");
|
||||
var managedEtcPath = [managedNpmPath, "etc"].join("/");
|
||||
var managedCachePath = [managedPath, "npm", "cache"].join("/");
|
||||
var managedPluginsPath = [managedPath, "plugins"].join("/");
|
||||
var managedModulesPath = [managedPath, "node_modules"].join("/");
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
|
||||
function load() {
|
||||
ui.insertCss(require("text!./style.css"), false, plugin);
|
||||
|
||||
var pkgs = options.packages;
|
||||
|
||||
if (!pkgs) {
|
||||
console.warn("[plugin.updater.npm] no managed packages configured, not loading.");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: DRY error handling
|
||||
|
||||
fsMkdirs([ managedPath, managedEtcPath, managedModulesPath, managedPluginsPath ], function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
fsWriteNpmrc(function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
npmCheckVersion(function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: clean up the flow for detecting and installing missing
|
||||
// packages. the nested functions are messy.
|
||||
|
||||
async.filter(pkgs, function(pkg, done) {
|
||||
npmExplorePath(pkg, function(err, path) {
|
||||
var isMissing = !!err;
|
||||
|
||||
if (isMissing)
|
||||
debug("missing package:", pkg, err);
|
||||
|
||||
done(isMissing);
|
||||
});
|
||||
}, function(missing) {
|
||||
if (missing.length) {
|
||||
console.info("[plugin.updater.npm] Installing missing plugins:", missing);
|
||||
showUpdateDialog();
|
||||
|
||||
npmInstall(missing, function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
buildLinks(pkgs, function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// reload browser
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
npmOutdated(pkgs, function(err, outdated) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!outdated) {
|
||||
debug("Plugins up-to-date.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.info("[plugin.updater.npm] Updating outdated plugins:", outdated);
|
||||
showUpdateDialog();
|
||||
|
||||
buildLinks(pkgs, function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
showErrorDialog(err);
|
||||
return;
|
||||
}
|
||||
|
||||
npmUpdate(outdated, function(err) {
|
||||
if (err) {
|
||||
console.error("[plugin.updater.npm]", err);
|
||||
alert("[plugin.updater.npm] Error: " + err.message);
|
||||
}
|
||||
|
||||
// reload browser
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function unload() {
|
||||
}
|
||||
|
||||
/* -- Helper Functions ----- */
|
||||
|
||||
function debug(format) {
|
||||
if (c9.debug) {
|
||||
var util = require("util");
|
||||
console.info(util.format.apply(null,
|
||||
Array.prototype.slice.call(arguments)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/* -- npm Management ----- */
|
||||
|
||||
/**
|
||||
* Check that the installed npm version matches the NPM_MIN_VERSION
|
||||
* required
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err An error if the version is lower than required
|
||||
*/
|
||||
function npmCheckVersion(callback) {
|
||||
npmExec("npm", ["-v"], function(err, stdout, stderr) {
|
||||
if (err) return callback(err, stdout, stderr);
|
||||
|
||||
var version = stdout;
|
||||
|
||||
debug("npm version", version);
|
||||
|
||||
if (semverCompare(version, NPM_MIN_VERSION) === -1) {
|
||||
var error = new Error("npm version " + NPM_MIN_VERSION + " or greater required");
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function npmExec(command, args, callback) {
|
||||
debug(npmBin, { args: [ "npm", command ].concat(args) });
|
||||
|
||||
proc.execFile(npmBin, {
|
||||
args: [ "npm", command ].concat(args),
|
||||
cwd: managedPath,
|
||||
env: {
|
||||
"npm_config_production": "true",
|
||||
"npm_config_depth": 0,
|
||||
"npm_config_userconfig": "/dev/null",
|
||||
"npm_config_prefix": managedNpmPath,
|
||||
"npm_config_cache": managedCachePath,
|
||||
},
|
||||
}, function(err, stdout, stderr) {
|
||||
debug([err, stdout, stderr]);
|
||||
|
||||
if (err) return callback(err, stdout, err.message);
|
||||
|
||||
stdout = stdout.trimRight();
|
||||
stderr = stderr.trimRight();
|
||||
|
||||
callback(null, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
/* -- Package Management ----- */
|
||||
|
||||
function npmOutdated(pkgs, callback) {
|
||||
npmExec("outdated", ["--json"], function(err, stdout, stderr) {
|
||||
if (err)
|
||||
return callback(err, null, stdout, stderr);
|
||||
|
||||
if (!stdout)
|
||||
return callback(null, null, stdout, stderr);
|
||||
|
||||
var outdated = JSON.parse(stdout);
|
||||
outdated = Object.keys(outdated);
|
||||
|
||||
callback(null, outdated, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
function npmInstall(pkgs, callback) {
|
||||
npmExec("install", ["--"].concat(pkgs), function(err, stdout, stderr) {
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
function npmUpdate(pkgs, callback) {
|
||||
npmExec("update", ["--"].concat(pkgs), function(err, stdout, stderr) {
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
function npmExplorePath(pkg, callback) {
|
||||
npmExec("explore", [pkg, "--", "pwd"], function(err, stdout, stderr) {
|
||||
if (err)
|
||||
return callback(err, null, stderr);
|
||||
|
||||
callback(null, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the symbolic links from `~/.c9/plugins` to the managed plugins.
|
||||
*
|
||||
* @param {String[]} pkgs A list of package names to link.
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {Error=} callback.err
|
||||
*/
|
||||
function buildLinks(pkgs, callback) {
|
||||
async.each(pkgs, function(pkg, done) {
|
||||
npmExplorePath(pkg, function(err, pkgPath) {
|
||||
if (err) return done(err);
|
||||
fsLink(pkgPath, done);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes symbolic links from the `~/.c9/managed/plugins` folder.
|
||||
*/
|
||||
function fsRmLinks(callback) {
|
||||
debug("find", { args: [ managedPluginsPath, "-maxdepth", "1", "-type", "l", "-exec", "rm", "{}", ";" ]});
|
||||
|
||||
// find . -maxdepth 1 -type l -exec rm {} \;
|
||||
|
||||
proc.execFile("find", {
|
||||
args: [
|
||||
managedPluginsPath,
|
||||
"-maxdepth", "1",
|
||||
"-type", "l",
|
||||
"-exec", "rm", "{}", ";"
|
||||
],
|
||||
}, function(err, stdout, stderr) {
|
||||
debug([err, stdout, stderr]);
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a symbolic link in `~/.c9/plugins` pointing to the given
|
||||
* plugin path.
|
||||
*
|
||||
* @param {String} pkgPath Path to the source package folder
|
||||
*/
|
||||
function fsLink(pkgPath, callback) {
|
||||
debug("ln", { args: [ "-s", "-f", pkgPath, [ managedPluginsPath, "." ].join("/") ]});
|
||||
|
||||
proc.execFile("ln", {
|
||||
args: [
|
||||
"-s", "-f",
|
||||
pkgPath,
|
||||
managedPluginsPath + "/.",
|
||||
],
|
||||
}, function(err, stdout, stderr) {
|
||||
debug([err, stdout, stderr]);
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
function fsMkdirs(dirPaths, callback) {
|
||||
debug("mkdir", { args: [ "-p", "--" ].concat(dirPaths) });
|
||||
|
||||
proc.execFile("mkdir", {
|
||||
args: [ "-p", "--" ].concat(dirPaths),
|
||||
}, function(err, stdout, stderr) {
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
function fsWriteNpmrc(callback) {
|
||||
var config = [
|
||||
"//registry.npmjs.org/:_authToken = a7c61f6e-5b10-41db-947f-8bc8f1f9468b",
|
||||
"production = true",
|
||||
"depth = 0",
|
||||
"userconfig = /dev/null",
|
||||
"prefix = " + managedNpmPath,
|
||||
"cache = " + managedCachePath,
|
||||
];
|
||||
|
||||
//
|
||||
// HACK: - fs.writeFile() does not always work? we are using echo
|
||||
// instead
|
||||
//
|
||||
// - config is not escaped
|
||||
//
|
||||
|
||||
debug("sh", { args: [ "-c", "echo '" + config.join("\\n") + "' > " + managedRcPath ]});
|
||||
|
||||
proc.execFile("sh", {
|
||||
args: [
|
||||
"-c",
|
||||
"echo '" + config.join("\\n") + "' > " + managedRcPath
|
||||
],
|
||||
}, function(err, stdout, stderr) {
|
||||
callback(err, stdout, stderr);
|
||||
});
|
||||
}
|
||||
|
||||
/* -- Interface ----- */
|
||||
|
||||
/**
|
||||
* Show a modal upgrade progress dialog, blocking the IDE interface
|
||||
* while we are updating the plugins.
|
||||
*/
|
||||
function showUpdateDialog() {
|
||||
var dialog = new Dialog("Ajax.org", [], {
|
||||
name: "plugin.updater.npm.dialog",
|
||||
class: "dialog-updater",
|
||||
allowClose: false,
|
||||
modal: true,
|
||||
elements: [
|
||||
],
|
||||
});
|
||||
|
||||
dialog.title = "Installing Updates";
|
||||
dialog.heading = "";
|
||||
dialog.body = "Your workspace will be updated to the newest version and reload automatically.";
|
||||
|
||||
dialog.show();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an upgrade error dialog, requesting to delete and recreate the
|
||||
* workspace. This is shown for critical update errors.
|
||||
*/
|
||||
function showErrorDialog(err) {
|
||||
var dialog = new Dialog("Ajax.org", [], {
|
||||
name: "plugin.updater.npm.error_dialog",
|
||||
allowClose: true,
|
||||
modal: true,
|
||||
elements: [
|
||||
],
|
||||
});
|
||||
|
||||
var errorMessage = (err && err.message) ? "" + err.message : err;
|
||||
|
||||
dialog.title = "Error installing updates";
|
||||
dialog.heading = "";
|
||||
dialog.body = "<strong>Important updates could not be installed on this workspace.</strong><br><br>"
|
||||
+ "Please delete this workspace and create a new one, in order to continue "
|
||||
+ "working in an up-to-date environment.<br><br>"
|
||||
+ "<div style='max-height: 100px; overflow: auto;'><small><code>" + errorMessage + "</code></small></div>";
|
||||
|
||||
dialog.show();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/***** Register and define API *****/
|
||||
|
||||
plugin.on("load", load);
|
||||
plugin.on("unload", unload);
|
||||
|
||||
/**
|
||||
* @class salesforc.sync
|
||||
*/
|
||||
plugin.freezePublicAPI({
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"plugin.updater.npm": plugin
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -98,7 +98,6 @@ define(function(require, exports, module) {
|
||||
name: "reverttosavedall",
|
||||
hint: "downgrade the all open tabs to the last saved version",
|
||||
bindKey: { mac: "Option-Shift-Q", win: "Alt-Shift-Q" },
|
||||
isAvailable: available,
|
||||
exec: function () {
|
||||
revertToSavedAll();
|
||||
}
|
||||
|
||||
@ -1520,7 +1520,7 @@ apf.item = function(struct, tagName) {
|
||||
return;
|
||||
|
||||
var opener = this.parentNode.opener;
|
||||
if (opener && opener.parentNode.$showingSubMenu)
|
||||
if (opener && opener.parentNode && opener.parentNode.$showingSubMenu)
|
||||
selectItem(opener);
|
||||
|
||||
if (!force && (apf.isChildOf(this.$ext, e.toElement || e.explicitOriginalTarget)
|
||||
|
||||
@ -65,6 +65,22 @@
|
||||
background-color: #565656;
|
||||
background-position: -2px -18px;
|
||||
}
|
||||
.ace_tree .tree-row .checkbox.loading:after{
|
||||
content:" ";
|
||||
position:relative;
|
||||
display:block;
|
||||
top:0; left:0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 20%;
|
||||
background-color: @color;
|
||||
animation: scaleout 1.2s infinite ease-in-out
|
||||
}
|
||||
@keyframes scaleout {
|
||||
0% { transform: scale(0) }
|
||||
80% { transform: scale(1); opacity: 0;}
|
||||
100% { transform: scale(1); opacity: 0;}
|
||||
}
|
||||
|
||||
.custom-tree.ace_tree .tree-row .toggler{
|
||||
.image-2x("@{tree-arrow}", 20px, 10px);
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
return obj;
|
||||
}
|
||||
window.isLocalVersion = nRequire ? true : false;
|
||||
window.require = undefined;
|
||||
window.require = window.module = undefined;
|
||||
</script>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
@ -64,8 +64,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
app.lut = {};
|
||||
|
||||
app.on("error", function(err){
|
||||
console.error(err.stack);
|
||||
if (!errored)
|
||||
@ -73,20 +71,11 @@
|
||||
});
|
||||
|
||||
app.on("service", function(name, plugin, options){
|
||||
if (name == "plugin.loader" || name == "plugin.installer"
|
||||
|| name == "plugin.debug" || name == "plugin.manager"
|
||||
|| name == "plugin.test")
|
||||
plugin.architect = app;
|
||||
if (!plugin.name)
|
||||
plugin.name = name;
|
||||
if (options)
|
||||
app.lut[(options.packagePath || "").replace(/^.*\/home\/.c9\//, "")] = options;
|
||||
});
|
||||
|
||||
app.on("ready", function(){
|
||||
if (app.services.configure)
|
||||
app.services.configure.services = app.services;
|
||||
|
||||
app.once("ready", function() {
|
||||
window.app = app.services;
|
||||
window.app.__defineGetter__("_ace", function(){
|
||||
return this.tabManager.focussedTab.editor.ace;
|
||||
|
||||
@ -124,29 +124,18 @@
|
||||
}
|
||||
});
|
||||
|
||||
app.lut = {};
|
||||
|
||||
app.on("error", function(err){
|
||||
console.error(err.stack);
|
||||
if (!errored)
|
||||
alert(err);
|
||||
});
|
||||
|
||||
app.on("service", function(name, plugin, options){
|
||||
if (name == "plugin.loader" || name == "plugin.installer"
|
||||
|| name == "plugin.debug" || name == "plugin.manager"
|
||||
|| name == "plugin.test")
|
||||
plugin.architect = app;
|
||||
app.on("service", function(name, plugin, options) {
|
||||
if (!plugin.name)
|
||||
plugin.name = name;
|
||||
if (options)
|
||||
app.lut[(options.packagePath || "").replace(/^.*\/home\/.c9\//, "")] = options;
|
||||
});
|
||||
|
||||
app.on("ready", function() {
|
||||
if (app.services.configure)
|
||||
app.services.configure.services = app.services;
|
||||
|
||||
window.app = app.services;
|
||||
window.app.__defineGetter__("_ace", function(){
|
||||
return this.tabManager.focussedTab.editor.ace;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user