search two
Multifolder search v2.0
This file search script uses Xtscript and filelist to create a javascript object (associative array) of the results of multiple xt:filelist functions
This object is then sorted and dynamically paged and displayed using the DOM and javascript
The script retrieves the next page of results from the object without reloading the page from XtGem or rerunning the filelists.
This means much faster loading of the next results page and much less data usage
While they are created by the Xtscript the actual filelist functions are not run until after Xtscript has finished and are not subject to xtscript timeouts
This script has been tested with over 100 filelists searching over 12,000 files
If the query is a single word the search filter tests for a match anywhere in the filename
If the query has multiple words the spaces in the query are converted to * wildcards and the filter then tests for those words in that order with any other words or characters between them
There are also tests for invalid characters and query length
Settings
- per_page
Set the number of results per page
- min_query_length
Set the minimum query length
This should be no lower than 2 or you will return too many results 3 is about optimum depending on the shortest filename or other factors
- ext
This is appended to the filelist filter so that only files with extensions are included in the search
Query validation
This version is set up to search 10 folders if you need to extend it
1/ Insert another line like this into the Filelist patterns
var $list11 = xt:filelist folder="/folder11" $params
2/ Insert another filelist code into the array function before the
{_$$dummy|} entry
<{_$$list11|xt:code}>
In the demo below enter ** wildcard into the search to return all files
Example code
Show in textarea<!--parser:xtscript-->
# Settings
var $per_page =6
var $min_query_length = 2
var $ext= .*
var $template = ['.file_name.','.file_url.','.file_size.','.file_datetime.','.file_mime.'],
# Search form container
print <div class="search_form" id="srch">
# Query validation
get search
var $search = call trim $val=$search
if not $search
var $checked = checked="checked"
var $disable_js = //
var $valid=0
goto @search_form
else
var $valid=1
endif
# Length
var $len = call strlen $val=$search
if $len < $min_query_length
var $disable_js = //
print <span class="query_error">Search query too short minimum length $min_query_length chars</span> <br />
var $valid=0
goto @search_form
endif
# Invalid characters
# var $star = call strpos $haystack=#$search;$needle=*
# var $query = call strpos $haystack=#$search;$needle=?
var $neg = call strpos $haystack=#$search;$needle=-
var $dquot = call strpos $haystack=#$search;$needle="
var $squot = call strpos $haystack=#$search;$needle='
if $star or $query or $dquot or $squot or ($neg == 1)
print <span class="query_error">Search query contains invalid chars</span> <br />
var $disable_js = //
var $search = call htmlspecialchars $val=$search ;$flags=ENT_QUOTES
var $valid=0
goto @search_form
endif
# Anywhere in filename check
get anywhere
if $anywhere
var $checked = checked="checked"
var $any = *
endif
# Convert spaces to wildcards
var $spc=call chr $val=32
var $parsed_search=call str_replace $subject=$search;$search=$spc;$replace=*
# Filelist patterns
var $xt=xt:filelist folder
var $params = template="$template" filter="$any$parsed_search*$ext" per_page="0"
var $list1 = $xt="/FOLDER_1" $params
var $list2 = $xt="/FOLDER_2" $params
var $list3 = $xt="/FOLDER_3" $params
var $list4 = $xt="/FOLDER_4" $params
var $list5 = $xt="/FOLDER_5" $params
var $list6 = $xt="/FOLDER_6" $params
var $list7 = $xt="/FOLDER_7" $params
var $list8 = $xt="/FOLDER_8" $params
var $list9 = $xt="/FOLDER_9" $params
var $list10 = $xt="/FOLDER_10" $params
var $dummy = ['dummy']
# Search form
@search_form
print {{
<form action="<xt:url/>#srch" method="post">
<input type="search" name="search" value="$search" pattern=".{$min_query_length,}" title="Minimum $min_query_length characters required" placeholder="Enter search query"/>
<input type="submit" value="Search" /><br />
<label>Anywhere in filename </label><input type="checkbox" name="anywhere" value="1" $checked />
</form></div>}}
# Set up results and pagination containers
if $valid
print <div id="search_results"></div><div id="pagination"></div>
endif
# Start the javascript
print <script type="text/javascript">
# The results object function (associative array)
<!--/parser:xtscript-->
{_$$disable_js|function results()}{return [<{_$$list1|xt:code}><{_$$list2|xt:code}><{_$$list3|xt:code}><{_$$list4|xt:code}><{_$$list5|xt:code}><{_$$list6|xt:code}><{_$$list7|xt:code}><{_$$list8|xt:code}><{_$$list9|xt:code}><{_$$list10|xt:code}> {_$$dummy|}];}
<!--parser:xtscript-->
# Exit if invalid
if not $search or not $dummy or not $valid
goto @end
endif
# Trim and sort object (case insensitive)
print_raw {{
var list = results();
list.length -=1;
var length = list.length;
if (length > 0){
list.sort(function(x,y){
var a = String(x).toUpperCase();
var b = String(y).toUpperCase();
if (a > b) return 1;
if (a < b) return -1;
return 0;
});
}}
# Setup results page
print {{
var per_page = $per_page;
var search = '$search';
}}
print_raw {{
search_results = document.getElementById('search_results');
search_results.setAttribute('class','search_results');
var total_pages=Math.ceil(length / per_page);
}}
# The results function
print_raw {{
function results_data(results_page){
var offset = (results_page * per_page);
var page_end = (offset + per_page);
if (page_end > length)page_end = length;
results_info = '<div class="results_data"\>';
if(length > 1 && offset < length-1) results_info += (offset+1)+' to ';
if(length > 1)results_info += page_end+' of ';
results_info += length+' Result';
if(length > 1) results_info += 's';
results_info += ' For "<span> '+search+' </span>" ';
if (total_pages > 1) results_info += '<span>'+total_pages+' pages</span>';
results_info += '</div>';
search_results.innerHTML = results_info;
}}
# Results
print_raw {{
for (i = offset;i < page_end;i ++){
search_result = document.createElement('div');
search_result.setAttribute('class','search_result');
file_mime = list[i][4];
}}
# Result name and file extension
print_raw {{
lastDot = list[i][0].lastIndexOf('.') ;
if (lastDot > 0){
search_result_html = '<div class="result_name">Name <span>'+list[i][0].substr(0,lastDot)+'</span><span class="result_ext">.'+list[i][0].substr(lastDot+1).toLowerCase()+'</span></div>';
}else{
search_result_html = '<div class="result_name">Name <span>'+list[i][0]+'</span></div>';}
}}
# Download
print_raw {{
if (file_mime.indexOf('text') != 0){
search_result_html += '<div class="result_download_link"><a href="'+list[i][1]+'?__xt_download=1">Download</a></div>';}
else {
search_result_html += '<div class="result_download_link"><a target="_BLANK" href="'+list[i][1]+'">Open</a></div>';
}
}}
# Metadata
print_raw {{
search_result_html += '<div class="result_meta">Size <span>'+list[i][2]+'</span> Date <span>'+list[i][3]+'</span> Mime <span>'+file_mime+'</span></div>';
}}
# File url
print_raw {{
search_result_html +='<div class="result_url">Url <input type="text" value="'+list[i][1]+'" /></div>';
}}
# Image embed
print_raw {{
if (file_mime.indexOf('image')>=0) search_result_html += '<div class="result_image"><img src="'+list[i][1]+'" alt="" /></div>';
}}
# Audio embed
print_raw {{
if (file_mime == 'audio/mpeg' || file_mime == 'audio/wav' || file_mime == 'audio/mp4') search_result_html += '<div class="audio_player"><audio controls preload="metadata"><source src="'+list[i][1]+'" type="'+file_mime+'"></audio></div>';
}}
# Video embed
print_raw {{
if (file_mime == 'video/mp4' || file_mime == 'application/ogg') search_result_html += '<div class="video_player"><video controls preload="metadata"><source src="'+list[i][1]+'" type="'+file_mime+'"></video></div>';
}}
# Add result to page
print_raw {{
search_result.innerHTML = search_result_html;
search_results.appendChild(search_result);
}
}}
# Pagination
print_raw {{
if (length > per_page){
paging = document.getElementById('pagination');
paging.setAttribute('class','results_pagination');
buttons = '';
if (results_page >= 3) buttons += '<a href="#srch" onclick="results_data(0)" title="1">«</a>';
if (results_page >= 8) buttons += '<a href="#srch" onclick="results_data('+Math.floor(results_page/2)+')" title="'+Math.floor(results_page/2+1)+'">‹</a>';
if (results_page >= 2) buttons += '<a href="#srch" onclick="results_data('+(results_page-2)+')">'+(results_page-1)+'</a>';
if (results_page >= 1) buttons += '<a href="#srch" onclick="results_data('+(results_page-1)+')">'+results_page+'</a>';
buttons += '<span class="current">'+(results_page+1)+'</span>';
if (results_page < (total_pages-1)) buttons += '<a href="#srch" onclick="results_data('+(results_page+1)+')">'+(results_page+2)+'</a>';
if (results_page < (total_pages-2)) buttons += '<a href="#srch" onclick="results_data('+(results_page+2)+')">'+(results_page+3)+'</a>';
if (results_page < (total_pages-8)) buttons += '<a href="#srch" onclick="results_data('+Math.floor((total_pages+results_page)/2)+')" title="'+Math.floor((total_pages+results_page)/2+1)+'" >›</a>';
if (results_page < (total_pages-3)) buttons += '<a href="#srch" onclick="results_data('+(total_pages-1)+')" title="'+total_pages+'">»</a>';
paging.innerHTML=buttons;
}
}
}
else {}}
# No results for search query
print {{
document.getElementById('srch').innerHTML += '<div class="search_results"><span class="query_error">No results for " $search " </span></div>';}
if (length>0)results_data(0);
}}
@end
<!--/parser:xtscript-->
</script>
Show in textarea Example output