c9-core/plugins/c9.fs/mock/file.js

489 wiersze
16 KiB
JavaScript

define(function(require, exports, module) {
main.consumes = [
"Plugin", "settings", "ui", "watcher", "menus", "tabManager", "find", "fs",
"panels", "fs.cache", "preferences", "c9", "commands", "tree"
];
main.provides = ["navigate"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var settings = imports.settings;
var ui = imports.ui;
var c9 = imports.c9;
var fs = imports.fs;
var fsCache = imports["fs.cache"];
var tabs = imports.tabManager;
var menus = imports.menus;
var watcher = imports.watcher;
var commands = imports.commands;
var panels = imports.panels;
var find = imports.find;
var filetree = imports.tree;
var prefs = imports.preferences;
var markup = require("text!./navigate.xml");
var search = require('./search');
var Tree = require("ace_tree/tree");
var ListData = require("./dataprovider");
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
var emit = plugin.getEmitter();
var winGoToFile, txtGoToFile, tree, ldSearch;
var lastPanel, lastSearch, lastPreviewed;
var dirty = true;
var arrayCache = [];
var timer;
var loaded = false;
function load(){
if (loaded) return false;
loaded = true;
// Register this panel on the left-side panels
panels.register({
index: 200,
caption: "Navigate",
command: "navigate",
hint: "search for a filename, line or symbol and jump to it",
bindKey: { mac: "Command-E|Command-P", win: "Ctrl-E|Ctrl-P" },
panel: plugin,
elementName: "winGoToFile",
minWidth: 130,
autohide: true,
draw: draw
});
panels.on("showpanelNavigate", function(e) {
lastPanel = e.lastPanel;
txtGoToFile.focus();
txtGoToFile.select();
tree.resize();
});
panels.on("hidepanelNavigate", function(e) {
tree.clearSelection();
});
// Menus
var mnuItem = new apf.item({ command : "navigate" });
menus.addItemByPath("File/Open...", mnuItem, 500, plugin);
menus.addItemByPath("Goto/Goto File...", mnuItem.cloneNode(false), 100, plugin);
// Settings
settings.on("read", function(){
settings.setDefaults("user/general", [["preview-navigate", "false"]]);
}, plugin);
// Prefs
prefs.add({
"General" : {
"General" : {
"Enable Preview on Navigation" : {
type: "checkbox",
position: 2000,
path: "user/general/@preview-navigate"
}
}
}
}, plugin);
// Update when the fs changes
fs.on("afterWriteFile", function(e) {
// Only mark dirty if file didn't exist yet
if (arrayCache.indexOf(e.path) == -1)
markDirty(e);
});
fs.on("afterUnlink", markDirty);
fs.on("afterRmfile", markDirty);
fs.on("afterRmdir", markDirty);
fs.on("afterCopy", markDirty);
fs.on("afterRename", markDirty);
fs.on("afterSymlink", markDirty);
// Or when a watcher fires
watcher.on("delete", markDirty);
watcher.on("directory", markDirty);
// Or when the user refreshes the tree
filetree.on("refresh", markDirty);
// Or when we change the visibility of hidden files
fsCache.on("setShowHidden", markDirty);
// Pre-load file list
updateFileCache();
}
function offlineHandler(e) {
// Online
if (e.state & c9.STORAGE) {
txtGoToFile.enable();
//@Harutyun This doesn't work
// tree.enable();
}
// Offline
else {
txtGoToFile.disable();
//@Harutyun This doesn't work
// tree.disable();
}
}
var drawn = false;
function draw(options) {
if (drawn) return;
drawn = true;
// Create UI elements
ui.insertMarkup(options.panel, markup, plugin);
// Import CSS
ui.insertCss(require("text!./style.css"), plugin);
var treeParent = plugin.getElement("tree");
txtGoToFile = plugin.getElement("txtGoToFile");
winGoToFile = plugin.getElement("winGoToFile");
txtGoToFile = plugin.getElement("txtGoToFile");
// Create the Ace Tree
tree = new Tree(treeParent.$int);
ldSearch = new ListData(arrayCache);
ldSearch.search = search;
// Assign the dataprovider
tree.setDataProvider(ldSearch);
// @TODO this is probably not sufficient
window.addEventListener("resize", function(){ tree.resize() });
tree.textInput = txtGoToFile.ace.textInput;
// @Harutyun; is this the right way to do it?
function available(){ return tree.isFocused() }
txtGoToFile.ace.commands.addCommands([
{
bindKey: "ESC",
exec: function(){ hide(); }
}, {
bindKey: "Up",
exec: function(){ tree.execCommand("goUp"); }
}, {
bindKey: "Down",
exec: function(){ tree.execCommand("goDown"); }
}, {
bindKey: "Enter",
exec: function(){ openFile(true); }
}
]);
tree.on("mousedown", function(e) {
var pos = e.getDocumentPosition();
var node = tree.provider.findItemAtOffset(pos.y);
ldSearch.selectNode(node);
openFile(true);
})
txtGoToFile.ace.on("input", function(e) {
var val = txtGoToFile.getValue();
filter(val);
if (dirty && val.length > 0 && ldSearch.loaded) {
dirty = false;
updateFileCache(true);
}
});
// @Harutyun, the select event should be on the tree or the selection object
// I just hacked it into the dataprovider for now, but that is very wrong.
// tree.getSelection().on("changeSelection", function(){ previewFile(); });
// tree.on("select", function(){ previewFile(); });
ldSearch.on("select", function(){ previewFile(); });
function onblur(e) {
if (!winGoToFile.visible)
return;
var to = e.toEasdasdasdasdaaaasssdddlement;
if (!to || apf.isChildOf(winGoToFile, to, true)
|| (lastPreviewed && tabs.previewTab
&& tabs.previewTab === lastPreviewed
&& (apf.isChildOf(lastPreviewed.aml.relPage, to, true)
|| lastPreviewed.aml == to))) {
return;
}
hide();
}
apf.addEventListener("movefocus", onblur);
// Focus the input field
txtGoToFile.focus();
// Offline
c9.on("stateChange", offlineHandler, plugin);
offlineHandler({ state: c9.status });
emit("draw");
}
/***** Methods *****/
function reloadResults(){
if (!winGoToFile)
return;
// Wait until window is visible
if (!winGoToFile.visible) {
winGoToFile.on("prop.visible", function visible(e) {
if (e.value) {
reloadResults();
winGoToFile.off("prop.visible", visible);
}
});
return;
}
// @Harutyun, how do I get the selection, scrollTop?
// var sel = [];
// dgGoToFile.getSelection().forEach(function(node) {
// var i = node.firstChild.nodeValue;
// sel.push(searchResults[i]);
// });
// var state = {
// sel : sel, //store previous selection
// caret : dgGoToFile.caret && searchResults[dgGoToFile.caret.firstChild.nodeValue],
// scrollTop : dgGoToFile.$viewport.getScrollTop()
// };
if (lastSearch)
filter(lastSearch);//, state.sel.length);
else
ldSearch.updateData(arrayCache);
// @Harutyun, how do I set the selection, scrollTop?
// if (state.sel.length && state.sel.length < 100) {
// var list = [];
// sel = state.sel;
// for (var i = 0, l = sel.length; i < l; i++) {
// list.push(dgGoToFile.queryNode("//d:href[text()='"
// + searchResults.indexOf(sel[i]) + "']"));
// }
// dgGoToFile.selectList(list);
// if (state.caret)
// dgGoToFile.setCaret(dgGoToFile.queryNode("//d:href[text()='"
// + searchResults.indexOf(state.caret) + "']"));
// dgGoToFile.$viewport.setScrollTop(state.scrollTop);
// }
}
function markDirty(options) {
// Ignore hidden files
var path = options && options.path || "";
if (path && !fsCache.showHidden && path.charAt(0) == ".")
return;
dirty = true;
if (panels.isActive("navigate")) {
clearTimeout(timer);
timer = setTimeout(function(){ updateFileCache(true); }, 2000);
}
}
function updateFileCache(isDirty) {
clearTimeout(timer);
find.getFileList({
path: "/",
nocache: isDirty,
hidden: fsCache.showHidden,
buffer: true
}, function(err, data) {
if (err)
return;
arrayCache = data.trim().split("\n");
reloadResults();
});
dirty = false;
}
/**
* Searches through the dataset
*
*/
function filter(keyword, nosel) {
keyword = keyword.replace(/\*/g, "");
if (!ldSearch.loaded) {
lastSearch = keyword;
return;
}
// Needed for highlighting
ldSearch.keyword = keyword;
var searchResults;
if (!keyword || !keyword.length) {
var result = arrayCache.slice();
// More prioritization for already open files
tabs.getTabs().forEach(function (tab) {
if (!tab.path
|| pages[i].document.meta.preview) return;
var idx = result.indexOf(tab.path);
if (idx > -1) {
result.splice(idx, 1);
result.unshift(tab.path);
}
});
searchResults = result;
}
else {
// @Harutyun, how do I set the scroll position?
// dgGoToFile.$viewport.setScrollTop(0);
searchResults = search.fileSearch(arrayCache, keyword);
}
lastSearch = keyword;
if (searchResults && searchResults.length)
ldSearch.updateData(searchResults);
if (nosel || !searchResults.length)
return;
// See if there are open files that match the search results
// and the first if in the displayed results
var pages = tabs.getTabs(), hash = {};
for (var i = pages.length - 1; i >= 0; i--) {
if (!pages[i].document.meta.preview)
hash[pages[i].path] = true;
}
// loop over all visible items. If we find a visible item
// that is in the `hash`, select it and return.
var first = tree.renderer.getFirstVisibleRow();
var last = tree.renderer.getLastVisibleRow();
for (var i = first; i < last; i++) {
if (hash[ldSearch.visibleItems[i]]) {
tree.select(i);
return;
}
}
// select the first item in the list
if (keyword) {
tree.select(0);
}
}
function openFile(noanim) {
if (!ldSearch.loaded)
return false;
// @Harutyun, How do I get the selection (multiple)
// var nodes = dgGoToFile.getSelection();
// Temporary
var nodes = [];
var row = ldSearch.selectedRow;
nodes.push(ldSearch.visibleItems[row]);
// Cancel Preview and Keep the tab if there's only one
if (tabs.preview({ cancel: true, keep : nodes.length == 1 }) === true)
return hide();
hide();
var fn = function(){};
for (var i = 0, l = nodes.length; i < l; i++) {
var path = "/" + nodes[i].replace(/^[\/]+/, "");
tabs.open({
path: path,
noanim: l > 1,
active: i == l - 1
}, fn);
}
lastPreviewed = null;
}
function previewFile(noanim) {
if (!settings.getBool("user/general/@preview-navigate"))
return;
if (!ldSearch.loaded)
return false;
var row = ldSearch.selectedRow;
var value = ldSearch.visibleItems[row];
if (!value)
return;
var path = "/" + value.replace(/^[\/]+/, "");
lastPreviewed = tabs.preview({ path: path }, function(){});
}
function show() {
panels.activate("navigate");
}
function hide(){
if (panels.isActive("navigate")) {
if (lastPanel)
panels.activate(lastPanel);
else
panels.deactivate("navigate");
// Cancel Preview
tabs.preview({ cancel: true });
if (tabs.focussedTab)
tabs.focussedTab.editor.focus();
}
}
/***** Lifecycle *****/
plugin.on("load", function(){
load();
});
plugin.on("enable", function(){
});
plugin.on("disable", function(){
});
plugin.on("unload", function(){
loaded = false;
drawn = false;
});
/***** Register and define API *****/
/**
* Navigation panel. Navigates to files, lines and symbols
**/
plugin.freezePublicAPI({
/**
*
*/
show: show
});
register(null, {
navigate: plugin
});
}
});