From 5acd862c43ae4371b43d6c9fc95c76df1ccce85a Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 1 May 2017 18:46:15 +0400 Subject: [PATCH] move ui code for pluginManager into separate plugin --- configs/ide/default.js | 1 + plugins/c9.ide.plugins/gui.js | 923 +++++++++++++++++++++++++++++ plugins/c9.ide.plugins/manager.js | 925 +++--------------------------- 3 files changed, 988 insertions(+), 861 deletions(-) create mode 100644 plugins/c9.ide.plugins/gui.js diff --git a/configs/ide/default.js b/configs/ide/default.js index 15af4529..cb53d374 100644 --- a/configs/ide/default.js +++ b/configs/ide/default.js @@ -88,6 +88,7 @@ module.exports = function(options) { staticPrefix: staticPrefix + "/plugins/c9.ide.plugins", devel: devel }, + "plugins/c9.ide.plugins/gui", // { // packagePath: "plugins/c9.ide.plugins/test", // staticPrefix: staticPrefix + "/plugins/c9.ide.plugins" diff --git a/plugins/c9.ide.plugins/gui.js b/plugins/c9.ide.plugins/gui.js new file mode 100644 index 00000000..d35aae9c --- /dev/null +++ b/plugins/c9.ide.plugins/gui.js @@ -0,0 +1,923 @@ +define(function(require, exports, module) { + main.consumes = [ + "PreferencePanel", "settings", "ui", "util", "ext", "c9", "Plugin", + "layout", "proc", "menus", "commands", "pluginManager", + "dialog.error", "dialog.info", "tree.favorites", "fs", "tree", "vfs", + "preferences.experimental", "apf", "hub", "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.hub.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 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("
You are in Debug Mode. " + + "" + + "", + 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 ""; + }; + + 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 '' + escapeHTML(x) + ''; + }).join(", ") + "]"; + } + + descriptionBar.$ext.style.overflow = "auto"; + var serviceDesc = '

Provided services [' + provided.length + ']

\ +

' + (provided.length ? formatServices(provided) : "") + '

\ +

Consumed services [' + (consumedList.length - provided.length) + ']

\ +

' + consumedGroups.map(formatServices).join("
") + '

\ +

Dependent services [' + (depList.length - provided.length) + ']

\ +

' + depGroups.map(formatServices).join("
") + '

\ +
'; + descriptionBar.$ext.innerHTML = '
\ +

' + (items.length == 1 + ? '' + escapeHTML(items[0].path) + '' + : (items.length || "no") + " plugins selected") + '

