diff --git a/.gitignore b/.gitignore index 1e7db6c361a..263720b1007 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.swp +*.un~ common/packager common/apf client/icons/Thumbs.db diff --git a/.gitmodules b/.gitmodules index d1018d30a3f..0c41dc57369 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,4 @@ [submodule "support/gnu-builds"] path = support/gnu-builds url = git://github.com/ajaxorg/gnu-builds.git + diff --git a/client/core/ext.js b/client/core/ext.js index 645b2f81dae..c29eb6804a8 100644 --- a/client/core/ext.js +++ b/client/core/ext.js @@ -143,7 +143,7 @@ return ext = { } }, - initExtension : function(oExtension, amlParent){ + initExtension : function(oExtension, amlParent) { if (oExtension.inited) return; diff --git a/client/core/ide.js b/client/core/ide.js index 873aa0f7531..7b8985d4751 100644 --- a/client/core/ide.js +++ b/client/core/ide.js @@ -157,12 +157,6 @@ define(function(require, exports, module) { }); }; - //@todo see if this can be moved to noderunner - ide.addEventListener("socketMessage", function(e){ - if (e.message.type && e.message.type == "state") - stProcessRunning.setProperty("active", e.message.processRunning); - }); - // for unknown reasons io is sometimes undefined try { ide.socket = new io.Socket(null, options); @@ -175,10 +169,11 @@ define(function(require, exports, module) { } ); - var socketIoScriptEl = Array.prototype.slice.call(document.getElementsByTagName("script")) - .filter(function(script) { + var socketIoScriptEl = Array.prototype.slice.call( + document.getElementsByTagName("script")).filter(function(script) { return script.src && script.src.indexOf("socket.io.js") >= 0; - })[0]; + } + )[0]; if (socketIoScriptEl) { apf.ajax(socketIoScriptEl.src, { diff --git a/client/ext/code/code.xml b/client/ext/code/code.xml index 0b97939ecfd..d29406185cd 100644 --- a/client/ext/code/code.xml +++ b/client/ext/code/code.xml @@ -25,7 +25,7 @@ contextmenu = "mnuCtxEditor" debugger = "{this.syntax == 'javascript' ? dbg : null}" - readonly = "{cloud9config.readonly or (location.host and stDebugProcessRunning.active and [@scriptid])}" + readonly = "{[@loading] or cloud9config.readonly or (location.host and stDebugProcessRunning.active and [@scriptid])}" /> diff --git a/client/ext/console/console.js b/client/ext/console/console.js index edab5407c3a..6789ea4b3fe 100644 --- a/client/ext/console/console.js +++ b/client/ext/console/console.js @@ -921,35 +921,40 @@ return ext.register("ext/console/console", { } }, - showObject : function(xmlNode, ref, expression){ + showObject : function(xmlNode, ref, expression) { if (ref && ref.dataType == apf.ARRAY) { - require("ext/debugger/debugger").showDebugFile(ref[0], ref[1] + 1, 0, ref[4]); + require(["ext/debugger/debugger"], function(dbg) { + dbg.showDebugFile(ref[0], ref[1] + 1, 0, ref[4]); + }); } else { - require("ext/quickwatch/quickwatch").toggleDialog(1); - - if (xmlNode && typeof xmlNode == "string") - xmlNode = apf.getXml(xmlNode); - - var name = xmlNode && xmlNode.getAttribute("name") || expression; - txtCurObject.setValue(name); - dgWatch.clear("loading"); - - if (xmlNode) { - setTimeout(function(){ - var model = dgWatch.getModel(); - var root = apf.getXml(""); - apf.xmldb.appendChild(root, xmlNode); - model.load(root); - //model.appendXml(xmlNode); - }, 10); - } - else if (ref) { + require(["ext/quickwatch/quickwatch"], function(quickwatch) { + quickwatch.toggleDialog(1); + + if (xmlNode && typeof xmlNode == "string") + xmlNode = apf.getXml(xmlNode); + + var name = xmlNode && xmlNode.getAttribute("name") || expression; + txtCurObject.setValue(name); + dgWatch.clear("loading"); + + if (xmlNode) { + setTimeout(function(){ + var model = dgWatch.getModel(); + var root = apf.getXml(""); + apf.xmldb.appendChild(root, xmlNode); + model.load(root); + //model.appendXml(xmlNode); + }, 10); + } + else if (ref) { + + } + else { + this.evaluate(expression); + } + }); - } - else { - this.evaluate(expression); - } } }, diff --git a/client/ext/debugger/debugger.js b/client/ext/debugger/debugger.js index bca42ed1188..fa0ec9992e3 100644 --- a/client/ext/debugger/debugger.js +++ b/client/ext/debugger/debugger.js @@ -35,6 +35,7 @@ return ext.register("ext/debugger/debugger", { }, nodes : [], + hotitems: {}, hook : function(){ ide.addEventListener("consolecommand.debug", function(e) { @@ -111,10 +112,28 @@ return ext.register("ext/debugger/debugger", { activeState: { x: -6, y: -360 } } }); + ext.initExtension(this); }, init : function(amlNode){ var _self = this; + + while(tbDebug.childNodes.length) { + var button = tbDebug.firstChild; + + if (button.nodeType == 1 && button.getAttribute("id") == "btnDebug") + ide.barTools.insertBefore(button, btnRun); + else + ide.barTools.appendChild(button); + if (button.nodeType == 1) { + this.nodes.push(button); + } + } + + this.hotitems["resume"] = [btnResume]; + this.hotitems["stepinto"] = [btnStepInto]; + this.hotitems["stepover"] = [btnStepOver]; + this.hotitems["stepout"] = [btnStepOut]; this.paths = {}; diff --git a/client/ext/debugger/debugger.xml b/client/ext/debugger/debugger.xml index 6013bb4f6a7..74bd01e328d 100644 --- a/client/ext/debugger/debugger.xml +++ b/client/ext/debugger/debugger.xml @@ -1,4 +1,47 @@ + + + + + + + + + + + + + + - - - OK - - - + + + OK + + + \ No newline at end of file diff --git a/client/ext/run/run.js b/client/ext/run/run.js index 46f25669030..19bb257b5e3 100644 --- a/client/ext/run/run.js +++ b/client/ext/run/run.js @@ -28,24 +28,19 @@ return ext.register("ext/run/run", { "stepover" : {hint: "step over the current expression on the execution stack"}, "stepout" : {hint: "step out of the current function scope"} }, - hotitems: {}, nodes : [], init : function(amlNode){ while(tbRun.childNodes.length) { var button = tbRun.firstChild; - ide.barTools.appendChild(button); - if (button.nodeType == 1) + ide.barTools.appendChild(button); + if (button.nodeType == 1) { this.nodes.push(button); + } } - this.hotitems["resume"] = [btnResume]; - this.hotitems["stepinto"] = [btnStepInto]; - this.hotitems["stepover"] = [btnStepOver]; - this.hotitems["stepout"] = [btnStepOut]; - var _self = this; mdlRunConfigurations.addEventListener("afterload", function(e) { _self.$updateMenu(); diff --git a/client/ext/run/run.xml b/client/ext/run/run.xml index 33956b6ddb6..07664cf0c75 100644 --- a/client/ext/run/run.xml +++ b/client/ext/run/run.xml @@ -86,18 +86,8 @@ - - - - - - - - - - + \ No newline at end of file diff --git a/client/style/icons/minus.png b/client/style/icons/minus.png new file mode 100644 index 00000000000..26c85a94fc9 Binary files /dev/null and b/client/style/icons/minus.png differ diff --git a/client/style/icons/plus.png b/client/style/icons/plus.png new file mode 100644 index 00000000000..4d46ed93a7a Binary files /dev/null and b/client/style/icons/plus.png differ diff --git a/client/style/images/load-indicator-active-tab.gif b/client/style/images/load-indicator-active-tab.gif new file mode 100644 index 00000000000..097ae207656 Binary files /dev/null and b/client/style/images/load-indicator-active-tab.gif differ diff --git a/client/style/images/load-indicator-inactive-tab.gif b/client/style/images/load-indicator-inactive-tab.gif new file mode 100644 index 00000000000..8c24a4febf8 Binary files /dev/null and b/client/style/images/load-indicator-inactive-tab.gif differ diff --git a/client/style/skins.xml b/client/style/skins.xml index abe049e6234..b2b19609167 100644 --- a/client/style/skins.xml +++ b/client/style/skins.xml @@ -1475,6 +1475,10 @@ .header-btnOver { background-position : 0 -15px; } + + .header-btnDisabled { + background-position : 0 -30px; + } ]]> @@ -5770,6 +5774,14 @@ .editor_tab .btnsesssioncontainer .saving .sessiontab_icon { background-image: url(images/save-indicator-inactive-tab.gif); } + + .editor_tab .btnsesssioncontainer .loading_active .sessiontab_icon { + background-image: url(images/load-indicator-active-tab.gif); + } + + .editor_tab .btnsesssioncontainer .loading .sessiontab_icon { + background-image: url(images/load-indicator-inactive-tab.gif); + } .editor_tab .btnsesssioncontainer .session_btn .tab_middle .sessiontab_title { overflow : hidden; diff --git a/server/cloud9/ext/auth/index.js b/server/cloud9/ext/auth/auth.js similarity index 66% rename from server/cloud9/ext/auth/index.js rename to server/cloud9/ext/auth/auth.js index 42fa2ec045d..b39eb4ab939 100644 --- a/server/cloud9/ext/auth/index.js +++ b/server/cloud9/ext/auth/auth.js @@ -7,8 +7,8 @@ var Plugin = require("cloud9/plugin"); var sys = require("sys"); -var AuthPlugin = module.exports = function(ide) { - this.ide = ide; +var AuthPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "auth"; }; @@ -21,13 +21,13 @@ sys.inherits(AuthPlugin, Plugin); if (message.command != "attach") return false; - if (message.workspaceId != this.ide.options.workspaceId) { - this.ide.error("Unable to attach web socket!", 10, message, client) + if (message.workspaceId != this.workspace.workspaceId) { + this.error("Unable to attach web socket!", 10, message, client) return true; } client.send('{"type": "attached"}'); - this.ide.execHook("connect", user, client); + this.workspace.execHook("connect", user, client); return true; }; diff --git a/server/cloud9/ext/blame/index.js b/server/cloud9/ext/blame/blame.js similarity index 96% rename from server/cloud9/ext/blame/index.js rename to server/cloud9/ext/blame/blame.js index cab44667462..83a5a3c5e4d 100644 --- a/server/cloud9/ext/blame/index.js +++ b/server/cloud9/ext/blame/blame.js @@ -8,8 +8,8 @@ var Plugin = require("cloud9/plugin"); var Fs = require("fs"); var sys = require("sys"); -var BlamePlugin = module.exports = function(ide) { - this.ide = ide; +var BlamePlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "blame"; }; diff --git a/server/cloud9/ext/debugger/index.js b/server/cloud9/ext/debugger/debugger.js similarity index 76% rename from server/cloud9/ext/debugger/index.js rename to server/cloud9/ext/debugger/debugger.js index a9fe08d58d4..9e668ba8722 100644 --- a/server/cloud9/ext/debugger/index.js +++ b/server/cloud9/ext/debugger/debugger.js @@ -12,26 +12,27 @@ var Path = require("path"), sys = require("sys"), netutil = require("cloud9/netutil"); -var DebuggerPlugin = module.exports = function(ide) { - this.ide = ide; +var DebuggerPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "debugger"; + this.nodeCmd = process.argv[0]; }; sys.inherits(DebuggerPlugin, Plugin); (function() { + this.NODE_DEBUG_PORT = 5858; + this.CHROME_DEBUG_PORT = 9222; + this.init = function() { var _self = this; - this.ide.getExt("state").on("statechange", function(state) { - state.debugClient = !!_self.debugClient; + this.workspace.getExt("state").on("statechange", function(state) { + state.debugClient = !!_self.debugClient; state.processRunning = !!_self.child; }); }; - this.NODE_DEBUG_PORT = 5858; - this.CHROME_DEBUG_PORT = 9222; - this.command = function(user, message, client) { var _self = this; @@ -47,7 +48,7 @@ sys.inherits(DebuggerPlugin, Plugin); message.preArgs = ["--debug=" + _self.NODE_DEBUG_PORT]; message.debug = true; _self.$run(message, client); - + setTimeout(function() { _self.$startDebug(); }, 100); @@ -56,11 +57,11 @@ sys.inherits(DebuggerPlugin, Plugin); case "rundebugbrk": netutil.findFreePort(this.NODE_DEBUG_PORT, "localhost", function(port) { _self.NODE_DEBUG_PORT = port; - + message.preArgs = ["--debug-brk=" + _self.NODE_DEBUG_PORT]; message.debug = true; _self.$run(message, client); - + setTimeout(function() { _self.$startDebug(); }, 100); @@ -68,25 +69,25 @@ sys.inherits(DebuggerPlugin, Plugin); break; case "rundebugchrome": if (this.chromeDebugProxy) { - this.ide.error("Chrome debugger already running!", 7, message); + this.error("Chrome debugger already running!", 7, message); break; } this.chromeDebugProxy = new ChromeDebugProxy(this.CHROME_DEBUG_PORT); this.chromeDebugProxy.connect(); this.chromeDebugProxy.addEventListener("connection", function() { - _self.ide.broadcast('{"type": "chrome-debug-ready"}', _self.name); + _self.send('{"type": "chrome-debug-ready"}', null, _self.name); }); break; case "debugnode": if (!this.nodeDebugProxy) - this.ide.error("No debug session running!", 6, message); + this.error("No debug session running!", 6, message); else this.nodeDebugProxy.send(message.body); break; case "debugattachnode": if (this.nodeDebugProxy) - this.ide.broadcast('{"type": "node-debug-ready"}', _self.name); + this.send('{"type": "node-debug-ready"}', null, _self.name); break; case "kill": this.$kill(); @@ -118,22 +119,22 @@ sys.inherits(DebuggerPlugin, Plugin); var _self = this; if (this.child) - return _self.ide.error("Child process already running!", 1, message); + return _self.error("Child process already running!", 1, message); + + var file = _self.workspace.workspaceDir + "/" + message.file; - var file = _self.ide.workspaceDir + "/" + message.file; - Path.exists(file, function(exists) { if (!exists) - return _self.ide.error("File does not exist: " + message.file, 2, message); - - var cwd = _self.ide.workspaceDir + "/" + (message.cwd || ""); + return _self.error("File does not exist: " + message.file, 2, message); + + var cwd = _self.workspace.workspaceDir + "/" + (message.cwd || ""); Path.exists(cwd, function(exists) { if (!exists) - return _self.ide.error("cwd does not exist: " + message.cwd, 3, message); + return _self.error("cwd does not exist: " + message.cwd, 3, message); // lets check what we need to run if(file.match(/\.js$/)){ var args = (message.preArgs || []).concat(file).concat(message.args || []); - _self.$runProc(_self.ide.nodeCmd, args, cwd, message.env || {}, message.debug || false); + _self.$runProc(_self.nodeCmd, args, cwd, message.env || {}, message.debug || false); } else { _self.$runProc(file, message.args||[], cwd, message.env || {}, false); } @@ -143,6 +144,7 @@ sys.inherits(DebuggerPlugin, Plugin); this.$runProc = function(proc, args, cwd, env, debug) { var _self = this; + var name = this.name; // mixin process env for (var key in process.env) { @@ -150,12 +152,12 @@ sys.inherits(DebuggerPlugin, Plugin); env[key] = process.env[key]; } - console.log("Executing node "+proc+" "+args.join(" ")+" "+cwd); + console.log("Executing node "+proc+" "+args.join(" ")+" "+cwd); var child = _self.child = Spawn(proc, args, {cwd: cwd, env: env}); _self.debugClient = args.join(" ").search(/(?:^|\b)\-\-debug\b/) != -1; - _self.ide.getExt("state").publishState(); - _self.ide.broadcast(JSON.stringify({"type": "node-start"}), _self.name); + _self.workspace.getExt("state").publishState(); + _self.send({"type": "node-start"}, null, name); child.stdout.on("data", sender("stdout")); child.stderr.on("data", sender("stderr")); @@ -167,12 +169,12 @@ sys.inherits(DebuggerPlugin, Plugin); "stream": stream, "data": data.toString("utf8") }; - _self.ide.broadcast(JSON.stringify(message), _self.name); + _self.send(message, null, name); }; } child.on("exit", function(code) { - _self.ide.broadcast(JSON.stringify({"type": "node-exit"}), _self.name); + _self.send({"type": "node-exit"}, null, name); _self.debugClient = false; delete _self.child; @@ -186,10 +188,10 @@ sys.inherits(DebuggerPlugin, Plugin); var _self = this; if (!this.debugClient) - return this.ide.error("No debuggable application running", 4, message); + return this.error("No debuggable application running", 4, message); if (this.nodeDebugProxy) - return this.ide.error("Debug session already running", 5, message); + return this.error("Debug session already running", 5, message); this.nodeDebugProxy = new NodeDebugProxy(this.NODE_DEBUG_PORT); this.nodeDebugProxy.on("message", function(body) { @@ -197,11 +199,11 @@ sys.inherits(DebuggerPlugin, Plugin); "type": "node-debug", "body": body }; - _self.ide.broadcast(JSON.stringify(msg), _self.name); + _self.send(msg, null, _self.name); }); this.nodeDebugProxy.on("connection", function() { - _self.ide.broadcast('{"type": "node-debug-ready"}', _self.name); + _self.send('{"type": "node-debug-ready"}', null, _self.name); }); this.nodeDebugProxy.on("end", function() { @@ -212,10 +214,10 @@ sys.inherits(DebuggerPlugin, Plugin); this.nodeDebugProxy.connect(); }; - + this.dispose = function(callback) { this.$kill(); callback(); }; - -}).call(DebuggerPlugin.prototype); \ No newline at end of file + +}).call(DebuggerPlugin.prototype); diff --git a/server/cloud9/ext/git/index.js b/server/cloud9/ext/git/git.js similarity index 91% rename from server/cloud9/ext/git/index.js rename to server/cloud9/ext/git/git.js index ae3262639ef..fde618fdc41 100644 --- a/server/cloud9/ext/git/index.js +++ b/server/cloud9/ext/git/git.js @@ -5,10 +5,11 @@ * @license GPLv3 */ var Plugin = require("cloud9/plugin"); -var sys = require("sys"); +var sys = require("sys"); +var util = require("cloud9/util"); -var ShellGitPlugin = module.exports = function(ide) { - this.ide = ide; +var ShellGitPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "git"; }; @@ -49,14 +50,14 @@ sys.inherits(ShellGitPlugin, Plugin); } function onfinish() { - _self.extend(commands, githelp); + util.extend(commands, githelp); callback(); } }; this.augmentCommand = function(cmd, struct) { var map = commandsMap[cmd] || commandsMap["default"]; - return this.extend(struct, map || {}); + return util.extend(struct, map || {}); }; this.command = function(user, message, client) { diff --git a/server/cloud9/ext/hg/index.js b/server/cloud9/ext/hg/hg.js similarity index 90% rename from server/cloud9/ext/hg/index.js rename to server/cloud9/ext/hg/hg.js index 6269d31e0b7..37aed0c86f1 100644 --- a/server/cloud9/ext/hg/index.js +++ b/server/cloud9/ext/hg/hg.js @@ -7,8 +7,8 @@ var Plugin = require("cloud9/plugin"); var sys = require("sys"); -var ShellHgPlugin = module.exports = function(ide) { - this.ide = ide; +var ShellHgPlugin = module.exports = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "hg"; this.banned = ["serve"]; @@ -17,14 +17,14 @@ var ShellHgPlugin = module.exports = function(ide) { sys.inherits(ShellHgPlugin, Plugin); (function() { - var hghelp = "", - commandsMap = { - "default": { - "commands": { - "[PATH]": {"hint": "path pointing to a folder or file. Autocomplete with [TAB]"} - } + var hghelp = ""; + var commandsMap = { + "default": { + "commands": { + "[PATH]": {"hint": "path pointing to a folder or file. Autocomplete with [TAB]"} } - }; + } + }; this.$commandHints = function(commands, message, callback) { var _self = this; diff --git a/server/cloud9/ext/settings/index.js b/server/cloud9/ext/settings/settings.js similarity index 91% rename from server/cloud9/ext/settings/index.js rename to server/cloud9/ext/settings/settings.js index f1277ed0e29..c792c747f23 100644 --- a/server/cloud9/ext/settings/index.js +++ b/server/cloud9/ext/settings/settings.js @@ -9,8 +9,8 @@ var Path = require("path"); var fs = require("fs"); var sys = require("sys"); -var SettingsPlugin = module.exports = function(ide) { - this.ide = ide; +var SettingsPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "settings"; @@ -37,7 +37,7 @@ sys.inherits(SettingsPlugin, Plugin); else if (message.action == "set") { this.storeSettings(user, message.settings, function(err) { if (err) - _self.ide.error(err, 500, message, client); + _self.error(err, 500, message, client); }); } return true; diff --git a/server/cloud9/ext/shell/index.js b/server/cloud9/ext/shell/shell.js similarity index 87% rename from server/cloud9/ext/shell/index.js rename to server/cloud9/ext/shell/shell.js index bc1d4607b5e..fe027e21cc0 100644 --- a/server/cloud9/ext/shell/index.js +++ b/server/cloud9/ext/shell/shell.js @@ -4,17 +4,18 @@ * @copyright 2010, Ajax.org B.V. * @license GPLv3 */ -var Plugin = require("cloud9/plugin"), - Fs = require("fs"), - Path = require("path"), - Async = require("asyncjs"), - sys = require("sys"); +var Plugin = require("cloud9/plugin"); +var Fs = require("fs"); +var Path = require("path"); +var Async = require("asyncjs"); +var sys = require("sys"); +var util = require("cloud9/util"); -var ShellPlugin = module.exports = function(ide) { - this.ide = ide; +var ShellPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["command"]; this.name = "shell"; -} +}; sys.inherits(ShellPlugin, Plugin); @@ -46,11 +47,11 @@ sys.inherits(ShellPlugin, Plugin); this["internal-isfile"] = function(message) { var file = message.argv.pop(), - path = message.cwd || this.ide.workspaceDir, + path = message.cwd || this.workspace.workspaceDir, _self = this; path = Path.normalize(path + "/" + file.replace(/^\//g, "")); - if (path.indexOf(this.ide.workspaceDir) === -1) { + if (path.indexOf(this.workspace.workspaceDir) === -1) { this.sendResult(); return; } @@ -71,9 +72,9 @@ sys.inherits(ShellPlugin, Plugin); var commands = {}, _self = this; - Async.list(Object.keys(this.ide.exts)) + Async.list(Object.keys(this.workspace.exts)) .each(function(sName, next) { - var oExt = _self.ide.getExt(sName); + var oExt = _self.workspace.getExt(sName); if (oExt["$commandHints"]) { oExt["$commandHints"](commands, message, next); } @@ -93,7 +94,7 @@ sys.inherits(ShellPlugin, Plugin); function afterMeta() { if (oExt.metadata && oExt.metadata.commands) - _self.extend(commands, oExt.metadata.commands); + util.extend(commands, oExt.metadata.commands); next(); } } @@ -118,11 +119,11 @@ sys.inherits(ShellPlugin, Plugin); this.cd = function(message) { var to = message.argv.pop(), - path = message.cwd || this.ide.workspaceDir, + path = message.cwd || this.workspace.workspaceDir, _self = this; if (to != "/") { path = Path.normalize(path + "/" + to.replace(/^\//g, "")); - if (path.indexOf(this.ide.workspaceDir) === -1) + if (path.indexOf(this.workspace.workspaceDir) === -1) return this.sendResult(); Fs.stat(path, function(err, stat) { if (err) { diff --git a/server/cloud9/ext/state/index.js b/server/cloud9/ext/state/state.js similarity index 69% rename from server/cloud9/ext/state/index.js rename to server/cloud9/ext/state/state.js index 03f6775a692..064114317b4 100644 --- a/server/cloud9/ext/state/index.js +++ b/server/cloud9/ext/state/state.js @@ -7,8 +7,8 @@ var Plugin = require("cloud9/plugin"); var sys = require("sys"); -var cloud9StatePlugin = module.exports = function(ide) { - this.ide = ide; +var cloud9StatePlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); this.hooks = ["connect", "command"]; this.name = "state"; }; @@ -19,24 +19,22 @@ sys.inherits(cloud9StatePlugin, Plugin); this.connect = function(user, message, client) { this.publishState(); }; - + this.command = function(user, message, client) { if (message && message.command !== "state") return false; return true; }; - + this.publishState = function() { var state = { - "type": "state", - "workspaceDir": this.ide.workspaceDir, - "davPrefix": this.ide.davPrefix + "type": "state" }; this.emit("statechange", state); - console.log("publish state" + JSON.stringify(state)) - this.ide.broadcast(JSON.stringify(state)); + console.log("publish state" + JSON.stringify(state)); + this.send(state, null, this.name); }; - + }).call(cloud9StatePlugin.prototype); diff --git a/server/cloud9/ext/watcher/index.js b/server/cloud9/ext/watcher/watcher.js similarity index 94% rename from server/cloud9/ext/watcher/index.js rename to server/cloud9/ext/watcher/watcher.js index b9f85c7ce9e..7178deca480 100644 --- a/server/cloud9/ext/watcher/index.js +++ b/server/cloud9/ext/watcher/watcher.js @@ -12,9 +12,9 @@ var IGNORE_TIMEOUT = 50, ignoredPaths = {}, ignoreTimers = {}; -function cloud9WatcherPlugin(ide) { - var that = this; - +var cloud9WatcherPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); + ide.davServer.plugins['watcher'] = function (handler) { handler.addEventListener('beforeWriteContent', function (e, uri) { var path = handler.server.tree.basePath + '/' + uri; @@ -25,7 +25,6 @@ function cloud9WatcherPlugin(ide) { }); }; - this.ide = ide; this.hooks = ["disconnect", "command"]; this.name = "watcher"; this.filenames = {}; @@ -98,12 +97,12 @@ sys.inherits(cloud9WatcherPlugin, Plugin); } }); } - that.ide.broadcast(JSON.stringify({ + that.send({ "type" : "watcher", "subtype" : subtype, "path" : path, "files" : files - })); + }); //console.log("Sent " + subtype + " notification for file " + path); }); this.filenames[path] = 0; @@ -123,6 +122,4 @@ sys.inherits(cloud9WatcherPlugin, Plugin); callback(); }; -}).call(cloud9WatcherPlugin.prototype); - -module.exports = cloud9WatcherPlugin; +}).call(cloud9WatcherPlugin.prototype); \ No newline at end of file diff --git a/server/cloud9/ide.js b/server/cloud9/ide.js index d9d6cddd5b3..a79c48aa247 100644 --- a/server/cloud9/ide.js +++ b/server/cloud9/ide.js @@ -12,7 +12,9 @@ var jsDAV = require("jsdav"), lang = require("pilot/lang"), Url = require("url"), template = require("./template"), - EventEmitter = require("events").EventEmitter; + Workspace = require("cloud9/workspace"), + EventEmitter = require("events").EventEmitter, + util = require("./util"); module.exports = Ide = function(options, httpServer, exts, socket) { EventEmitter.call(this); @@ -48,7 +50,8 @@ module.exports = Ide = function(options, httpServer, exts, socket) { offlineManifest: options.offlineManifest || "", projectName: options.projectName || this.workspaceDir.split("/").pop(), version: options.version, - extra: options.extra + extra: options.extra, + remote: options.remote }; this.$users = {}; @@ -61,10 +64,25 @@ module.exports = Ide = function(options, httpServer, exts, socket) { server: this.httpServer, standalone: false }; + + if (options.remote) + util.extend(davOptions, options.remote); + else + davOptions.path = this.options.mountDir; + this.davServer = jsDAV.mount(davOptions); this.davInited = false; - this.registerExts(exts); + this.workspace = new Workspace({ ide: this }); + + this.workspace.createPlugins(exts); + var statePlugin = this.workspace.getExt("state"); + if (statePlugin) { + statePlugin.on("statechange", function(state) { + state.workspaceDir = this.workspace.workspaceDir; + state.davPrefix = this.ide.davPrefix; + }); + } }; sys.inherits(Ide, EventEmitter); @@ -179,7 +197,7 @@ Ide.DEFAULT_PLUGINS = [ version: _self.options.version }; - var settingsPlugin = _self.getExt("settings"); + var settingsPlugin = _self.workspace.getExt("settings"); var user = _self.getUser(req); if (!settingsPlugin || !user) { index = template.fill(index, replacements); @@ -210,7 +228,7 @@ Ide.DEFAULT_PLUGINS = [ _self.onUserMessage(msg.user, msg.message, msg.client); }); user.on("disconnectClient", function(msg) { - _self.execHook("disconnect", msg.user, msg.client); + _self.workspace.execHook("disconnect", msg.user, msg.client); }); user.on("disconnectUser", function(user) { console.log("Running user disconnect timer..."); @@ -259,7 +277,7 @@ Ide.DEFAULT_PLUGINS = [ }; this.onUserMessage = function(user, message, client) { - this.execHook("command", user, message, client); + this.workspace.execHook("command", user, message, client); }; this.onUserCountChange = function() { @@ -279,76 +297,10 @@ Ide.DEFAULT_PLUGINS = [ this.sendToUser = function(username, msg) { this.$users[username] && this.$users[username].broadcast(msg); - } - - this.registerExts = function(exts) { - this.exts = {} - - for (var ext in exts) { - this.exts[ext] = new exts[ext](this); - } - for (ext in this.exts) { - if (this.exts[ext].init) - this.exts[ext].init(); - } - } - - this.getExt = function(name) { - return this.exts[name] || null; - }; - - this.execHook = function(hook, user /* varargs */) { - var ext, hooks, - args = Array.prototype.slice.call(arguments, 1), - hook = hook.toLowerCase().replace(/^[\s]+/, "").replace(/[\s]+$/, ""); - - var server_exclude = lang.arrayToMap(user.getPermissions().server_exclude.split("|")); - - for (var name in this.exts) { - if (server_exclude[name]) { - continue; - } - - ext = this.exts[name]; - hooks = ext.getHooks(); - if (hooks.indexOf(hook) > -1 && ext[hook].apply(ext, args) === true) { - return; - } - } - // if we get here, no hook function was successfully delegated to an - // extension. - - //this.error("Error: no handler found for hook '" + hook + "'. Arguments: " - // + sys.inspect(args), 9, args[0]); - }; - - // TODO remove - this.error = function(description, code, message, client) { - //console.log("Socket error: " + description, new Error().stack); - var sid = (message || {}).sid || -1; - var error = JSON.stringify({ - "type": "error", - "sid": sid, - "code": code, - "message": description - }); - if (client) - client.send(error) - else - this.broadcast(error); }; this.dispose = function(callback) { - var count; - for (var name in this.exts) { - count++; - var ext = this.exts[name]; - ext.dispose(function() { - count--; - if (count == 0) - callback(); - }); - } + this.workspace.dispose(callback); }; }).call(Ide.prototype); diff --git a/server/cloud9/index.js b/server/cloud9/index.js index 73b4632f3d9..199312da59d 100644 --- a/server/cloud9/index.js +++ b/server/cloud9/index.js @@ -18,18 +18,19 @@ exports.main = function(options) { ip = options.ip, user = options.user, group = options.group; - - if (!Path.existsSync(projectDir)) + + if (!Path.existsSync(projectDir)) throw new Error("Workspace directory does not exist: " + projectDir); - + var ideProvider = function(projectDir, server) { var uid = "owner" + Math.random().toString().slice(2); // load plugins: var exts = {}; Fs.readdirSync(Path.normalize(__dirname + "/ext")).forEach(function(name){ - exts[name] = require("./ext/" + name); + if (name[0] !== ".") + exts[name] = require("./ext/" + name + "/" + name); }); - + // create web socket var socketOptions = { transports: ['websocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'] @@ -38,7 +39,7 @@ exports.main = function(options) { socketIo.on("connection", function(client) { ide.addClientConnection(uid, client, null); }); - + var name = projectDir.split("/").pop(); var serverOptions = { workspaceDir: projectDir, @@ -51,14 +52,14 @@ exports.main = function(options) { version: options.version }; var ide = new IdeServer(serverOptions, server, exts); - + return function(req, res, next) { req.session.uid = uid; ide.addUser(uid, User.OWNER_PERMISSIONS); ide.handle(req, res, next); }; }; - + var server = Connect.createServer(); //server.use(Connect.logger()); server.use(Connect.conditionalGet()); @@ -86,4 +87,4 @@ process.on("uncaughtException", function(e) { if (module === require.main) { exports.main({workspace: ".", port: 3000, ip: '127.0.0.1'}); -} \ No newline at end of file +} diff --git a/server/cloud9/plugin.js b/server/cloud9/plugin.js index 193dd11fe50..26f36bee3a0 100644 --- a/server/cloud9/plugin.js +++ b/server/cloud9/plugin.js @@ -1,41 +1,58 @@ /** - * @copyright 2010, Ajax.org Services B.V. + * @copyright 2011, Ajax.org Services B.V. * @license GPLv3 */ -var Spawn = require("child_process").spawn; -var sys = require("sys"); -function cloud9Plugin() {} +var events = require("events"); +var Spawn = require("child_process").spawn; +var sys = require("sys"); -sys.inherits(cloud9Plugin, process.EventEmitter); +var Plugin = function(ide, workspace) { + this.ide = ide; + this.workspace = workspace; +}; + +sys.inherits(Plugin, events.EventEmitter); (function() { this.getHooks = function() { return this.hooks || []; }; - this.extend = function(dest, src) { - for (var prop in src) { - dest[prop] = src[prop]; - } - return dest; - }; - this.sendResult = function(sid, type, msg) { - //console.log("sending result to client: ", type, JSON.stringify(msg)); - this.ide.broadcast(JSON.stringify({ + var error = { type : "result", subtype: type || "error", sid : sid || 0, body : msg || "Access denied." - }), this.name); + }; + + // We check for the ide variable in order to know if we are in a cloud9 + // plugin or in a infra plugin. Pretty nasty, but it will hopefully go + // away soon. + if (this.ide) + this.ide.broadcast(JSON.stringify(error), this.name); + else + this.send(error); + }; + + this.error = function(description, code, message, client) { + return this.workspace.error(description, code, message, client); + }; + + this.send = function(msg, replyTo, scope) { + this.workspace.send(msg, replyTo, scope); }; this.spawnCommand = function(cmd, args, cwd, onerror, ondata, onexit) { - var child = this.activePs = Spawn(cmd, args || [], {cwd: cwd || this.server.workspaceDir}), - out = "", - err = "", - _self = this; + var child = this.activePs = Spawn(cmd, args || [], { + cwd: cwd || this.server.workspaceDir + }); + + var out = ""; + var err = ""; + var _self = this; + child.stdout.on("data", sender("stdout")); child.stderr.on("data", sender("stderr")); @@ -45,8 +62,7 @@ sys.inherits(cloud9Plugin, process.EventEmitter); if (stream == "stderr") { err += s; onerror && onerror(s); - } - else { + } else { out += s; ondata && ondata(s); } @@ -60,11 +76,11 @@ sys.inherits(cloud9Plugin, process.EventEmitter); return child; }; - + this.dispose = function(callback) { callback(); }; - -}).call(cloud9Plugin.prototype); -module.exports = cloud9Plugin; +}).call(Plugin.prototype); + +module.exports = Plugin; diff --git a/server/cloud9/user.js b/server/cloud9/user.js index 28a33adc4a6..6b56aae5e80 100644 --- a/server/cloud9/user.js +++ b/server/cloud9/user.js @@ -123,14 +123,15 @@ User.VISITOR_PERMISSIONS = { this.error = function(description, code, message, client) { //console.log("Socket error: " + description, new Error().stack); var sid = (message || {}).sid || -1; - var error = JSON.stringify({ + var error = { "type": "error", "sid": sid, "code": code, "message": description - }); + }; + if (client) - client.send(error); + client.send(JSON.stringify(error)); else this.broadcast(error); }; diff --git a/server/cloud9/util.js b/server/cloud9/util.js new file mode 100644 index 00000000000..c0a664c1db4 --- /dev/null +++ b/server/cloud9/util.js @@ -0,0 +1,10 @@ +/** + * @copyright 2011, Ajax.org Services B.V. + * @license GPLv3 + */ +exports.extend = function(dest, src) { + for (var prop in src) { + dest[prop] = src[prop]; + } + return dest; +}; \ No newline at end of file diff --git a/server/cloud9/workspace.js b/server/cloud9/workspace.js new file mode 100644 index 00000000000..c9dc5e259b9 --- /dev/null +++ b/server/cloud9/workspace.js @@ -0,0 +1,96 @@ +var lang = require("pilot/lang"); + +var Workspace = module.exports = function(config) { + if (config) + for (var prop in config) + this[prop] = config[prop]; + else + throw new Error("No parameters were passed to Workspace."); + + this.init(); +}; + +(function() { + this.init = function() { + this.workspaceId = this.ide.options.workspaceId; + this.workspaceDir = this.ide.options.workspaceDir; + }; + + this.createPlugins = function (plugins) { + this.plugins = {}; + + for (var name in plugins) { + this.plugins[name] = new plugins[name](this.ide, this); + } + + for (var name in plugins) { + if (this.plugins[name].init) + this.plugins[name].init(); + } + }; + + this.getServerExclude = function(user) { + return lang.arrayToMap(user.getPermissions().server_exclude.split("|")); + }; + + this.execHook = function(hook, user /* varargs */) { + var plugin, hooks; + var args = Array.prototype.slice.call(arguments, 1); + var hook = hook.toLowerCase().trim(); + + var server_exclude = this.getServerExclude(user); + + for (var name in this.plugins) { + if (server_exclude[name]) continue; + + plugin = this.plugins[name]; + hooks = plugin.getHooks(); + if (hooks.indexOf(hook) > -1 && plugin[hook].apply(plugin, args) === true) { + return; + } + } + }; + + this.getExt = function(name) { + return this.plugins[name] || null; + }; + + this.send = function(msg, replyTo, scope) { + if (replyTo) + msg.sid = replyTo.sid; + this.ide.broadcast(JSON.stringify(msg), scope); + }; + + this.sendError = function(error, client) { + if (client) + client.send(JSON.stringify(error)); + else + this.ide.broadcast(error); + }; + + this.error = function(description, code, message, client) { + var sid = (message || {}).sid || -1; + var error = { + "type": "error", + "sid": sid, + "code": code, + "message": description + }; + + this.sendError(error, client || null); + }; + + this.dispose = function(callback) { + var count; + for (var name in this.plugins) { + count += 1; + var plugin = this.plugins[name]; + plugin.dispose(function() { + count -= 1; + if (count == 0) + callback(); + }); + } + }; + +}).call(Workspace.prototype); \ No newline at end of file diff --git a/support/apf b/support/apf index 52f8e185f6f..0a6bcd92aaa 160000 --- a/support/apf +++ b/support/apf @@ -1 +1 @@ -Subproject commit 52f8e185f6f267e0aaeb08ef0c3bc1a4f573d494 +Subproject commit 0a6bcd92aaa10ef05b6d3b348b451d81a670d228 diff --git a/support/jsdav b/support/jsdav index a6cc73351f2..4610fcc2e7f 160000 --- a/support/jsdav +++ b/support/jsdav @@ -1 +1 @@ -Subproject commit a6cc73351f2baf9dca1919d8040011e3b483871f +Subproject commit 4610fcc2e7fcae3de35d9fc8d2adfb7fb85b6d27 diff --git a/support/paths.js b/support/paths.js index 89b72919430..8455ca3ad8d 100644 --- a/support/paths.js +++ b/support/paths.js @@ -2,13 +2,14 @@ * @copyright 2010, Ajax.org B.V. * @license GPLv3 */ - + require("./requireJS-node"); require.paths.unshift(__dirname + "/../server"); require.paths.unshift(__dirname + "/connect/lib"); require.paths.unshift(__dirname + "/asyncjs/lib"); require.paths.unshift(__dirname + "/jsdav/lib"); +require.paths.unshift(__dirname + "/jsdav/support"); require.paths.unshift(__dirname + "/jsdav/support/node-ftp"); require.paths.unshift(__dirname + "/jsdav/support/node-sftp/lib"); require.paths.unshift(__dirname + "/socket.io/lib"); @@ -18,4 +19,4 @@ require.paths.unshift(__dirname + "/lib-v8debug/lib"); require.paths.unshift(__dirname); require.paths.unshift(__dirname + "/../demo/plugin"); -require.paths.unshift(__dirname + "/../demo/template"); \ No newline at end of file +require.paths.unshift(__dirname + "/../demo/template");