mirror of
https://github.com/xevidos/codiad.git
synced 2024-11-10 21:26:35 +01:00
291 lines
10 KiB
JavaScript
291 lines
10 KiB
JavaScript
|
(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);
|