@ -63,6 +63,7 @@ typedef struct {
excludes_buffer * excludes ;
buffer * external_css ;
buffer * external_js ;
buffer * encoding ;
buffer * set_footer ;
} plugin_config ;
@ -178,6 +179,7 @@ FREE_FUNC(mod_dirlisting_free) {
excludes_buffer_free ( s - > excludes ) ;
buffer_free ( s - > external_css ) ;
buffer_free ( s - > external_js ) ;
buffer_free ( s - > encoding ) ;
buffer_free ( s - > set_footer ) ;
@ -200,6 +202,7 @@ FREE_FUNC(mod_dirlisting_free) {
# define CONFIG_ACTIVATE "dir-listing.activate"
# define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
# define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
# define CONFIG_EXTERNAL_JS "dir-listing.external-js"
# define CONFIG_ENCODING "dir-listing.encoding"
# define CONFIG_SHOW_README "dir-listing.show-readme"
# define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
@ -231,6 +234,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
{ CONFIG_ENCODE_README , NULL , T_CONFIG_BOOLEAN , T_CONFIG_SCOPE_CONNECTION } , /* 11 */
{ CONFIG_ENCODE_HEADER , NULL , T_CONFIG_BOOLEAN , T_CONFIG_SCOPE_CONNECTION } , /* 12 */
{ CONFIG_AUTO_LAYOUT , NULL , T_CONFIG_BOOLEAN , T_CONFIG_SCOPE_CONNECTION } , /* 13 */
{ CONFIG_EXTERNAL_JS , NULL , T_CONFIG_STRING , T_CONFIG_SCOPE_CONNECTION } , /* 14 */
{ NULL , NULL , T_CONFIG_UNSET , T_CONFIG_SCOPE_UNSET }
} ;
@ -248,6 +252,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
s - > excludes = excludes_buffer_init ( ) ;
s - > dir_listing = 0 ;
s - > external_css = buffer_init ( ) ;
s - > external_js = buffer_init ( ) ;
s - > hide_dot_files = 1 ;
s - > show_readme = 0 ;
s - > hide_readme_file = 0 ;
@ -274,6 +279,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
cv [ 11 ] . destination = & ( s - > encode_readme ) ;
cv [ 12 ] . destination = & ( s - > encode_header ) ;
cv [ 13 ] . destination = & ( s - > auto_layout ) ;
cv [ 14 ] . destination = s - > external_js ;
p - > config_storage [ i ] = s ;
@ -331,6 +337,7 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH ( dir_listing ) ;
PATCH ( external_css ) ;
PATCH ( external_js ) ;
PATCH ( hide_dot_files ) ;
PATCH ( encoding ) ;
PATCH ( show_readme ) ;
@ -362,6 +369,8 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH ( hide_dot_files ) ;
} else if ( buffer_is_equal_string ( du - > key , CONST_STR_LEN ( CONFIG_EXTERNAL_CSS ) ) ) {
PATCH ( external_css ) ;
} else if ( buffer_is_equal_string ( du - > key , CONST_STR_LEN ( CONFIG_EXTERNAL_JS ) ) ) {
PATCH ( external_js ) ;
} else if ( buffer_is_equal_string ( du - > key , CONST_STR_LEN ( CONFIG_ENCODING ) ) ) {
PATCH ( encoding ) ;
} else if ( buffer_is_equal_string ( du - > key , CONST_STR_LEN ( CONFIG_SHOW_README ) ) ) {
@ -509,6 +518,189 @@ static void http_list_directory_include_file(buffer *out, buffer *path, const ch
}
}
/* portions copied from mod_status
* modified and specialized for stable dirlist sorting by name */
static const char js_simple_table_resort [ ] = \
" var click_column; \n " \
" var name_column = 0; \n " \
" var date_column = 1; \n " \
" var size_column = 2; \n " \
" var type_column = 3; \n " \
" var prev_span = null; \n " \
" \n " \
" if (typeof(String.prototype.localeCompare) === 'undefined') { \n " \
" String.prototype.localeCompare = function(str, locale, options) { \n " \
" return ((this == str) ? 0 : ((this > str) ? 1 : -1)); \n " \
" }; \n " \
" } \n " \
" \n " \
" if (typeof(String.prototype.toLocaleUpperCase) === 'undefined') { \n " \
" String.prototype.toLocaleUpperCase = function() { \n " \
" return this.toUpperCase(); \n " \
" }; \n " \
" } \n " \
" \n " \
" function get_inner_text(el) { \n " \
" if((typeof el == 'string')||(typeof el == 'undefined')) \n " \
" return el; \n " \
" if(el.innerText) \n " \
" return el.innerText; \n " \
" else { \n " \
" var str = \" \" ; \n " \
" var cs = el.childNodes; \n " \
" var l = cs.length; \n " \
" for (i=0;i<l;i++) { \n " \
" if (cs[i].nodeType==1) str += get_inner_text(cs[i]); \n " \
" else if (cs[i].nodeType==3) str += cs[i].nodeValue; \n " \
" } \n " \
" } \n " \
" return str; \n " \
" } \n " \
" \n " \
" function isdigit(c) { \n " \
" return (c >= '0' && c <= '9'); \n " \
" } \n " \
" \n " \
" function unit_multiplier(unit) { \n " \
" return (unit=='K') ? 1000 \n " \
" : (unit=='M') ? 1000000 \n " \
" : (unit=='G') ? 1000000000 \n " \
" : (unit=='T') ? 1000000000000 \n " \
" : (unit=='P') ? 1000000000000000 \n " \
" : (unit=='E') ? 1000000000000000000 : 1; \n " \
" } \n " \
" \n " \
" function sortfn_then_by_name(a,b,sort_column) { \n " \
" if (sort_column == name_column || sort_column == type_column) { \n " \
" var ad = (a.cells[type_column].innerHTML === 'Directory'); \n " \
" var bd = (b.cells[type_column].innerHTML === 'Directory'); \n " \
" if (ad != bd) return (ad ? -1 : 1); \n " \
" } \n " \
" var at = get_inner_text(a.cells[sort_column]); \n " \
" var bt = get_inner_text(b.cells[sort_column]); \n " \
" var cmp; \n " \
" if (a.cells[sort_column].className == 'int') { \n " \
" cmp = parseInt(at)-parseInt(bt); \n " \
" } else if (sort_column == date_column) { \n " \
" cmp = Date.parse(at.replace(/-/g, '/')) \n " \
" - Date.parse(bt.replace(/-/g, '/')); \n " \
" var ad = isdigit(at.substr(0,1)); \n " \
" var bd = isdigit(bt.substr(0,1)); \n " \
" if (ad != bd) return (!ad ? -1 : 1); \n " \
" } else if (sort_column == size_column) { \n " \
" var ai = parseInt(at, 10) * unit_multiplier(at.substr(-1,1)); \n " \
" var bi = parseInt(bt, 10) * unit_multiplier(bt.substr(-1,1)); \n " \
" if (at.substr(0,1) == '-') ai = -1; \n " \
" if (bt.substr(0,1) == '-') bi = -1; \n " \
" cmp = ai - bi; \n " \
" } else { \n " \
" cmp = at.toLocaleUpperCase().localeCompare(bt.toLocaleUpperCase()); \n " \
" if (0 != cmp) return cmp; \n " \
" cmp = at.localeCompare(bt); \n " \
" } \n " \
" if (0 != cmp || sort_column == name_column) return cmp; \n " \
" return sortfn_then_by_name(a,b,name_column); \n " \
" } \n " \
" \n " \
" function sortfn(a,b) { \n " \
" return sortfn_then_by_name(a,b,click_column); \n " \
" } \n " \
" \n " \
" function resort(lnk) { \n " \
" var span = lnk.childNodes[1]; \n " \
" var table = lnk.parentNode.parentNode.parentNode.parentNode; \n " \
" var rows = new Array(); \n " \
" for (j=1;j<table.rows.length;j++) \n " \
" rows[j-1] = table.rows[j]; \n " \
" click_column = lnk.parentNode.cellIndex; \n " \
" rows.sort(sortfn); \n " \
" \n " \
" if (prev_span != null) prev_span.innerHTML = ''; \n " \
" if (span.getAttribute('sortdir')=='down') { \n " \
" span.innerHTML = '↑'; \n " \
" span.setAttribute('sortdir','up'); \n " \
" rows.reverse(); \n " \
" } else { \n " \
" span.innerHTML = '↓'; \n " \
" span.setAttribute('sortdir','down'); \n " \
" } \n " \
" for (i=0;i<rows.length;i++) \n " \
" table.tBodies[0].appendChild(rows[i]); \n " \
" prev_span = span; \n " \
" } \n " ;
/* portions copied from mod_dirlist (lighttpd2) */
static const char js_simple_table_init_sort [ ] = \
" \n " \
" function init_sort(init_sort_column, ascending) { \n " \
" var tables = document.getElementsByTagName( \" table \" ); \n " \
" for (var i = 0; i < tables.length; i++) { \n " \
" var table = tables[i]; \n " \
" //var c = table.getAttribute( \" class \" ) \n " \
" //if (-1 != c.split( \" \" ).indexOf( \" sort \" )) { \n " \
" var row = table.rows[0].cells; \n " \
" for (var j = 0; j < row.length; j++) { \n " \
" var n = row[j]; \n " \
" if (n.childNodes.length == 1 && n.childNodes[0].nodeType == 3) { \n " \
" var link = document.createElement( \" a \" ); \n " \
" var title = n.childNodes[0].nodeValue.replace(/:$/, \" \" ); \n " \
" link.appendChild(document.createTextNode(title)); \n " \
" link.setAttribute( \" href \" , \" # \" ); \n " \
" link.setAttribute( \" class \" , \" sortheader \" ); \n " \
" link.setAttribute( \" onclick \" , \" resort(this);return false; \" ); \n " \
" var arrow = document.createElement( \" span \" ); \n " \
" arrow.setAttribute( \" class \" , \" sortarrow \" ); \n " \
" arrow.appendChild(document.createTextNode( \" : \" )); \n " \
" link.appendChild(arrow) \n " \
" n.replaceChild(link, n.firstChild); \n " \
" } \n " \
" } \n " \
" var lnk = row[init_sort_column].firstChild; \n " \
" if (ascending) { \n " \
" var span = lnk.childNodes[1]; \n " \
" span.setAttribute('sortdir','down'); \n " \
" } \n " \
" resort(lnk); \n " \
" //} \n " \
" } \n " \
" } \n " ;
static void http_dirlist_append_js_table_resort ( buffer * b , connection * con ) {
char col = ' 0 ' ;
char ascending = ' 0 ' ;
if ( ! buffer_string_is_empty ( con - > uri . query ) ) {
const char * qs = con - > uri . query - > ptr ;
do {
if ( qs [ 0 ] = = ' C ' & & qs [ 1 ] = = ' = ' ) {
switch ( qs [ 2 ] ) {
case ' N ' : col = ' 0 ' ; break ;
case ' M ' : col = ' 1 ' ; break ;
case ' S ' : col = ' 2 ' ; break ;
case ' T ' :
case ' D ' : col = ' 3 ' ; break ;
default : break ;
}
}
else if ( qs [ 0 ] = = ' O ' & & qs [ 1 ] = = ' = ' ) {
switch ( qs [ 2 ] ) {
case ' A ' : ascending = ' 1 ' ; break ;
case ' D ' : ascending = ' 0 ' ; break ;
default : break ;
}
}
} while ( ( qs = strchr ( qs , ' & ' ) ) & & * + + qs ) ;
}
buffer_append_string_len ( b , CONST_STR_LEN ( " \n <script type= \" text/javascript \" > \n // <!-- \n \n " ) ) ;
buffer_append_string_len ( b , js_simple_table_resort , sizeof ( js_simple_table_resort ) - 1 ) ;
buffer_append_string_len ( b , js_simple_table_init_sort , sizeof ( js_simple_table_init_sort ) - 1 ) ;
buffer_append_string_len ( b , CONST_STR_LEN ( " \n init_sort( " ) ) ;
buffer_append_string_len ( b , & col , 1 ) ;
buffer_append_string_len ( b , CONST_STR_LEN ( " , " ) ) ;
buffer_append_string_len ( b , & ascending , 1 ) ;
buffer_append_string_len ( b , CONST_STR_LEN ( " ); \n \n // --> \n </script> \n \n " ) ) ;
}
static void http_list_directory_header ( server * srv , connection * con , plugin_data * p , buffer * out ) {
UNUSED ( srv ) ;
@ -592,7 +784,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
" </thead> \n "
" <tbody> \n "
" <tr class= \" d \" > "
" <td class= \" n \" ><a href= \" ../ \" >Parent Directory </a>/</td> "
" <td class= \" n \" ><a href= \" ../ \" >.. </a>/</td> "
" <td class= \" m \" > </td> "
" <td class= \" s \" >- </td> "
" <td class= \" t \" >Directory</td> "
@ -620,6 +812,15 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
}
if ( p - > conf . auto_layout ) {
if ( ! buffer_string_is_empty ( p - > conf . external_js ) ) {
buffer_append_string_len ( out , CONST_STR_LEN ( " <script type= \" text/javascript \" src= \" " ) ) ;
buffer_append_string_buffer ( out , p - > conf . external_js ) ;
buffer_append_string_len ( out , CONST_STR_LEN ( " \" /> \n " ) ) ;
} else if ( buffer_is_empty ( p - > conf . external_js ) ) {
http_dirlist_append_js_table_resort ( out , con ) ;
}
buffer_append_string_len ( out , CONST_STR_LEN (
" <div class= \" foot \" > "
) ) ;