View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@cs.vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (C): 2009-2015, VU University Amsterdam
    7
    8    This program is free software; you can redistribute it and/or
    9    modify it under the terms of the GNU General Public License
   10    as published by the Free Software Foundation; either version 2
   11    of the License, or (at your option) any later version.
   12
   13    This program is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16    GNU General Public License for more details.
   17
   18    You should have received a copy of the GNU General Public
   19    License along with this library; if not, write to the Free Software
   20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21
   22    As a special exception, if you link this library with other files,
   23    compiled with a Free Software compiler, to produce an executable, this
   24    library does not by itself cause the resulting executable to be covered
   25    by the GNU General Public License. This exception does not however
   26    invalidate any other reasons why the executable file might be covered by
   27    the GNU General Public License.
   28*/
   29
   30:- module(plweb_wiki,
   31	  [ wiki_file_to_dom/2,		% +File, -DOM
   32	    wiki_file_codes_to_dom/3,	% +Codes, +File, -DOM
   33	    wiki_page_title/2,		% +Location, -Title
   34	    index_wiki_pages/0,		%
   35	    update_wiki_page_title/1,	% +Location
   36	    wiki_extension/1,		% ?Extension
   37	    file//2,			% +File, +Options
   38	    include//3			% +Object, +Type, +Options
   39	  ]).   40:- reexport(library(pldoc/doc_html),
   41	    except([ file//2,
   42		     include//3
   43		   ])).   44
   45:- use_module(library(pldoc/doc_wiki)).   46:- use_module(library(http/html_write)).   47:- use_module(library(http/http_wrapper)).   48:- use_module(library(http/http_dispatch)).   49:- use_module(library(readutil)).   50:- use_module(library(option)).   51:- use_module(library(apply)).   52:- use_module(library(lists)).   53:- use_module(library(filesex)).   54:- use_module(wiki_edit).   55
   56:- predicate_options(file//2, 2,
   57		     [ absolute_path(atom),
   58		       label(any)
   59		     ]).   60:- predicate_options(include//3, 3,
   61		     [pass_to(pldoc_html:include/5, 3)]).
 wiki_file_to_dom(+File, +DOM) is det
DOM is the HTML dom representation for the content of File.
   67wiki_file_to_dom(File, DOM) :-
   68	read_file_to_codes(File, String, []),
   69	wiki_file_codes_to_dom(String, File, DOM).
 wiki_codes_to_dom(+Codes, +File, -DOM)
DOM is the HTML dom representation for Codes that originate from File.
   76wiki_file_codes_to_dom(String, File, DOM) :-
   77	(   nb_current(pldoc_file, OrgFile)
   78	->  setup_call_cleanup(
   79		b_setval(pldoc_file, File),
   80		wiki_codes_to_dom(String, [], DOM),
   81		b_setval(pldoc_file, OrgFile))
   82	;   setup_call_cleanup(
   83		b_setval(pldoc_file, File),
   84		wiki_codes_to_dom(String, [], DOM),
   85		nb_delete(pldoc_file))
   86	).
   87
   88
   89		 /*******************************
   90		 *	     RENDERING		*
   91		 *******************************/
 include(+Object, +Type, +Options)//
   95include(Object, Type, Options) -->
   96	pldoc_html:include(Object, Type,
   97			   [ map_extension([txt-html])
   98			   | Options
   99			   ]).
 file(+Path, Options)//
Trap translation of \file(+Path, Options)
  105file(Path, Options) -->
  106	{ \+ option(label(_), Options),
  107	  file_base_name(Path, File),
  108	  file_name_extension(Label, txt, File), !,
  109	  file_href(Options, Options1)
  110	},
  111	pldoc_html:file(Path,
  112			[ label(Label),
  113			  map_extension([txt-html]),
  114			  edit_handler(wiki_edit)
  115			| Options1
  116			]).
  117file(File, Options) -->
  118	{ file_href(Options, Options1)
  119	},
  120	pldoc_html:file(File,
  121			[ map_extension([txt-html]),
  122			  edit_handler(wiki_edit)
  123			| Options1
  124			]).
  125
  126
  127file_href(Options0, Options) :-
  128	\+ ( nb_current(pldoc_file, CFile),
  129	     CFile \== []
  130	   ),
  131	option(absolute_path(Path), Options0),
  132	absolute_file_name(document_root(.),
  133			   DocRoot,
  134			   [ file_type(directory),
  135			     access(read)
  136			   ]),
  137	atom_concat(DocRoot, DocLocal, Path), !,
  138	ensure_leading_slash(DocLocal, HREF),
  139	Options = [ href(HREF) | Options0 ].
  140file_href(Options, Options).
  141
  142ensure_leading_slash(Path, SlashPath) :-
  143	(   sub_atom(Path, 0, _, _, /)
  144	->  SlashPath = Path
  145	;   atom_concat(/, Path, SlashPath)
  146	).
  147
  148		 /*******************************
  149		 *     OBJECT INTEGRATION	*
  150		 *******************************/
  151
  152:- multifile
  153	prolog:doc_object_summary/4,
  154	prolog:doc_object_link//2,
  155	prolog:doc_object_page//2,
  156	prolog:doc_category/3,
  157	prolog:doc_file_index_header//2.  158
  159prolog:doc_object_summary(wiki(Location), wiki, wiki, Summary) :-
  160	wiki_page_title(Location, Summary).
  161
  162:- dynamic
  163	wiki_page_title_cache/3,	% Location, Title, Time
  164	wiki_pages_indexed/1.
 wiki_page_title(?Location, ?Title) is nondet
