codiad/components/finder/init.js

291 lines
10 KiB
JavaScript
Executable File

(function(global, $){
var codiad = global.codiad;
$(window).load(function() {
codiad.finder.init();
});
//////////////////////////////////////////////////////////////////
//
// Search utility to quickly filter the directory tree
// according to multiple matching strategies
//
//////////////////////////////////////////////////////////////////
codiad.finder = {
// Create DOM node for a particular tree element
_makeDomNode: function(name, obj){
var str, path, ext, chStr;
str = "<li><span class=\"none\"></span><a";
if (obj.type === 'directory'){
str += " class='directory open'";
} else {
s = name.split('.');
str += " class='file";
if (s.length > 0)
str += " ext-"+s[s.length -1];
str += "'";
}
str += " data-path='"+obj.path+"' data-type='"+
obj.type +"' >" + name + "</a>";
chStr = "";
for (key in obj.children){
chStr += this._makeDomNode(key, obj.children[key]);
}
if (chStr.length > 0){
str += "<ul>"+chStr +"</ul>";
}
str += "</li>";
return str;
},
// Construct DOM tree from internal data-structure representing
// the filtered directory tree
_makeDomTree: function(tree){
var str = "<ul>";
for (key in tree){
str += this._makeDomNode(key, tree[key]);
}
str += "</ul>";
//console.debug("DOM tree :", str);
return str;
},
// Construct internal representation for filtered directory tree
// from array returned by server
_makeHierarchy: function(data){
data = data.index;
//console.log('data : ', data);
var tree = {}, fpathArr, i, j, fragment, curLevel, type;
for (i = 0; i < data.length; i++){
curLevel = tree;
if(codiad.project.isAbsPath(data[i].path)) {
fpathArr = data[i].path.replace(this._rootPath, this._rootName).split('/');
} else {
fpathArr = data[i].path.split('/');
}
for (j = 0; j < fpathArr.length; j++){
fragment = fpathArr[j];
if (fragment === "") continue;
if (! curLevel[fragment]){
type = j < fpathArr.length -1 ? 'directory' : data[i].type;
curLevel[fragment] = {
type: type,
children: {}
}
if (type === 'file'){
curLevel[fragment].path = data[i].path;
} else {
if(codiad.project.isAbsPath(data[i].path)) {
curLevel[fragment].path = fpathArr.slice(0, j+1).join('/').replace(this._rootName, this._rootPath);
} else {
curLevel[fragment].path = fpathArr.slice(0, j+1).join('/');
}
}
}
curLevel = curLevel[fragment].children;
}
}
//console.log('tree : ', tree, JSON.stringify(tree));
return tree;
},
// Use query response returned by server to filter the directory tree
_filterTree: function(data){
var tree = this._makeHierarchy(data);
var domTree = this._makeDomTree(tree);
$('#file-manager').html(domTree);
$('#file-manager>ul>li:first-child>span').remove();
$('#file-manager>ul>li:first-child>a').attr({
id: 'project-root',
'data-type': 'root',
'data-path': this._rootPath
});
},
// Clear all filters applied and restore the tree to its original state
_clearFilters: function(){
//console.info("Reloading initial tree state ");
if (this._htmlStash)
$('#file-manager').html(this._htmlStash);
this._htmlStash = null;
$('#finder').attr('value', '');
},
// Empty the tree and notify that no files were found
_emptyTree: function(){
$('#file-manager').html("No files found .");
},
// Check finder for changes in the user entered query
_checkFinder: function(){
var fentry = $('#finder').attr('value');
var _this = this;
fentry = fentry.replace(/^\s+|\s+$/g, '');
if (! fentry || fentry == this._lastEntry) return;
/*else if (fentry.substring(0, this._lastEntry.length) ===
this._lastEntry) {
// TODO : Scope for optimization
//
// User has added characters to query - so unless the
// query is a regexp - the filtered results can be
// deduced locally if last ajax request had completed.
// Not implementing this currently because this is
// not very beneficial practically for decent
// typing speed.
}*/ else{
// Stop currently ongoing request
if (this._xhr) this._xhr.abort();
// Query the server for results
//console.log("Finder query changed");
this._lastEntry = fentry;
this._xhr = $.ajax({
url: 'components/filemanager/controller.php',
type: 'GET',
dataType: 'json',
data: {
query: fentry,
action: 'find',
path: this._rootPath,
options: this._options
},
success: function(data){
if (data.status == 'success'){
_this._filterTree(data.data);
} else {
_this._emptyTree();
}
}
});
}
},
//////////////////////////////////////////////////////////////////
//
// Expand the finder box (Textbox through which the directory tree
// can be searched for matching files) and focus on it.
//
//////////////////////////////////////////////////////////////////
expandFinder: function(){
this._isFinderExpanded = true;
//console.info("Saving tree state : ");
this._htmlStash = $('#file-manager').html();
this._rootPath = $('#project-root').attr('data-path');
this._rootName = $('#project-root').html();
$("#finder-wrapper").show();
$("#sb-left-title h2").hide();
var _this = this;
this._lastEntry = null;
this._poller = setInterval(function(){
_this._checkFinder();
}, 500);
$("#finder").focus();
$("#finder-quick").hide();
$("#sb-left-title").addClass('active');
$("#tree-search")
.removeClass('icon-search')
.addClass('icon-cancel-squared active');
},
// Contract the finder box
contractFinder: function(){
this._isFinderExpanded = false;
$("#finder-wrapper").hide('fast');
$("#sb-left-title h2").show('fast');
clearInterval(this._poller);
this.finderMenu.hide();
this._clearFilters();
$("#finder-quick").show();
$("#sb-left-title").removeClass('active');
$("#tree-search")
.removeClass('icon-cancel-squared active')
.addClass('icon-search');
},
// Setup finder
init: function(){
var _this = this;
var isExpanded = false;
this._options = {};
$('#tree-search').click(function(){
if (! _this._isFinderExpanded) {
_this.expandFinder();
} else {
_this.contractFinder();
}
});
$('#finder-label').click(function(){
_this.expandFinder();
});
this.finderMenu = finderMenu = $('#finder-options-menu')
.appendTo($('#sb-left'))
.hide();
$finderOptionsMenu = $('#finder-options-menu');
$('#finder-options').click(function(){
finderMenu.toggle();
});
// Setup the menu for selection of finding strategy
$finderOptionsMenu.bind('click', 'a', function(e){
$target = $(e.target);
var strategy = $target.attr('data-option');
var action = $target.attr('data-action');
if (strategy){
_this._options.strategy = strategy;
$finderOptionsMenu
.find('li.chosen')
.removeClass('chosen');
$target.parent('li').addClass('chosen');
} else if (action){
codiad.filemanager[action](codiad.project.getCurrent());
_this.contractFinder();
}
$finderOptionsMenu.hide();
});
// Setup the menu for selection of finding strategy
$('#finder-quick').click(function(e){
codiad.filemanager['search'](codiad.project.getCurrent());
_this.contractFinder();
});
/*
TODO: provide configuration option
to automatically collapse finder
--
The code below does exactly that
--
$('#sb-left').mouseleave(function(){
_this.finderSustainFocus = false;
if (! $('#finder').is(':focus')){
_this.contractFinder();
}
}).mouseenter(function(){
_this.finderSustainFocus = true;
});
$('#finder').blur(function(){
if (! _this.finderSustainFocus)
_this.contractFinder();
});
*/
}
}
})(this, jQuery);