\ +
' + + (items.length ? serviceDesc : "") + + '
'; + + } + 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); + 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; + }, + onclick: function() { + var selected = datagrid.selection.getCursor(); + var tabbehavior = architectApp.services.tabbehavior; + var filePath = selected.packageConfig && selected.packageConfig.filePath; + if (filePath) { + tabbehavior.revealtab({ path: filePath }); + } + }, + }), 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({ + onclick: function() { reloadGridSelection(); }, + }), plugin); + treeBar.setAttribute("contextmenu", mnuCtxTree); + } + + + /***** Methods *****/ + + function reloadModel() { + if (!model) return; + + var packages = pluginManager.packages; + + if (!CORE.pluginManager) { + CORE.pluginManager = 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 && mode == null) { + var href = document.location.href.replace(/[?&]reload=[^&]+/, ""); + href += (href.match(/\?/) ? "&" : "?") + "reload=" + reloadLast.join(","); + window.history.replaceState(window.history.state, null, href); + + showReloadTip(); + updateReloadLastButton(); + } + } + + + function updateReloadLastButton() { + var last = getLastReloaded(); + if (last) { + btnReloadLast.visible = true; + btnReloadLast.textContent = "Reload " + last; + } else { + btnReloadLast.visible = false; + } + } + + function showReloadTip(name) { + if (options.devel) { + var key = commands.getHotkey("reloadLastPlugin"); + if (commands.platform == "mac") + key = apf.hotkeys.toMacNotation(key); + if (!getLastReloaded()) { + showInfo("Reloaded " + name + ". Press " + key + " to reload again.", 3000); + return; + } + } + showInfo("Reloaded " + name + ".", 1000); + } + + 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, + }); + } +}); diff --git a/plugins/c9.ide.plugins/manager.js b/plugins/c9.ide.plugins/manager.js index ab22de35..99dc0c9c 100644 --- a/plugins/c9.ide.plugins/manager.js +++ b/plugins/c9.ide.plugins/manager.js @@ -1,22 +1,14 @@ /*global requirejs*/ define(function(require, exports, module) { main.consumes = [ - "PreferencePanel", "settings", "ui", "util", "ext", "c9", "Plugin", - "layout", "proc", "menus", "commands", - "dialog.error", "dialog.info", "tree.favorites", "fs", "tree", "vfs", - "preferences.experimental", "apf", "hub", "dialog.notification" + "hub", "ext", "c9", "Plugin", "proc", "fs", "tree", "vfs", + "dialog.error", "tree.favorites" ]; main.provides = ["pluginManager", "plugin.manager", "plugin.debug"]; 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; @@ -24,29 +16,18 @@ define(function(require, exports, module) { var proc = imports.proc; var Plugin = imports.Plugin; var util = imports.util; - var qs = require("querystring"); - var apf = imports.apf; var vfs = imports.vfs; var showError = imports["dialog.error"].show; - var showInfo = imports["dialog.info"].show; - var notify = imports["dialog.notification"].show; var favs = imports["tree.favorites"]; - var experimental = imports["preferences.experimental"]; var architectApp = imports.hub.app; - var search = require("../c9.ide.navigate/search"); - var Tree = require("ace_tree/tree"); - var TreeData = require("./managerdp"); var join = require("path").join; var basename = require("path").basename; var dirname = require("path").dirname; var async = require("async"); - var escapeHTML = require("ace/lib/lang").escapeHTML; - var staticPrefix = options.staticPrefix; - var CORE = {}; var TEMPLATES = { "plugin.simple": "Empty Plugin", "plugin.default": "Full Plugin", @@ -54,583 +35,14 @@ define(function(require, exports, module) { "plugin.bundle": "Cloud9 Bundle" }; - var STATE_ENABLED = 1; - var STATE_PARTIAL = 2; - var STATE_MISSING_DEPS = 3; - var STATE_DISABLED = 4; - /***** 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 plugin = new Plugin(); var emit = plugin.getEmitter(); - var model, datagrid, filterbox; - var btnInstall, btnUninstall, btnServices, btnReadme, btnReload; - var btnReloadLast; - var localPlugins; var disabledPlugins = Object.create(null); var packages = Object.create(null); - 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("
You are in Debug Mode. " - + "" - + "", - false); - - document.getElementById(".pm_btn1").onclick = function() { commands.exec("openPluginManager") }; - btnReloadLast = document.getElementById(".pm_btn2"); - btnReloadLast.onclick = function() { commands.exec("reloadLastPlugin") }; - updateReloadLastButton(); - - readAvailablePlugins(function() { - if (sessionStorage.localPackages) { - loadPackage( - util.safeParseJson(sessionStorage.localPackages) || [] - ); - } - var updateSessionStorage = function() { - 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)); - }; - plugin.on("enablePackage", updateSessionStorage); - plugin.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() { - createNewPlugin(name); - } - }), 210, plugin); - }); - - ext.on("register", function() { - setTimeout(reloadModel); - }); - } - - var drawn; - function draw(e) { - if (drawn) return; - drawn = true; - - 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); - } - }), - btnReload = 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 ""; - }; - - 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; - }); - addAllProviders(consumedMap); - var consumedList = Object.keys(consumedMap); - var consumedGroups = splitToGroups(consumedList, consumedMap); - - var dependents = Object.create(null); - provided.forEach(function(service) { - dependents[service] = 0; - }); - 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 '' + escapeHTML(x) + ''; - }).join(", ") + "]"; - } - - descriptionBar.$ext.style.overflow = "auto"; - var serviceDesc = '

Provided services [' + provided.length + ']

\ -

' + (provided.length ? formatServices(provided) : "") + '

\ -

Consumed services [' + (consumedList.length - provided.length) + ']

\ -

' + consumedGroups.map(formatServices).join("
") + '

\ -

Dependent services [' + (depList.length - provided.length) + ']

\ -

' + depGroups.map(formatServices).join("
") + '

\ -
'; - descriptionBar.$ext.innerHTML = '
\ -

' + (items.length == 1 - ? '' + escapeHTML(items[0].path) + '' - : (items.length || "no") + " plugins selected") + '