True when Title is the title of the wiki page at Location.
  170wiki_page_title(Location, Title) :-
  171	wiki_pages_indexed(_), !,
  172	wiki_page_title_cache(Location, Title, _).
  173wiki_page_title(Location, Title) :-
  174	nonvar(Location), !,
  175	(   wiki_page_title_cache(Location, TitleRaw, _)
  176	->  Title = TitleRaw
  177	;   extract_wiki_page_title(Location, File, TitleRaw)
  178	->  time_file(File, Modified),
  179	    assertz(wiki_page_title_cache(Location, TitleRaw, Modified)),
  180	    Title = TitleRaw
  181	;   print_message(warning, wiki(no_title(Location))),
  182	    Title = 'No title'
  183	).
  184wiki_page_title(Location, Title) :-
  185	index_wiki_pages,
  186	wiki_page_title(Location, Title).
  187
  188
  189update_wiki_title_cache :-
  190	wiki_locations(Pages),
  191	maplist(update_wiki_page_title, Pages).
 update_wiki_page_title(Location) is det
Update the cached information about a wiki file.
  197update_wiki_page_title(Location) :-
  198	wiki_page_title_cache(Location, _, Time), !,
  199	location_wiki_file(Location, File),
  200	time_file(File, Modified),
  201	(   abs(Time-Modified) < 1
  202	->  true
  203	;   extract_wiki_page_title(Location, File, Title),
  204	    retractall(wiki_page_title_cache(Location, _, _)),
  205	    assertz(wiki_page_title_cache(Location, Title, Modified))
  206	).
  207update_wiki_page_title(Location) :-
  208	extract_wiki_page_title(Location, File, Title),
  209	time_file(File, Modified),
  210	assertz(wiki_page_title_cache(Location, Title, Modified)).
  211
  212extract_wiki_page_title(Location, File, Title) :-
  213	(   var(File)
  214	->  location_wiki_file(Location, File, read)
  215	;   true
  216	),
  217	(   catch(wiki_file_to_dom(File, DOM), E,
  218		  ( print_message(warning, E),
  219		    fail
  220		  )),
  221	    dom_title(DOM, Title)
  222	->  true
  223	;   format(atom(Title), 'Wiki page at "~w"', Location)
  224	).
 dom_title(+DOM, -Title) is semidet
Get the title as an atom from a parsed wiki page.
To be done
- Currently assumes no markup in the title.
  233dom_title([h1(_, TitleList)|_], Title) :-
  234	maplist(to_atom, TitleList, TitleList2),
  235	atomic_list_concat(TitleList2, Title).
  236
  237to_atom(Atomic, Atomic) :- atomic(Atomic).
  238to_atom(predref(Name/Arity), Label) :-
  239	atomic_list_concat([Name,/,Arity], Label).
  240
  241prolog:doc_object_link(wiki(Location), _Options) -->
  242	{ wiki_page_title(Location, Title) },
  243	html([ '[wiki] ', Title ]).
  244
  245prolog:doc_object_page(wiki(Location), _Options) -->
  246	{ http_current_request(Request),
  247	  http_redirect(see_other, root(Location), Request)
  248	}.
  249
  250prolog:doc_category(wiki, 60, 'Wiki pages').
  251
  252prolog:doc_file_index_header(wiki, _) --> [].
 index_wiki_pages
Create a (title) index of the available wiki pages. This is started from server/1 in a background thread.
  259index_wiki_pages :-
  260	wiki_pages_indexed(_), !.
  261index_wiki_pages :-
  262	with_mutex(index_wiki_pages,
  263		   index_wiki_pages_sync).
  264
  265index_wiki_pages_sync :-
  266	wiki_pages_indexed(_).
  267index_wiki_pages_sync :-
  268	wiki_locations(Locations),
  269	maplist(wiki_page_title, Locations, _Titles),
  270	get_time(Now),
  271	asserta(wiki_pages_indexed(Now)).
 wiki_locations(-Locations) is det
True when Files is a list of all .txt files on the site.
  278wiki_locations(Files) :-
  279	findall(Dir, absolute_file_name(
  280			 document_root(.), Dir,
  281			 [ access(read),
  282			   file_type(directory),
  283			   solutions(all)
  284			 ]),
  285		RootDirs),
  286	maplist(wiki_locations, RootDirs, NestedFiles),
  287	append(NestedFiles, Files).
  288
  289wiki_locations(Dir, Files) :-
  290	phrase(wiki_locations(Dir, Dir), Files).
  291
  292wiki_locations([], _) --> !.
  293wiki_locations([H|T], Root) --> !,
  294	wiki_locations(H, Root),
  295	wiki_locations(T, Root).
  296wiki_locations(CurrentDir, Root) -->
  297	{ exists_directory(CurrentDir), !,
  298	  directory_files(CurrentDir, Members),
  299	  exclude(special, Members, Members2),
  300	  maplist(directory_file_path(CurrentDir), Members2, MemberPaths)
  301	},
  302	wiki_locations(MemberPaths, Root).
  303wiki_locations(Entry, Root) -->
  304	{ file_name_extension(_, Ext, Entry),
  305	  wiki_extension(Ext), !,
  306	  directory_file_path(Root, Wiki, Entry)
  307	},
  308	[Wiki].
  309wiki_locations(_, _) --> [].
  310
  311wiki_extension(txt).
  312wiki_extension(md).
  313
  314special(.).
  315special(..)