203 lines
5.7 KiB
Prolog
203 lines
5.7 KiB
Prolog
/* Part of SWI-Prolog
|
|
|
|
Author: Jan Wielemaker
|
|
E-mail: J.Wielemaker@cs.vu.nl
|
|
WWW: http://www.swi-prolog.org
|
|
Copyright (C): 2009, VU University Amsterdam
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
As a special exception, if you link this library with other files,
|
|
compiled with a Free Software compiler, to produce an executable, this
|
|
library does not by itself cause the resulting executable to be covered
|
|
by the GNU General Public License. This exception does not however
|
|
invalidate any other reasons why the executable file might be covered by
|
|
the GNU General Public License.
|
|
*/
|
|
|
|
:- module(http_dirindex,
|
|
[ http_reply_dirindex/3 % +PhysicalDir, +Options, +Request
|
|
]).
|
|
:- use_module(library(http/html_write)).
|
|
:- use_module(library(http/http_path)).
|
|
:- use_module(library(http/http_dispatch)).
|
|
:- use_module(library(http/http_server_files)).
|
|
:- use_module(library(http/html_head)).
|
|
:- use_module(library(apply)).
|
|
:- use_module(library(option)).
|
|
|
|
/** <module> HTTP directory listings
|
|
|
|
This module provides a simple API to generate an index for a physical
|
|
directory. The index can be customised by overruling the dirindex.css
|
|
CSS file and by defining additional rules for icons using the hook
|
|
http:file_extension_icon/2.
|
|
|
|
@tbd Provide more options (sorting, selecting columns, hiding files)
|
|
*/
|
|
|
|
%% http_reply_dirindex(+DirSpec, +Options, +Request) is det.
|
|
%
|
|
% Provide a directory listing for Request, assuming it is an index
|
|
% for the physical directrory Dir. If the request-path does not
|
|
% end with /, first return a moved (301 Moved Permanently) reply.
|
|
%
|
|
% The calling conventions allows for direct calling from
|
|
% http_handler/3.
|
|
|
|
http_reply_dirindex(DirSpec, Options, Request) :-
|
|
http_safe_file(DirSpec, Options),
|
|
absolute_file_name(DirSpec, Dir,
|
|
[ file_type(directory),
|
|
access(read)
|
|
]),
|
|
memberchk(path(Path), Request),
|
|
( atom_concat(PlainPath, /, Path),
|
|
merge_options(Options,
|
|
[ title(['Index of ', PlainPath]) ],
|
|
Options1)
|
|
-> dir_index(Dir, Options1)
|
|
; atom_concat(Path, /, NewLocation),
|
|
throw(http_reply(moved(NewLocation)))
|
|
).
|
|
|
|
dir_index(Dir, Options) :-
|
|
directory_members(Dir, SubDirs, Files),
|
|
option(title(Title), Options, Dir),
|
|
reply_html_page(title(Title),
|
|
[ \html_requires(http_dirindex),
|
|
h1(Title),
|
|
table(class(dirindex),
|
|
[ \dirindex_title,
|
|
\back
|
|
| \dirmembers(SubDirs, Files)
|
|
])
|
|
]).
|
|
|
|
directory_members(Dir, Dirs, Files) :-
|
|
atom_concat(Dir, '/*', Pattern),
|
|
expand_file_name(Pattern, Matches),
|
|
partition(exists_directory, Matches, Dirs, Files).
|
|
|
|
dirindex_title -->
|
|
html(tr(class(dirindex_header),
|
|
[ th(class(icon), ''),
|
|
th(class(name), 'Name'),
|
|
th(class(modified), 'Last modified'),
|
|
th(class(size), 'Size')
|
|
])).
|
|
|
|
back -->
|
|
html(tr([ \icon_cell('back.png', '[UP]'),
|
|
\name_cell(.., 'Up'),
|
|
td(class(modified), -),
|
|
td(class(size), -)
|
|
])).
|
|
|
|
dirmembers(Dirs, Files) -->
|
|
dir_rows(Dirs, odd, End),
|
|
file_rows(Files, End, _).
|
|
|
|
dir_rows([], OE, OE) --> [].
|
|
dir_rows([H|T], OE0, OE) -->
|
|
dir_row(H, OE0),
|
|
{ oe(OE0, OE1) },
|
|
dir_rows(T, OE1, OE).
|
|
|
|
file_rows([], OE, OE) --> [].
|
|
file_rows([H|T], OE0, OE) -->
|
|
file_row(H, OE0),
|
|
{oe(OE0, OE1)},
|
|
file_rows(T, OE1, OE).
|
|
|
|
oe(odd, even).
|
|
oe(even, odd).
|
|
|
|
dir_row(Dir, OE) -->
|
|
{ file_base_name(Dir, Name)
|
|
},
|
|
html(tr(class(OE),
|
|
[ \icon_cell('folder.png', '[DIR]'),
|
|
\name_cell(Name, Name),
|
|
\modified_cell(Dir),
|
|
td(class(size), -)
|
|
])).
|
|
|
|
|
|
file_row(File, OE) -->
|
|
{ file_base_name(File, Name),
|
|
file_name_extension(_, Ext, Name),
|
|
file_type_icon(Ext, IconName)
|
|
},
|
|
html(tr(class(OE),
|
|
[ \icon_cell(IconName, '[FILE]'),
|
|
\name_cell(Name, Name),
|
|
\modified_cell(File),
|
|
td(class(size), \size(File))
|
|
])).
|
|
|
|
icon_cell(IconName, Alt) -->
|
|
{ http_absolute_location(icons(IconName), Icon, [])
|
|
},
|
|
html(td(class(icon), img([src(Icon), alt(Alt)]))).
|
|
|
|
|
|
name_cell(Ref, Name) -->
|
|
html(td(class(name), a(href(Ref), Name))).
|
|
|
|
|
|
modified_cell(Name) -->
|
|
{ time_file(Name, Stamp),
|
|
format_time(string(Date), '%+', Stamp)
|
|
},
|
|
html(td(class(modified), Date)).
|
|
|
|
size(Name) -->
|
|
{ size_file(Name, Size)
|
|
},
|
|
html('~D'-[Size]).
|
|
|
|
%% file_type_icon(+Extension, -Icon) is det.
|
|
%
|
|
% Determine the icon that is used to show a file of the given
|
|
% extension. This predicate can be hooked using the multifile
|
|
% http:file_extension_icon/2 hook with the same signature. Icon is
|
|
% the plain name of an image file that appears in the
|
|
% file-search-path =icons=.
|
|
|
|
file_type_icon(Ext, Icon) :-
|
|
http:file_extension_icon(Ext, Icon), !.
|
|
file_type_icon(_, 'generic.png').
|
|
|
|
:- multifile
|
|
http:file_extension_icon/2.
|
|
|
|
http:file_extension_icon(pdf, 'layout.png').
|
|
http:file_extension_icon(c, 'c.png').
|
|
http:file_extension_icon(gz, 'compressed.png').
|
|
http:file_extension_icon(tgz, 'compressed.png').
|
|
http:file_extension_icon(zip, 'compressed.png').
|
|
|
|
|
|
/*******************************
|
|
* RESOURCES *
|
|
*******************************/
|
|
|
|
:- html_resource(http_dirindex,
|
|
[ virtual(true),
|
|
requires([ css('dirindex.css')
|
|
])
|
|
]).
|