\ -
' - + (items.length ? serviceDesc : "") - + '
'; - - } - 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; - addAllDependents(deps); - 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); - 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; - }, - onclick: function() { - var selected = datagrid.selection.getCursor(); - var tabbehavior = architectApp.services.tabbehavior; - var filePath = selected.packageConfig && selected.packageConfig.filePath; - if (filePath) { - tabbehavior.revealtab({ path: filePath }); - } - }, - }), 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({ - onclick: function() { reloadGridSelection(); }, - }), plugin); - treeBar.setAttribute("contextmenu", mnuCtxTree); - } - - /***** Methods *****/ function readAvailablePlugins(callback) { @@ -643,193 +55,10 @@ define(function(require, exports, module) { if (!/(directory|folder)$/.test(stat.mime)) return; if (!/[._]/.test(name[0])) available.push(name); }); - localPlugins = available.concat(); - reloadModel(); callback && callback(null, available); }); } - function reloadModel() { - if (!model) return; - - if (!CORE.pluginManager) { - CORE.pluginManager = 1; - 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 console.error("Broken plugin", plugin); - 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 createNewPlugin(template) { if (!template) template = "c9.ide.default"; @@ -871,7 +100,11 @@ define(function(require, exports, module) { c9.sourceDir ? [ "cp", util.escapeShell(c9.sourceDir + "/plugins/c9.ide.plugins/" + tarSourcePath), util.escapeShell(tarPathAbsolute) ] - : [ "curl", "-L", util.escapeShell(url), "-o", util.escapeShell(tarPathAbsolute) ] + : [ "curl", "-L", + (architectApp.services.onlinedev_helper ? "-k" : ""), // ignore certificate errors in dev mode + util.escapeShell(url), + "-o", util.escapeShell(tarPathAbsolute) + ].filter(Boolean) ).join(" ")] }, function(err, stderr, stdout) { if (err) @@ -899,7 +132,9 @@ define(function(require, exports, module) { // Select and expand the folder of the plugin tree.expandAndSelect(path); - readAvailablePlugins(reloadModel); + readAvailablePlugins(function(e) { + emit("change"); + }); }); }); }); @@ -907,19 +142,7 @@ define(function(require, exports, module) { }); } - function reload(names) { - var nodes = names.split(/\s*,\s*/).map(function(name) { - if (packages[name]) - return { packageConfig: packages[name] }; - return { path: name }; - }); - - reloadGridSelection(null, nodes); - } - - function reloadGridSelection(mode, nodes) { - if (!nodes) - nodes = datagrid.selection.getSelectedNodes(); + function reload(nodes, mode) { var reloadLast = []; nodes.forEach(function(node) { var id; @@ -945,16 +168,9 @@ define(function(require, exports, module) { else delete disabledPlugins[id]; }); - if (reloadLast.length && mode == null) { - var href = document.location.href.replace(/[?&]reload=[^&]+/, ""); - href += (href.match(/\?/) ? "&" : "?") + "reload=" + reloadLast.join(","); - window.history.replaceState(window.history.state, null, href); - - showReloadTip(); - updateReloadLastButton(); - } + return reloadLast; } - + function checkPluginsWithMissingDependencies() { var services = architectApp.services; var plugins = []; @@ -982,33 +198,6 @@ define(function(require, exports, module) { }); } - function updateReloadLastButton() { - var last = getLastReloaded(); - if (last) { - btnReloadLast.visible = true; - btnReloadLast.textContent = "Reload " + last; - } else { - btnReloadLast.visible = false; - } - } - - function showReloadTip() { - if (options.devel) { - var key = commands.getHotkey("reloadLastPlugin"); - if (commands.platform == "mac") - key = apf.hotkeys.toMacNotation(key); - if (!getLastReloaded()) { - showInfo("Reloaded " + name + ". Press " + key + " to reload again.", 3000); - return; - } - } - showInfo("Reloaded " + name + ".", 1000); - } - - function getLastReloaded() { - return qs.parse(document.location.search.substr(1)).reload; - } - function getAllPlugins(includeDisabled) { var config = architectApp.config; Object.keys(packages).forEach(function(n) { @@ -1181,7 +370,7 @@ define(function(require, exports, module) { packages[name].__error = new Error(message + "\n" + err.message); packages[name].loading = false; - reloadModel(); + emit("change"); callback && callback(err); } @@ -1219,7 +408,7 @@ define(function(require, exports, module) { if (err) return addError("Error loading plugins", err); if (packages[name]) packages[name].loading = false; - reloadModel(); + emit("change"); callback && callback(err, result); }); } @@ -1389,7 +578,7 @@ define(function(require, exports, module) { pluginConfig.__userDisabled = true; } - reloadModel(); + emit("change"); } function unloadPluginConfig(plugin) { @@ -1488,34 +677,10 @@ define(function(require, exports, module) { /***** 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; - - model = null; - datagrid = null; - filterbox = null; - btnInstall = null; - btnUninstall = null; - localPlugins = null; disabledPlugins = null; + plugin = null; }); /***** Register and define API *****/ @@ -1527,12 +692,27 @@ define(function(require, exports, module) { /** * */ - createNewPlugin: createNewPlugin, - + readAvailablePlugins: readAvailablePlugins, + /** * */ - loadPackage: loadPackage, + createNewPlugin: createNewPlugin, + + /** + * + */ + getAllPlugins: getAllPlugins, + + /** + * + */ + addAllDependents: addAllDependents, + + /** + * + */ + addAllProviders: addAllProviders, /** * @@ -1542,18 +722,41 @@ define(function(require, exports, module) { /** * */ - addStaticPlugin: addStaticPlugin, - + loadPackage: loadPackage, + + /** + * + */ + loadPlugins: loadPlugins, + /** * */ reload: reload, - /* - * @ignore + /** + * */ - get datagrid() { return datagrid; }, + getServiceNamesByPath: getServiceNamesByPath, + + /** + * + */ + unloadPlugins: unloadPlugins, + + /** + * + */ + unloadPluginConfig: unloadPluginConfig, + + /** + * + */ + addStaticPlugin: addStaticPlugin, + + get packages() { return packages; }, + get disabledPlugins() { return disabledPlugins; }, }); var shim = new Plugin();