c9-core/plugins/c9.ide.layout.classic/layout.js

656 wiersze
25 KiB
JavaScript

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");
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
var emit = plugin.getEmitter();
var highResolution = c9.location.indexOf("2x=1") > -1;
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" && plugin.hasTheme)
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("./less/index"), options.staticPrefix, plugin);
}
draw();
}
var drawn = false;
function draw() {
if (drawn) return;
drawn = true;
// Load the skin
ui.insertSkin({
"data": require("text!./skins.xml"),
}, 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);
// 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:
[
"close_tab_btn@1x.png"
].forEach(function(p) {
var img = new Image();
img.src = options.staticPrefix + "/images/" + p;
});
window.addEventListener("resize", resize, false);
window.addEventListener("focus", resize, false);
plugin.addOther(function() {
window.removeEventListener("resize", resize, false);
window.removeEventListener("focus", resize, false);
});
emit("draw");
}
var allowedThemes = {};
function addTheme(data) {
allowedThemes[data.name] = data;
emit("themeAdded", data);
}
function listThemes() {
return Object.keys(allowedThemes).map(function(key) {
return allowedThemes[key];
});
}
function setImageResolution(value) {
if (window.matchMedia) {
var mq = window.matchMedia("(-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 1.25dppx) ");
if (mq.matches || highResolution)
return value.replace(/@1x/g, "@2x");
}
return value;
}
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, themeCss) {
if (err)
return;
if (sTheme !== theme)
return;
// Remove Current Theme
if (removeTheme)
removeTheme();
var url = options.staticPrefix.replace(/c9.ide.layout.classic\/?$/, "");
themeCss = themeCss.replace(/(url\(["']?)\/static\/plugins\//g, function(_, x) {
return x + url;
});
themeCss = setImageResolution(themeCss);
// Load the theme css
ui.insertCss(themeCss, false, {
addOther: function(remove) { removeTheme = remove; }
});
changeTheme();
});
} else
changeTheme();
}
function changeTheme() {
var event = {
theme: theme,
oldTheme: oldTheme,
type: type
};
emit("eachTheme", { changed: true });
emit("themeChange", event);
setGeckoMask();
var auto = emit("validateThemeChange", event) !== false;
if (!oldTheme || noquestion) return;
if (auto)
return emit("themeDefaults", { theme: theme, type: type, force: false });
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": "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@" + (highResolution ? 2 : 1) + "x.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 xmlns="http://www.w3.org/2000/svg">'
+ '<defs>'
+ '<mask id="tab-mask-left" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">'
+ '<image width="' + width + 'px" height="' + height + 'px" xlink:href="' + img + '" x="' + x1 + 'px"></image>'
+ '</mask>'
+ '<mask id="tab-mask-right" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">'
+ '<image width="' + width + 'px" height="' + height + 'px" xlink:href="' + img + '" x="' + x2 + 'px"></image>'
+ '</mask>'
+ '</defs>'
+ '</svg>');
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("<div class='c9-update'>A new version of "
+ "Cloud9 is available. Click this bar to update to the new "
+ "version (requires a restart).</div>", 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;
},
get hasTheme() {
return !ui.packedThemes || !!removeTheme
},
addTheme: addTheme,
listThemes: listThemes,
/**
* 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
});
}
});