kopia lustrzana https://github.com/c9/core
477 wiersze
16 KiB
JavaScript
477 wiersze
16 KiB
JavaScript
define(function(require, exports, module) {
|
|
"use strict";
|
|
|
|
main.consumes = [
|
|
"Plugin", "tabManager", "menus", "commands", "settings",
|
|
"tree", "save", "ui", "c9", "panels", "layout"
|
|
];
|
|
main.provides = ["openfiles"];
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
var Plugin = imports.Plugin;
|
|
var tabs = imports.tabManager;
|
|
var menus = imports.menus;
|
|
var commands = imports.commands;
|
|
var settings = imports.settings;
|
|
var panels = imports.panels;
|
|
var layout = imports.layout;
|
|
var tree = imports.tree;
|
|
var save = imports.save;
|
|
var ui = imports.ui;
|
|
|
|
var Tree = require("ace_tree/tree");
|
|
var TreeData = require("./openfilesdp");
|
|
var basename = require("path").basename;
|
|
|
|
/***** Initialization *****/
|
|
|
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
|
var emit = plugin.getEmitter();
|
|
|
|
// tree maximum height
|
|
var showOpenFiles = false;
|
|
var defaultShow = options.defaultShow;
|
|
var dragged = false;
|
|
|
|
// UI Elements
|
|
var ofDataProvider, ofTree, treeParent, winFileTree;
|
|
var ctxItem, preventUpdate, mnuFilesSettings;
|
|
|
|
var loaded = false;
|
|
function load() {
|
|
if (loaded) return false;
|
|
loaded = true;
|
|
|
|
// Hook events to get the focussed tab
|
|
tabs.on("focusSync", delayedUpdate);
|
|
// tabs.on("tabDestroy", delayedUpdate);
|
|
tabs.on("tabAfterClose", update);
|
|
tabs.on("tabReparent", delayedUpdate);
|
|
tabs.on("tabOrder", delayedUpdate);
|
|
|
|
save.on("tabSavingState", refresh);
|
|
|
|
commands.addCommand({
|
|
name: "toggleOpenfiles",
|
|
exec: function(editor, args) {
|
|
toggleOpenfiles(args && args.forceOpen);
|
|
}
|
|
}, plugin);
|
|
|
|
menus.addItemByPath("View/Open Files", new ui.item({
|
|
type: "check",
|
|
checked: "user/openfiles/@show"
|
|
// command : "toggleOpenfiles"
|
|
}), 210, plugin);
|
|
|
|
tree.getElement("mnuFilesSettings", function(mnuFilesSettings) {
|
|
ui.insertByIndex(mnuFilesSettings, new ui.item({
|
|
caption: "Show Open Files",
|
|
type: "check",
|
|
checked: "user/openfiles/@show",
|
|
}), 190, plugin);
|
|
ui.insertByIndex(mnuFilesSettings,
|
|
new ui.divider(), 185, plugin);
|
|
});
|
|
|
|
settings.on("read", function(e) {
|
|
// Defaults
|
|
settings.setDefaults("user/openfiles", [
|
|
["show", defaultShow],
|
|
["hidetree", "false"]
|
|
]);
|
|
showOpenFiles = settings.getBool("user/openfiles/@show");
|
|
updateVisibility(showOpenFiles);
|
|
}, plugin);
|
|
|
|
settings.on("user/openfiles/@show", function(value) {
|
|
showOpenFiles = value;
|
|
updateVisibility(showOpenFiles);
|
|
});
|
|
|
|
panels.on("showPanelTree", function() { update(); });
|
|
}
|
|
|
|
var drawn = false;
|
|
function draw() {
|
|
if (drawn) return;
|
|
drawn = true;
|
|
|
|
// ace_tree customization '.openfiles'
|
|
ui.insertCss(require("text!./openfiles.css"), null, plugin);
|
|
|
|
tree.getElement("winOpenfiles", function(winOpenfiles) {
|
|
treeParent = winOpenfiles;
|
|
|
|
tree.getElement("winFileTree", function(winFileTreeL) {
|
|
winFileTree = winFileTreeL;
|
|
});
|
|
|
|
var div = document.createElement("div");
|
|
treeParent.$int.appendChild(div);
|
|
|
|
// Create the Ace Tree
|
|
ofTree = new Tree(div);
|
|
ofDataProvider = new TreeData();
|
|
// ofTree.renderer.setScrollMargin(0, 10);
|
|
ofTree.renderer.setTheme({ cssClass: "filetree" });
|
|
// Assign the dataprovider
|
|
ofTree.setDataProvider(ofDataProvider);
|
|
|
|
layout.on("eachTheme", function(e) {
|
|
var height = parseInt(ui.getStyleRule(".openfiles .ace_tree .tree-row", "height"), 10);
|
|
ofDataProvider.rowHeightInner = height;
|
|
ofDataProvider.rowHeight = height;
|
|
|
|
if (e.changed) (tree).resize(true);
|
|
});
|
|
|
|
ofTree.on("userSelect", function() {
|
|
setTimeout(onSelect, 40);
|
|
});
|
|
|
|
// make sure scrollbar on windows is in the padding area
|
|
ofTree.renderer.on("scrollbarVisibilityChanged", updateScrollBarSize);
|
|
ofTree.renderer.on("resize", updateScrollBarSize);
|
|
function updateScrollBarSize() {
|
|
var w = ofTree.renderer.scrollBarV.getWidth();
|
|
ofTree.renderer.scroller.style.right = Math.max(w, 10) + "px";
|
|
}
|
|
|
|
// APF + DOM HACK: close tab with confirmation
|
|
ofTree.on("mousedown", function(e) {
|
|
var domTarget = e.domEvent.target;
|
|
var pos = e.getDocumentPosition();
|
|
var node = ofDataProvider.findItemAtOffset(pos.y);
|
|
|
|
if (node.children && !~domTarget.className.indexOf("toggler")) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (! (node && node.path && domTarget && ~domTarget.className.indexOf("close")))
|
|
return;
|
|
|
|
var amlTab = node.tab.aml;
|
|
amlTab.parentNode.remove(amlTab, {});
|
|
});
|
|
|
|
ofTree.focus = function() {};
|
|
|
|
ofTree.renderer.on("autoresize", function() {
|
|
updateHeight();
|
|
});
|
|
|
|
ofTree.setOption("maxLines", 100);
|
|
ofTree.renderer.getMaxHeight = function () {
|
|
return Math.floor(treeParent.parentNode.$int.offsetHeight * 0.5 - 23);
|
|
};
|
|
|
|
mnuFilesSettings = tree.getElement("mnuFilesSettings");
|
|
ctxItem = ui.insertByIndex(mnuFilesSettings, new ui.item({
|
|
caption: "Hide Workspace Files",
|
|
type: "check",
|
|
visible: treeParent.visible,
|
|
checked: "state/openfiles/@hidetree",
|
|
onclick: function(e) {
|
|
hideTree(this.checked);
|
|
}
|
|
}), 195, plugin);
|
|
|
|
if (showOpenFiles) {
|
|
tabs.once("ready", function() { show(); });
|
|
|
|
if (settings.getBool("state/openfiles/@hidetree"))
|
|
hideTree(true);
|
|
}
|
|
else
|
|
hideOpenFiles();
|
|
|
|
emit("draw");
|
|
});
|
|
}
|
|
|
|
/***** Methods *****/
|
|
|
|
function hideTree(state) {
|
|
settings.set("state/openfiles/@hidetree", state);
|
|
|
|
if (treeParent) {
|
|
if (state)
|
|
ui.setStyleClass(treeParent.parentNode.$int, "hidetree");
|
|
else
|
|
ui.setStyleClass(treeParent.parentNode.$int, "", ["hidetree"]);
|
|
}
|
|
|
|
if (mnuFilesSettings) {
|
|
mnuFilesSettings.childNodes.forEach(function(node) {
|
|
if (node.$position >= 200) {
|
|
node.setAttribute("visible", !state);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (ofTree) {
|
|
ofTree.resize();
|
|
tree.resize();
|
|
}
|
|
}
|
|
|
|
var updateTimer;
|
|
function delayedUpdate() {
|
|
if (updateTimer)
|
|
return;
|
|
updateTimer = setTimeout(function() {
|
|
updateTimer = null;
|
|
update();
|
|
}, 10);
|
|
}
|
|
|
|
function update() {
|
|
if (!showOpenFiles)
|
|
return;
|
|
|
|
if (!panels.isActive("tree"))
|
|
return;
|
|
|
|
draw();
|
|
|
|
if (!ofTree)
|
|
return;
|
|
|
|
preventUpdate = true;
|
|
|
|
var activePanes = tabs.getPanes(tabs.container);
|
|
var focussedTab = tabs.focussedTab;
|
|
// focussedTab can be the terminal or output views
|
|
if (focussedTab && activePanes.indexOf(focussedTab.pane) === -1
|
|
&& activePanes.length)
|
|
focussedTab = activePanes[0].getTab();
|
|
|
|
// unhook document change update listeners
|
|
tabs.getTabs().forEach(function (tab) {
|
|
tab.document && tab.document.off("changed", refresh);
|
|
});
|
|
|
|
var selected;
|
|
var root = { groups: []};
|
|
var actualRoot = {
|
|
children: [
|
|
{
|
|
name: "open files",
|
|
path: "!openfiles",
|
|
isOpen: true,
|
|
className: "heading",
|
|
isRoot: true,
|
|
isFolder: true,
|
|
status: "loaded",
|
|
map: {},
|
|
children: root.groups,
|
|
noSelect: true
|
|
}
|
|
]
|
|
};
|
|
|
|
var oldRoot = ofDataProvider && ofDataProvider.root;
|
|
var existing = oldRoot && oldRoot.groups || {};
|
|
root.children = activePanes.map(function(pane, i) {
|
|
var group = existing[i] || { isOpen: true, className: "group" };
|
|
if (group.isOpen == "forced")
|
|
group.isOpen = false;
|
|
root.groups[i] = group;
|
|
group.children = null;
|
|
// name: pane.name (tab0 ...)
|
|
group.children = pane.getTabs()
|
|
.filter(function(tab) {
|
|
return tab.path && tab.loaded && !tab.meta.$closing;
|
|
})
|
|
.map(function(tab) {
|
|
var node = {
|
|
name: basename(tab.path),
|
|
path: tab.path,
|
|
tab: tab
|
|
};
|
|
if (tab == focussedTab) {
|
|
selected = node;
|
|
group.isOpen = "forced";
|
|
}
|
|
|
|
tab.document.on("changed", refresh);
|
|
return node;
|
|
});
|
|
return group;
|
|
}).filter(function(pane) {
|
|
return pane.children.length;
|
|
}).map(function (node, i) {
|
|
node.name = "GROUP " + (i + 1);
|
|
return node;
|
|
});
|
|
|
|
// Hide the openfiles
|
|
if (!root.children.length) {
|
|
preventUpdate = false;
|
|
return hideOpenFiles();
|
|
}
|
|
|
|
ui.setStyleClass(treeParent.parentNode.$int, "hasopenfiles");
|
|
|
|
treeParent.show();
|
|
|
|
if (root.children.length === 1)
|
|
actualRoot.children[0].children = root.children[0].children;
|
|
|
|
ofDataProvider.setRoot(actualRoot);
|
|
ofDataProvider.selection.selectNode(selected);
|
|
|
|
updateHeight();
|
|
}
|
|
|
|
function updateHeight(selected) {
|
|
preventUpdate = true;
|
|
|
|
var maxHeight = treeParent.parentNode.$int.offsetHeight * 0.5;
|
|
var treeHeight = ofTree.renderer.desiredHeight + 23;
|
|
|
|
treeParent.$int.style.height = dragged
|
|
? Math.min(treeParent.getHeight(), treeHeight) + "px"
|
|
: Math.min(treeHeight, maxHeight) + "px";
|
|
|
|
// ofTree.resize(true);
|
|
tree.resize();
|
|
|
|
if (!selected)
|
|
selected = ofTree.selectedNode;
|
|
|
|
ofTree.renderer.scrollCaretIntoView(selected, 0.5);
|
|
|
|
preventUpdate = false;
|
|
}
|
|
|
|
function refresh() {
|
|
if (!showOpenFiles || !ofDataProvider)
|
|
return;
|
|
ofDataProvider._signal("change");
|
|
}
|
|
|
|
function onSelect() {
|
|
var node = ofTree.selection.getCursor();
|
|
if (node && tabs.focussedTab && tabs.focussedTab.path != node.path)
|
|
tabs.focusTab(node.path);
|
|
}
|
|
|
|
function hideOpenFiles() {
|
|
var htmlNode = treeParent && treeParent.parentNode.$int;
|
|
htmlNode && ui.setStyleClass(htmlNode, "", ["hasopenfiles"]);
|
|
treeParent && treeParent.hide();
|
|
tree.resize();
|
|
}
|
|
|
|
function toggleOpenfiles(forceOpen) {
|
|
showOpenFiles = forceOpen == null ? !showOpenFiles : forceOpen;
|
|
settings.set("user/openfiles/@show", showOpenFiles);
|
|
updateVisibility(showOpenFiles);
|
|
}
|
|
|
|
function updateVisibility(show) {
|
|
if (show) {
|
|
draw();
|
|
update();
|
|
ctxItem && ctxItem.show();
|
|
|
|
if (settings.getBool("state/openfiles/@hidetree"))
|
|
hideTree(true);
|
|
|
|
if (!panels.isActive("tree")) {
|
|
panels.once("showPanelTree", function() {
|
|
ofTree.resize(true);
|
|
tree.resize(true);
|
|
});
|
|
|
|
panels.activate("tree");
|
|
}
|
|
}
|
|
else {
|
|
hideOpenFiles();
|
|
ctxItem && ctxItem.hide();
|
|
|
|
if (treeParent)
|
|
hideTree(false);
|
|
}
|
|
|
|
emit("visible", { value: show });
|
|
}
|
|
|
|
/***** Lifecycle *****/
|
|
|
|
plugin.on("load", function() {
|
|
load();
|
|
});
|
|
plugin.on("enable", function() {
|
|
|
|
});
|
|
plugin.on("disable", function() {
|
|
|
|
});
|
|
plugin.on("unload", function() {
|
|
loaded = false;
|
|
drawn = false;
|
|
});
|
|
|
|
function show() {
|
|
updateVisibility(true);
|
|
}
|
|
|
|
function hide() {
|
|
updateVisibility(false);
|
|
}
|
|
|
|
/***** Register and define API *****/
|
|
|
|
/**
|
|
* Displays the open files above the tree.
|
|
*
|
|
* @singleton
|
|
*/
|
|
plugin.freezePublicAPI({
|
|
/**
|
|
* Show the openfiles panel
|
|
*/
|
|
show: show,
|
|
|
|
/**
|
|
* Hide the openfiles panel
|
|
*/
|
|
hide: hide,
|
|
|
|
/**
|
|
* Trigger a complete update of the openfiles view, only when the
|
|
* openfiles panel is visible.
|
|
*/
|
|
update: update,
|
|
|
|
/**
|
|
* Rerender the viewed part of the tree without having to recreate
|
|
* the tree data.
|
|
* Example usage: when the saving state or document content changed
|
|
* Only applies when openfiles is visible
|
|
*/
|
|
refresh: refresh,
|
|
|
|
/**
|
|
*
|
|
*/
|
|
showTree: hideTree.bind(null, false),
|
|
|
|
/**
|
|
*
|
|
*/
|
|
hideTree: hideTree.bind(null, true)
|
|
});
|
|
|
|
register(null, {
|
|
openfiles: plugin
|
|
});
|
|
}
|
|
});
|