From dcc9a063400835014237a619f300e33b2949460a Mon Sep 17 00:00:00 2001 From: Lennart kats Date: Wed, 11 Feb 2015 11:43:02 +0000 Subject: [PATCH] Fix +6131 no method onError --- configs/client-default-local.js | 158 +++++++++++++++ node_modules/vfs-socket/worker.js | 2 +- package.json | 56 +++--- plugins/c9.ide.login/login.css | 36 ++++ plugins/c9.ide.login/login.js | 194 ++++++++++++++++++ plugins/c9.login.client/bootstrap.js | 283 +++++++++++++++++++++++++++ 6 files changed, 700 insertions(+), 29 deletions(-) create mode 100644 configs/client-default-local.js create mode 100644 plugins/c9.ide.login/login.css create mode 100644 plugins/c9.ide.login/login.js create mode 100644 plugins/c9.login.client/bootstrap.js diff --git a/configs/client-default-local.js b/configs/client-default-local.js new file mode 100644 index 00000000..b2ed60a1 --- /dev/null +++ b/configs/client-default-local.js @@ -0,0 +1,158 @@ +var join = require("path").join; + +module.exports = function(options) { + var config = require("./client-default")(options); + return module.exports.makeLocal(config, options); +}; + +module.exports.makeLocal = function(config, options) { + var c9Ws = options.remoteWorkspace; // true when opening c9 workspace as local + var root = options.workspaceDir; + + var nodeBin = options.nodeBin || ["node"]; + var settingDir = options.settingDir || options.installPath; + + if (!c9Ws) { + // Local version + options.local = true; + options.projectName = root.substr(root.lastIndexOf("/") + 1); + options.debug = 2; + options.env = "local"; + } + + for (var i = config.length - 1; i >= 0; i--) { + // if (config[i].packagePath == "plugins/c9.cli.bridge/bridge") + // config[i].port = 55556; + if (config[i].packagePath == "plugins/c9.ide.welcome/welcome" && !c9Ws) { + config[i].intro = + "Welcome to your brand new Cloud9. Use this welcome screen " + + "to tweak the look & feel of the Cloud9 user interface. " + + "If you prefer a more advanced IDE experience, you can choose " + + "to change the layout below. " + + "\n\n" + + "On the right you can find videos and documentation for Cloud9 " + + "IDE. Happy Coding!"; + } + // else if (config[i].packagePath == "plugins/c9.ide.login/login") { + // config.splice(i, 1); + // } + else if (config[i].packagePath == "plugins/c9.ide.run/run" && !c9Ws) { + config[i].runnerPath = join(settingDir, "/runners"); + } + else if (config[i].packagePath == "plugins/c9.ide.ui/menus") { + config[i].autoInit = false; + } + else if (config[i].packagePath == "plugins/c9.ide.save/autosave") { + config[i].slowChangeTimeout = 500; + } + else if (config[i].packagePath == "plugins/c9.ide.run.build/build" && !c9Ws) { + config[i].builderPath = join(settingDir, "/builders"); + } + else if (config[i].packagePath == "plugins/c9.ide.editors/metadata" && !c9Ws) { + config[i].path = join(settingDir, "/metadata"); + config[i].changeCheckInterval = 2000; + } + else if (config[i].packagePath == "plugins/c9.ide.feedback/feedback") { + config[i].screenshotSupport = false; + } + // else if (config[i].packagePath == "plugins/c9.ide.feedback/feedback") { + // config[i] = { + // packagePath : "plugins/c9.ide.help/help", + // staticPrefix : options.staticPrefix + "/plugins/c9.ide.help" + // }; + // } + + else if (config[i].packagePath == "plugins/c9.core/c9") { + config[i].local = true; + } + else if (config[i].packagePath == "plugins/c9.ide.clipboard/html5") + config[i].packagePath = "plugins/c9.ide.local/clipboard"; + else if (config[i].packagePath == "plugins/c9.ide.configuration/configure") + config[i].pathFromFavorite = true; + else if (config[i].packagePath == "plugins/c9.core/settings" && !c9Ws) { + // todo: Don't show console when opening a file? + // config[i].template = ; + config[i].projectConfigPath = join(settingDir, ""); + config[i].userConfigPath = join(settingDir, ""); + config[i].stateConfigPath = join(settingDir, ""); + } else if (config[i].packagePath == "plugins/c9.ide.log/log" && !c9Ws) { + config[i].source = "desktop"; + } else if (config[i].packagePath == "plugins/c9.ide.info/info" && c9Ws) { + config[i].packagePath = "plugins/c9.ide.local/info"; + } else if (config[i].packagePath == "plugins/c9.ide.ui/menus" && c9Ws) { + config[i].autoInit = false; + } else if (config[i].packagePath == "plugins/c9.ide.tree/tree") { + config[i].defaultExpanded = !config.hosted; + } + } + + // Add local modules + var includes = [{ + packagePath: "plugins/c9.ide.local/local", + options: options, + }, { + packagePath: "plugins/c9.ide.local/windowframe", + staticPrefix: options.staticPrefix + "/plugins/c9.ide.local" + }, { + packagePath: "plugins/c9.ide.local/update", + host: options.update && options.update.host || "localhost", // "update.c9.io", + port: options.update && options.update.port || "8888", // "443" + path: options.update && options.update.path, + protocol: options.update && options.update.protocol, + installPath: options.correctedInstallPath, + bashBin: options.bashBin, + nodeBin: nodeBin + }, { + packagePath: "plugins/c9.ide.local/projectmanager" + }, { + packagePath: "plugins/c9.ide.local/open" + }, { + packagePath: "plugins/c9.ide.local/nativemenus" + }, !c9Ws && { + packagePath: "plugins/c9.ide.local/info", + installPath: options.correctedInstallPath, + settingDir: settingDir, + cookie: options.user.cookie, + user: { + id: options.user.id, + name: options.user.name, + fullname: options.user.fullname, + email: options.user.email, + pubkey: options.user.pubkey + }, + project: { + id: options.project.id, + name: options.project.name, + contents: options.project.contents, + descr: options.project.descr + } + }].filter(Boolean); + + var excludes = c9Ws ? {} : { + "plugins/c9.ide.newresource/open": true, + "plugins/c9.ide.info/info": true, + // "plugins/c9.ide.login/login": true, + "plugins/c9.ide.collab/connect": true, + "plugins/c9.ide.collab/collab": true, + "plugins/c9.ide.collab/collabpanel": true, + "plugins/c9.ide.collab/workspace": true, + "plugins/c9.ide.collab/util": true, + "plugins/c9.ide.collab/ot/document": true, + "plugins/c9.ide.collab/cursor_layer": true, + "plugins/c9.ide.collab/author_layer": true, + "plugins/c9.ide.collab/timeslider/timeslider": true, + "plugins/c9.ide.notifications/notifications": true, + "plugins/c9.ide.collab/members/members_panel": true, + "plugins/c9.ide.collab/share/share": true, + "plugins/c9.ide.collab/members/members": true, + "plugins/c9.ide.collab/chat/chat": true, + "plugins/c9.ide.feedback/nps": true, + "plugins/c9.ide.download/download": true + }; + + config = config.concat(includes).filter(function (p) { + return !excludes[p] && !excludes[p.packagePath]; + }); + + return config; +}; diff --git a/node_modules/vfs-socket/worker.js b/node_modules/vfs-socket/worker.js index 0fc07f34..15d17904 100644 --- a/node_modules/vfs-socket/worker.js +++ b/node_modules/vfs-socket/worker.js @@ -168,7 +168,7 @@ function Worker(vfs) { streams[id] = stream; stream.id = id; stream.on("error", function(err) { - remote.onError(id, err); + remote.onError && remote.onError(id, err); }); if (stream.readable) { stream.on("data", function (chunk) { diff --git a/package.json b/package.json index 2719bccc..4e79f2a4 100644 --- a/package.json +++ b/package.json @@ -47,31 +47,31 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#9f588f9152", - "c9.ide.language.css": "#89deece6c0", - "c9.ide.language.generic": "#50161ba888", - "c9.ide.language.html": "#e393db66ae", - "c9.ide.language.html.diff": "#31965d98b3", - "c9.ide.language.javascript": "#5b6237f875", - "c9.ide.language.javascript.immediate": "#0f7c640825", - "c9.ide.language.javascript.eslint": "#8fbaa9cc96", - "c9.ide.language.javascript.tern": "#3d678a103a", - "c9.ide.language.javascript.infer": "#1ae097af44", - "c9.ide.language.jsonalyzer": "#45a20496be", - "c9.ide.collab": "#fabc22dda7", - "c9.ide.local": "#d5c324ee5b", - "c9.ide.find": "#be3bca94b7", - "c9.ide.find.infiles": "#462928475c", - "c9.ide.find.replace": "#fe41fa768d", - "c9.ide.run.debug": "#b734a2a47f", + "c9.ide.language": "#39d454da5b", + "c9.ide.language.css": "#abbf350903", + "c9.ide.language.generic": "#2d5927b0aa", + "c9.ide.language.html": "#6c2477bd42", + "c9.ide.language.html.diff": "#cf121289b0", + "c9.ide.language.javascript": "#b6b804d7d4", + "c9.ide.language.javascript.immediate": "#bd0ff1d429", + "c9.ide.language.javascript.eslint": "#8e18a29cb0", + "c9.ide.language.javascript.tern": "#6333e6ba9a", + "c9.ide.language.javascript.infer": "#e31348b13f", + "c9.ide.language.jsonalyzer": "#a0d50228e0", + "c9.ide.collab": "#60a887d616", + "c9.ide.local": "#cd387994ad", + "c9.ide.find": "#025306c379", + "c9.ide.find.infiles": "#b7d3bce241", + "c9.ide.find.replace": "#06445a9d0b", + "c9.ide.run.debug": "#5b80e46ea7", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", - "c9.ide.ace.keymaps": "#422e83553b", - "c9.ide.ace.repl": "#26bca9ee17", + "c9.ide.ace.keymaps": "#1fc125c28f", + "c9.ide.ace.repl": "#c3c573fd5e", "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", "c9.ide.ace.stripws": "#34426a03d1", - "c9.ide.behaviors": "#f5aaf10aff", + "c9.ide.behaviors": "#1e3494a4af", "c9.ide.closeconfirmation": "#a28bfd8272", "c9.ide.configuration": "#b8470f4107", "c9.ide.dialog.wizard": "#a588b64050", @@ -81,25 +81,25 @@ "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#e9ba147cc2", "c9.ide.installer": "#24e7d6f399", - "c9.ide.mount": "#c9d598b254", - "c9.ide.navigate": "#7985b5a50b", + "c9.ide.mount": "#cbb1a7947b", + "c9.ide.navigate": "#67983493b9", "c9.ide.newresource": "#9a7464cc47", "c9.ide.openfiles": "#28a4f5af16", "c9.ide.preview": "#3c4dded23f", "c9.ide.preview.browser": "#be197b0464", "c9.ide.preview.markdown": "#bf952685f6", - "c9.ide.pubsub": "#e6526a20f7", + "c9.ide.pubsub": "#570969cd70", "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", "c9.ide.remote": "#37773d905b", - "c9.ide.run": "#9bf773dd1b", - "c9.ide.run.build": "#2ba0107f97", - "c9.ide.save": "#4cf2ae332c", - "c9.ide.terminal.monitor": "#8e025b3ae1", + "c9.ide.run": "#002336effe", + "c9.ide.run.build": "#1917b4cc52", + "c9.ide.save": "#c869a0db76", + "c9.ide.terminal.monitor": "#198045cbbd", "c9.ide.theme.flat": "#5c7c27ab74", "c9.ide.threewaymerge": "#229382aa0b", "c9.ide.undo": "#b028bcb4d5", - "c9.ide.upload": "#8726fed462", + "c9.ide.upload": "#90dc9a8509", "c9.ide.welcome": "#b4be5c22a5" } } \ No newline at end of file diff --git a/plugins/c9.ide.login/login.css b/plugins/c9.ide.login/login.css new file mode 100644 index 00000000..3a5d245e --- /dev/null +++ b/plugins/c9.ide.login/login.css @@ -0,0 +1,36 @@ +.c9-menu-btn.titlebar{ + position: absolute; + z-index: 100000000; + right: 24px; + top: 1px; + height: 19px; +} + +.c9-menu-btn.titlebar:not(.c9-menu-btnDown){ + height: 18px; + border-bottom: 1px solid black; +} + +.fullscreen>.btnName{ + display: none; +} + +.btnName.c9-menu-btnIcon{ + text-indent: -2000px; + overflow: hidden; +} +.btnName{ + padding: @menu-name-button-padding; + margin-left: @menu-name-button-diff !important; +} +.btnName.c9-menu-btnmenuDown{ + margin-left: 0 !important; +} +.btnName .icon{ + background-size: @menu-name-button-icon-width @menu-name-button-icon-height !important; + top: @menu-name-button-icon-top !important; + left: @menu-name-button-icon-left !important; + width: @menu-name-button-icon-width; + height: @menu-name-button-icon-height; + border-radius: @menu-name-button-icon-border-radius; +} \ No newline at end of file diff --git a/plugins/c9.ide.login/login.js b/plugins/c9.ide.login/login.js new file mode 100644 index 00000000..817480a5 --- /dev/null +++ b/plugins/c9.ide.login/login.js @@ -0,0 +1,194 @@ +define(function(require, exports, module) { + main.consumes = [ + "Plugin", "ui", "menus", "info", "layout", "http", "util", + "vfs.endpoint", "auth", "dialog.alert", "c9" + ]; + main.provides = ["login"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var c9 = imports.c9; + var menus = imports.menus; + var layout = imports.layout; + var http = imports.http; + var util = imports.util; + var info = imports.info; + var auth = imports.auth; + var alert = imports["dialog.alert"].show; + + var vfsEndpoint = imports["vfs.endpoint"]; + + /***** Initialization *****/ + + var ideBaseUrl = options.ideBaseUrl; + var dashboardUrl = options.dashboardUrl; + var accountUrl = options.accountUrl; + var lastUser, mnuUser; + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var loaded = false; + function load() { + if (loaded) return false; + loaded = true; + + info.getUser(function(err, user) { + updateButton({user: user}); + }); + + auth.on("relogin", onReLogin); + } + + /***** Methods *****/ + + function updateButton(e) { + var user = e.user; + if (lastUser && lastUser.id == user.id) + return; + plugin.cleanUp(); + info.on("change", updateButton, plugin); + createButton(user); + lastUser = user; + + emit.sticky("ready", { name: user.fullname, id: user.id }, plugin); + } + + function createButton(user) { + var name = "user_" + user.id; + + // todo cleanup seems to not work well + // without this menu is empty after logging out and back in + if (lastUser) + menus.remove("user_" + lastUser.id); + menus.remove(name); + + var parent = layout.findParent(plugin); + + // Insert CSS + ui.insertCss(require("text!./login.css"), plugin); + + // Create Menu + mnuUser = new ui.menu(); + plugin.addElement(mnuUser); + + // Add named button + var icon = util.getGravatarUrl(user.email, 32, ""); + menus.addItemByPath(name + "/", mnuUser, 110000, plugin); + + // Add Divider + ui.insertByIndex(parent, new ui.divider({ + skin: "c9-divider-double", + "class" : "extrasdivider" + }), 870, plugin); + + // Add sub menu items + var c = 500; + menus.addItemByPath(name + "/Dashboard", new ui.item({ + onclick: function() { window.open(dashboardUrl); } + }), c += 100, plugin); + menus.addItemByPath(name + "/Account", new ui.item({ + onclick: function() { window.open(accountUrl); } + }), c += 100, plugin); + menus.addItemByPath(name + "/Home", new ui.item({ + onclick: function() { window.open(ideBaseUrl); } + }), c += 100, plugin); + + if (!options.noLogout) { + menus.addItemByPath(name + "/~", new ui.divider(), c += 100, plugin); + menus.addItemByPath(name + "/Log out", new ui.item({ + onclick: function() { + if (!c9.local) + return signout(); + auth.logout(function() { + info.login(true); + }); + } + }), c += 100, plugin); + } + + var button = menus.get(name).item; + button.setAttribute("class", "btnName"); + button.setAttribute("icon", icon); + button.setAttribute("iconsize", "16px 16px"); + button.setAttribute("tooltip", user.fullname); + button.setAttribute("caption", user.fullname); + ui.insertByIndex(parent, button, 600, plugin); + + if (c9.local) { + function minimize(){ + apf.document.documentElement.appendChild(button); + ui.setStyleClass(button.$ext, "titlebar"); + } + function restore(){ + ui.insertByIndex(parent, button, 870, plugin); + ui.setStyleClass(button.$ext, "", ["titlebar"]); + } + + menus.on("minimize", minimize, plugin); + menus.on("restore", restore, plugin); + + if (menus.minimized) + minimize(); + } + } + + function signout() { + vfsEndpoint.clearCache(); + auth.logout(function() { location.href = ideBaseUrl; }); + } + + function onReLogin() { + if (!c9.local) { + alert("Logged out", + "You have been logged in as a different user", + "Please hit OK to reload the IDE.", + function() { + vfsEndpoint.clearCache(); + auth.logout(function() { + document.location.reload(); + }); + }); + } + } + + /***** Lifecycle *****/ + + plugin.on("load", function() { + load(); + }); + plugin.on("enable", function() { + + }); + plugin.on("disable", function() { + + }); + plugin.on("unload", function() { + loaded = false; + }); + + /***** Register and define API *****/ + + /** + * + **/ + plugin.freezePublicAPI({ + get menu(){ return mnuUser; }, + + _events: [ + /** + * @event ready + */ + "ready" + ], + createButton: createButton, + updateButton: updateButton + }); + + register(null, { + login: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.login.client/bootstrap.js b/plugins/c9.login.client/bootstrap.js new file mode 100644 index 00000000..9f62d313 --- /dev/null +++ b/plugins/c9.login.client/bootstrap.js @@ -0,0 +1,283 @@ +(function(global) { +"use strict"; + +var token = ""; + +var auth = global.auth = function(options) { + // can only be called once + global.auth = null; + + var onLoad = options.onLoad; + var preload = options.preload || noop; + var authorized = options.authorized || noop; + var background = options.background || noop; + + importCssString("html.fulliframe, body.fulliframe {\ + overflow: hidden;\ + margin: auto;\ + height: 100%;\ + width: 100%;\ + }"); + + function noop(callback) { callback(); } + + if (onLoad) { + auth.parallel([ + background, + auth.serial([ + auth.parallel([ + preload, + login + ]), + authorized, + ]) + ])(done); + } + + function login(callback, errback) { + var oauth = new Auth(options.clientId, options.authorizationUrl, options.loginHint); + + oauth.authorize(true, function(err, _token) { + if (err) + return iframeLogin(); + + token = _token.access_token; + callback(null, token); + }); + + function iframeLogin() { + errback && errback(); + oauth.authorize(false, function(err, _token) { + if (err) return callback(err); + token = _token.access_token; + callback(null, token); + }); + } + + return function cancel() { + oauth.cancel(); + }; + } + + function done(err) { + onLoad(err, token); + } + + return { + login: login + }; +}; + +function bindScript(script) { + if (typeof script == "function") + return script; + else + return loadScript.bind(null, script, token); +} + +auth.serial = function(list) { + return function(callback) { + serial(list.map(bindScript), callback); + }; +}; + +auth.parallel = function(list) { + return function(callback) { + parallel(list.map(bindScript), callback); + }; +}; + +function loadScript(path, token, callback) { + var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement; + var s = document.createElement('script'); + + var and = path.indexOf("?") >= 0 ? "&" : "?"; + s.src = path + (token ? and + "access_token=" + encodeURIComponent(token) : ""); + head.appendChild(s); + + s.onload = s.onreadystatechange = function(_, isAbort) { + if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") { + s = s.onload = s.onreadystatechange = null; + if (!isAbort) + callback(); + } + }; +} + +// copied from ace/lib/dom +function importCssString(cssText) { + var style; + + if (document.createStyleSheet) { + style = document.createStyleSheet(); + style.cssText = cssText; + } else { + style = document.createElementNS + ? document.createElementNS("http://www.w3.org/1999/xhtml", "style") + : document.createElement("style"); + + style.appendChild(document.createTextNode(cssText)); + + (document.head || document.getElementsByTagName("head")[0] || document.documentElement).appendChild(style); + } +} + +function serial(handlers, callback) { + (function loop(i) { + if (i >= handlers.length) return callback(); + + handlers[i](function(err) { + if (err) return callback(err); + + loop(i+1); + }); + })(0); +} + +function parallel(handlers, callback) { + var hadErr = false; + var count = 0; + handlers.forEach(function(handler) { + handler(function(err) { + if (hadErr) return; + if (err) { + hadErr = true; + return callback(err); + } + count += 1; + if (count == handlers.length) + return callback(); + }); + }); +} + +// install exactly one global listener +var listeners = {}; +window.addEventListener("message", function(e) { + var token = e.data.token; + if (token) { + for (var url in listeners) { + if (url.indexOf(e.origin) === 0) { + var callback = listeners[url][token.state]; + delete listeners[url][token.state]; + if (callback) callback(null, token); + + // make sure later listeners can't steal the token + e.data.token = null; + break; + } + } + } +}, true); + + +function Auth(clientId, authorizationUrl, loginHint) { + this.clientId = clientId; + this.authorizationUrl = authorizationUrl; + this.loginHint = loginHint; + listeners[authorizationUrl] = {}; +} + +Auth.prototype.authorize = function(immediate, callback) { + if (typeof immediate == "function") + return this.authorize({}, immediate); + + immediate = immediate || false; + + var that = this; + this.state = uid(15); + + var url = this.authorizationUrl + + "?response_type=postmessage" + + "&client_id=" + encodeURIComponent(this.clientId) + + "&state=" + encodeURIComponent(this.state) + + "&style=overlay"; + + if (this.loginHint) + url += "&login_hint=" + encodeURIComponent(this.loginHint || ""); + + if (immediate) + url += "&immediate=1"; + + var frame = this._createFrame(url, immediate); + var timeout = immediate ? 3000 : 0; + + if (timeout) { + var timer = setTimeout(function() { + that._unpoll(); + callback(new Error("Login timed out")); + }, timeout); + } + + this._removeFrame = function() { + clearTimeout(timer); + + frame.parentNode.removeChild(frame); + document.documentElement.className = document.documentElement.className.replace(/\bfulliframe\b/, ""); + document.body.className = document.body.className.replace(/\bfulliframe\b/, ""); + that._removeFrame = null; + }; + + this._poll(function(err, token) { + if (that._removeFrame) + that._removeFrame(); + + if (err) + return callback(err); + + if (token.error) { + err = new Error(token.error); + err.code = token.error_code; + return callback(err); + } + + that.token = token; + return callback(null, token); + }); +}; + +Auth.prototype.cancel = function() { + this._unpoll(); + if (this._removeFrame) + this._removeFrame(); +}; + +Auth.prototype._createFrame = function(url, hidden) { + var frame = document.createElement("iframe"); + frame.setAttribute("src", url); + frame.setAttribute("frameborder", "0"); + if (hidden) { + frame.style.width = "1000px"; + frame.style.height = "1000px"; + frame.style.left = "-10000px"; + } + else { + frame.style.width = "100%"; + frame.style.height = "100%"; + frame.style.zIndex = "300000"; + document.documentElement.className += " fulliframe"; + document.body.className += " fulliframe"; + } + frame.style.position = "absolute"; + document.body.appendChild(frame); + return frame; +}; + +Auth.prototype._poll = function(callback) { + listeners[this.authorizationUrl][this.state] = callback; +}; + +Auth.prototype._unpoll = function() { + delete listeners[this.authorizationUrl][this.state]; +}; + +function uid(length) { + var buf = new Uint8Array(new ArrayBuffer(length)); + (window.crypto || window.msCrypto).getRandomValues(buf); + + return btoa(Array.prototype.reduce.call(buf, function(s, c) { + return s + String.fromCharCode(c); + }, "")).slice(0, length); +} + +})(this); \ No newline at end of file