define(function(require, exports, module) { main.consumes = [ "Plugin", "layout.preload", "c9", "ui", "dialog.alert", "settings", "commands", "dialog.question", "anims" ]; main.provides = ["layout"]; return main; function main(options, imports, register) { var c9 = imports.c9; var Plugin = imports.Plugin; var settings = imports.settings; var commands = imports.commands; var alert = imports["dialog.alert"].show; var question = imports["dialog.question"]; var preload = imports["layout.preload"]; var anims = imports.anims; var ui = imports.ui; var markup = require("text!./layout.xml"); // pre load themes require("text!./themes/default-dark.less"); require("text!./themes/default-dark-gray.less"); require("text!./themes/default-light-gray.less"); require("text!./themes/default-light.less"); require("text!./themes/default-flat-light.less"); require("text!./themes/default-flat-dark.less"); /***** Initialization *****/ var plugin = new Plugin("Ajax.org", main.consumes); var emit = plugin.getEmitter(); var dashboardUrl = options.dashboardUrl || "/dashboard.html"; var logobar, removeTheme, theme; var c9console, menus, tabManager, panels; var userLayout, ignoreTheme, notify, svg; var loaded = false; function load(){ if (loaded) return false; loaded = true; settings.on("read", function(){ updateTheme(true); userLayout = settings.get("user/general/@layout"); settings.on("user/general", function(){ var newlayout = settings.get("user/general/@layout"); if (newlayout != userLayout) { userLayout = newlayout; setBaseLayout(userLayout); } }); }, plugin); settings.on("user/general/@skin", function(){ !ignoreTheme && updateTheme(); }, plugin); plugin.on("newListener", function(type, listener){ if (type == "eachTheme") listener({}); }, plugin); if (!ui.packedThemes) { var theme = settings.get("user/general/@skin"); ui.defineLessLibrary(require("text!./themes/default-" + theme + ".less"), plugin); ui.defineLessLibrary(require("text!./less/lesshat.less"), plugin); ui.insertCss(require("text!./keyframes.css") .replace(/@\{image-path\}/g, options.staticPrefix + "/images"), false, plugin); ui.insertCss(require("text!./less/main.less"), options.staticPrefix, plugin); } draw(); } var drawn = false; function draw(){ if (drawn) return; drawn = true; // Load the skin ui.insertSkin({ "data" : require("text!./skins.xml"), "media-path" : options.staticPrefix + "/images/", "icon-path" : options.staticPrefix + "/icons/" }, plugin); // Create UI elements ui.insertMarkup(null, markup, plugin); var hboxMain = plugin.getElement("hboxMain"); var colRight = plugin.getElement("colRight"); hboxMain.$handle.setAttribute("id", "splitterPanelLeft"); colRight.parentNode.$handle.setAttribute("id", "splitterPanelRight"); plugin.addElement(hboxMain.$handle); plugin.addElement(colRight.parentNode.$handle); // Intentionally global window.sbShared = plugin.getElement("sbShared"); // update c9 main logo link logobar = plugin.getElement("logobar"); if (c9.hosted) { var mainlogo = logobar.$ext.getElementsByClassName('mainlogo'); if (mainlogo && (mainlogo = mainlogo[0])) { mainlogo.title = "back to dashboard"; mainlogo.href = dashboardUrl; mainlogo.innerHTML = "Dashboard"; } } // Offline // preload the offline images programmatically: [ "noconnection.png", "close_tab_btn.png" ].forEach(function(p) { var img = new Image(); img.src = options.staticPrefix + "/images/" + p; }); window.addEventListener("resize", resize, false); window.addEventListener("focus", resize, false); setGeckoMask(); plugin.addOther(function(){ window.removeEventListener("resize", resize, false); window.removeEventListener("focus", resize, false); }); emit("draw"); } var allowedThemes = { "dark": 1, "dark-gray": 1, "light-gray": 1, "light": 1, "flat-light": 1, "flat-dark": 1 }; function updateTheme(noquestion, type) { var sTheme = settings.get("user/general/@skin"); if (!allowedThemes[sTheme]) sTheme = "dark"; if (noquestion === undefined) noquestion = !theme; var oldTheme = theme; if (sTheme !== theme) { // Set new Theme theme = sTheme; if (ui.packedThemes) { preload.getTheme(theme, function(err, theme) { if (err) return; // Remove Current Theme if (removeTheme) removeTheme(); var url = options.staticPrefix.replace(/c9.ide.layout.classic\/?$/, ""); theme = theme.replace(/(url\(["']?)\/static\/plugins\//g, function(_, x) { return x + url; }); // Load the theme css ui.insertCss(theme, false, { addOther: function(remove){ removeTheme = remove; } }); changeTheme(); }); } else changeTheme(); } function changeTheme() { if (!oldTheme) return; emit("eachTheme", { changed: true }); var auto = emit("themeChange", { theme: theme, oldTheme: oldTheme, type: type }) !== false; setGeckoMask(); if (noquestion) return; if (auto) return emit("themeDefaults", { theme: theme, type: type }); question.show("Set default colors?", "Would you like to reset colors to their default value?", "Plugins like the terminal, the output window and others " + "have default colors based on the main theme. Click Yes to " + "reset the colors to the default colors for this theme.", function(){ // yes emit("themeDefaults", { theme: theme, type: type }); }, function(){ // no }); } } function proposeLayoutChange(kind, force, type) { if (!force && settings.getBool("user/general/@propose")) return; question.show("Change the Main Cloud9 Theme", "Would you like to change the main theme to a " + kind + " theme?", "Click Yes to change the theme or No to keep the current theme.", function(){ // yes ignoreTheme = true; var theme = {"dark": "flat-dark", "light": "flat-light"}[kind]; settings.set("user/general/@skin", theme); updateTheme(false, type); ignoreTheme = false; settings.set("user/general/@propose", question.dontAsk); }, function(){ // no settings.set("user/general/@propose", question.dontAsk); }, { showDontAsk: true }); } /***** Methods *****/ // There will be a better place for this when theming is fully // abstracted. For now this is a hack function setGeckoMask(){ if (!apf.isGecko) return; if (svg) svg.parentNode.removeChild(svg); var isFlatTheme = theme.indexOf("flat") > -1; var img = options.staticPrefix + "/images/" + ( isFlatTheme ? "gecko_mask_flat_light.png" : "gecko_mask.png"); var width = isFlatTheme ? 76 : 46; var height = isFlatTheme ? 26 : 24; var x1 = isFlatTheme ? 1 : 1; var x2 = isFlatTheme ? -40 : -28; document.body.insertAdjacentHTML("beforeend", '' + '' + '' + '' + '' + '' + '' + '' + '' + ''); svg = document.body.lastChild; } function findParent(obj, where) { if (obj.name == "menus") { menus = obj; return plugin.getElement("logobar"); } if (obj.name == "save") return plugin.getElement("barTools"); if (obj.name == "run.gui") return plugin.getElement("barTools"); else if (obj.name == "console") { c9console = obj; return plugin.getElement("consoleRow"); } else if (obj.name == "panels") { panels = obj; } else if (obj.name == "tabManager") { tabManager = obj; return plugin.getElement("colMiddle"); } else if (obj.name == "area-left") return plugin.getElement("colLeft"); else if (obj.name == "area-right") return plugin.getElement("colRight"); else if (obj.name == "preview") return plugin.getElement("barTools"); else if (obj.name == "runpanel") return plugin.getElement("barTools"); else if (obj.name == "vim.cli") return plugin.getElement("searchRow"); else if (obj.name == "findinfiles") return plugin.getElement("searchRow"); else if (obj.name == "findreplace") return plugin.getElement("searchRow"); else if (obj.name == "help") return plugin.getElement("barExtras"); else if (obj.name == "preferences") return plugin.getElement("barExtras"); else if (obj.name == "login") return plugin.getElement("barExtras"); else if (obj.name == "dragdrop") return plugin.getElement("colMiddle"); else if (obj.name == "dialog.notification") { notify = obj.show; return plugin.getElement("barQuestion"); } } function initMenus(menus) { // Menus menus.setRootMenu("Cloud9", 50, plugin); menus.setRootMenu("File", 100, plugin); menus.setRootMenu("Edit", 200, plugin); menus.setRootMenu("Find", 300, plugin); menus.setRootMenu("View", 400, plugin); menus.setRootMenu("Goto", 500, plugin); // run plugin adds: menus.setRootMenu("Run", 600, plugin); menus.setRootMenu("Tools", 700, plugin); menus.setRootMenu("Window", 800, plugin); var amlNode = menus.get("Cloud9").item; if (amlNode && amlNode.$ext) amlNode.$ext.className += " c9btn"; menus.addItemByPath("File/~", new apf.divider(), 1000000, plugin); menus.addItemByPath("View/~", new apf.divider(), 9999, plugin); menus.addItemByPath("Window/Presets", null, 10200, plugin); menus.addItemByPath("Window/Presets/Full IDE", new ui.item({ onclick: function(){ setBaseLayout("default"); } }), 100, plugin); menus.addItemByPath("Window/Presets/Minimal Editor", new ui.item({ onclick: function(){ setBaseLayout("minimal"); } }), 200, plugin); menus.addItemByPath("Window/Presets/Sublime Mode", new ui.item({ onclick: function(){ setBaseLayout("sublime"); } }), 300, plugin); } function resetTheme(theme, type) { ignoreTheme = true; settings.set("user/general/@skin", theme); updateTheme(true); emit("themeDefaults", {theme: theme, type: type}); ignoreTheme = false; } function resize(){ if (c9console && tabManager) { var tRect = tabManager.container.$ext.getBoundingClientRect(); var cRect = c9console.container.$ext.getBoundingClientRect(); if (cRect.top - tRect.top < 30) { c9console.container.setAttribute("height", Math.max(60, window.innerHeight - tRect.top - 30)); } } emit("resize"); } function setBaseLayout(type) { if (type == "sublime") { // Hide all side panes Object.keys(panels.panels).forEach(function(name) { panels.disablePanel(name, null, name == "tree"); }); // Hide console c9console && c9console.hide(); // Minimize menus menus.minimize(); // Active tree // setTimeout(function(){ // panels.activate("tree"); // }, 300); // Set Sublime Like Defaults settings.set("user/ace/@cursorStyle", "smooth slim"); settings.set("user/ace/@theme", "ace/theme/monokai"); settings.set("user/ace/@keyboardmode", "sublime"); settings.set("user/general/@preview-tree", true); settings.set("user/general/@preview-navigate", true); settings.set("user/ace/@wrapBehavioursEnabled", true); settings.set("user/language/@overrideMultiselectShortcuts", false); settings.set("user/openfiles/@show", true); } else { // Set Cloud9 Defaults settings.set("user/ace/@cursorStyle", "ace"); settings.set("user/ace/@theme", "ace/theme/cloud9_night"); settings.set("user/ace/@keyboardmode", "default"); settings.set("user/general/@preview-tree", false); settings.set("user/general/@preview-navigate", false); settings.set("user/ace/@wrapBehavioursEnabled", false); settings.set("user/language/@overrideMultiselectShortcuts", true); settings.set("user/openfiles/@show", c9.local); if (type == "default") { // Hide all side panes Object.keys(panels.panels).forEach(function(name) { panels.enablePanel(name, true); }); // Hide console commands.exec("toggleconsole", null, { show: true }); // Minimize menus menus.restore(); // Active tree panels.activate("tree"); } else if (type == "minimal") { // Hide all side panes Object.keys(panels.panels).forEach(function(name) { panels.disablePanel(name, null, name == "tree"); }); // Hide console c9console && c9console.hide(); // Minimize menus menus.minimize(); // Active tree // setTimeout(function(){ // panels.activate("tree"); // }, 300); } } } var activeFindArea, defaultFindArea, activating; function setFindArea(amlNode, options, callback) { var animate = options.animate; if (animate == undefined) animate = settings.getBool("user/general/@animateui"); var toHide = activeFindArea || defaultFindArea; if (options.isDefault) defaultFindArea = amlNode; var toShow = amlNode || defaultFindArea; activeFindArea = amlNode; if (toShow == toHide) return; var searchRow = plugin.getElement("searchRow"); activating = true; if (toShow) { searchRow.appendChild(toShow); toShow.show(); toShow.$ext.style.overflow = "hidden"; toShow.$ext.style.height = toShow.$ext.offsetHeight + "px"; } hide(toHide, function() { show(toShow, function() { activating = false; callback && callback(); }); }); function show(amlNode, callback) { if (!amlNode) return callback(); anims.animateSplitBoxNode(amlNode, { height: amlNode.$ext.scrollHeight + "px", duration: 0.2, timingFunction: "cubic-bezier(.10, .10, .25, .90)" }, function() { amlNode.$ext.style.height = ""; ui.layout.forceResize(null, true); callback && callback(); }); } function hide(amlNode, callback) { if (!amlNode) return callback(); amlNode.visible = false; amlNode.$ext.style.height = amlNode.$ext.offsetHeight + "px"; if (animate) { anims.animateSplitBoxNode(amlNode, { height: "0px", duration: 0.2, timingFunction: "ease-in-out" }, function(){ amlNode.visible = true; amlNode.hide(); if (amlNode.parentNode) amlNode.parentNode.removeChild(amlNode); callback && callback(); }); } else { amlNode.visible = true; amlNode.setHeight(0); amlNode.hide(); amlNode.parentNode.removeChild(amlNode); callback && callback(); } } } var hideFlagUpdate; function flagUpdate(callback) { if (hideFlagUpdate) return; hideFlagUpdate = notify("
A new version of " + "Cloud9 is available. Click this bar to update to the new " + "version (requires a restart).
", true); document.querySelector(".c9-update").addEventListener("click", function(){ hideFlagUpdate(); hideFlagUpdate = null; callback(); }, false); } /***** Lifecycle *****/ plugin.on("load", function(){ load(); }); plugin.on("enable", function(){ }); plugin.on("disable", function(){ }); plugin.on("unload", function(){ loaded = false; window.removeEventListener("resize", resize); if (removeTheme) removeTheme(); logobar = null; removeTheme = null; theme = null; c9console = null; menus = null; tabManager = null; panels = null; userLayout = null; ignoreTheme = null; notify = null; hideFlagUpdate = null; activeFindArea = null; defaultFindArea = null; activating = null; if (svg && svg.parentNode) svg.parentNode.removeChild(svg); svg = null; }); /***** Register and define API *****/ /** * Manages the layout of the Cloud9 UI. * * If you wish to build your own IDE, with a completely different * layout (for instance for a tablet or phone) reimplement this plugin. * This plugin is capable of telling plugins where to render. * * The layout plugin also provides a way to display error messages to * the user. * * @singleton **/ plugin.freezePublicAPI({ get maxConsoleHeight(){ var tRect = tabManager.container.$ext.getBoundingClientRect(); return window.innerHeight - tRect.top - 30; }, get theme(){ return theme; }, /** * Returns an AMLElement that can server as a parent. * @param {Plugin} plugin The plugin for which to find the parent. * @param {String} where Additional modifier to influence the decision of the layout manager. * @return {AMLElement} */ findParent: findParent, /** * Initializes the main menus * This method is called by the menus plugin. * @private */ initMenus: initMenus, /** * Resets theme (without questioning user). * @param {String} theme Theme to use. * @param {String} type Type of editor to use. */ resetTheme: resetTheme, /** * Sets the layout in one of two default modes: * @param {"default"|"minimal"} type */ setBaseLayout: setBaseLayout, /** * */ setFindArea: setFindArea, /** * */ proposeLayoutChange: proposeLayoutChange, /** * */ flagUpdate: flagUpdate }); register(null, { layout: plugin }); } });