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-2017, 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_page, []).   31:- use_module(footer).   32:- use_module(library(http/html_write)).   33:- use_module(library(http/html_head)).   34:- use_module(library(http/http_path)).   35:- use_module(library(pldoc/doc_search)).   36:- use_module(library(http/js_write)).   37:- use_module(library(http/html_head)).   38:- use_module(library(http/http_wrapper)).   39:- use_module(library(http/http_dispatch)).   40:- use_module(library(http/http_parameters)).   41:- use_module(library(pldoc/doc_html), [object_name//2]).   42:- use_module(library(uri)).   43:- use_module(library(option)).   44
   45:- use_module(wiki).   46:- use_module(post).   47:- use_module(openid).   48:- use_module(did_you_know).   49:- use_module(holidays).   50
   51:- html_meta
   52	outer_container(html, +, ?, ?).   53
   54:- http_handler(root(search), plweb_search, []).
 user:body(+Style, +Body)//
Provide the page skin.
   60:- multifile
   61	user:body//2,
   62	plweb:page_title//1.   63
   64user:body(homepage, Body) --> !,
   65	outer_container([ \tag_line_area,
   66			  \menubar(homepage),
   67			  \blurb,
   68			  \cta_area,
   69			  \enhanced_search_area,
   70			  Body
   71			], []).
   72user:body(Style, Body) -->
   73	{ page_style(Style, Options), !,
   74	  functor(Style, ContentClass, _)
   75	},
   76	outer_container(
   77	    [ \title_area(Style),
   78	      \menubar(Style),
   79	      div(class(breadcrumb), []),
   80	      div(class(['inner-contents', ContentClass]),
   81		  div([id(contents), class([contents, ContentClass])],
   82		      Body))
   83	    ],
   84	    Options).
   85user:body(Style, Body) -->
   86	{ Style = forum(_) }, !,
   87	outer_container(
   88	    [ \title_area(Style),
   89	      \menubar(Style),
   90	      div(class(breadcrumb), []),
   91	      Body
   92	    ],
   93	    []).
   94user:body(plain, Body) --> !,
   95	html(body(class(plain), Body)).
   96user:body(default, Body) --> !,
   97	html(body(class(plain), Body)).
   98user:body(Style, _Body) -->
   99	html(div('Unknown page style ~q'-[Style])).
 page_style(+Style, -Options) is semidet
True if Style is an `object page' and Obj is the object.
  105page_style(user(_Action),	   [show_user(false)]).
  106page_style(download(_Dir, _Title), []).
  107page_style(dir_index(_Dir, _Title),[]).
  108page_style(news(_Which),	   []).
  109page_style(wiki(_Special),	   []).
  110page_style(wiki(Path, _Title),	   [object(wiki(Path))]).
  111page_style(pack(_Action),	   []).
  112page_style(tags(_Action),	   []).
  113page_style(pldoc(object(Obj)),	   [object(Obj)]) :- !.
  114page_style(pldoc(search(For)),     [for(For)]) :- !.
  115page_style(pldoc(_),		   []).
  116page_style(pack(_Type, _Title),	   []).
  117page_style(git(_),		   []).
 outer_container(+Content, +Options)//
Display a typical page including headers and footers.
  123outer_container(Content, Options) -->
  124	html(body(div(class('outer-container'),
  125		  [ \html_requires(plweb),
  126		    \html_requires(swipl_css),
  127		    \shortcut_icons,
  128		    \upper_header(Options),
  129		    Content,
  130		    div([id(dialog),style('display:none;')], []),
  131		    div(class([footer, newstyle]), \footer(Options)),
  132		    div(id('tail-end'), &(nbsp))
  133		  ]))),
  134	html_receive(script).
 prolog:doc_page_header(+File, +Options)// is det
prolog:doc_links(+Directory, +Options)// is det
prolog:doc_file_title(+Title, +File, +Options)// is det
Called to render the PlDoc page header and link menu. We kill both.
  144:- multifile
  145	prolog:doc_page_header//2,
  146	prolog:doc_links//2.  147
  148prolog:doc_page_header(_File, _Options) --> [].
  149prolog:doc_links(_Directory, _Options) --> [].
  150prolog:doc_file_title(_Title, _File, _Options) --> [].
  151
  152shortcut_icons -->
  153	{ http_absolute_location(icons('favicon.ico'), FavIcon, []),
  154	  http_absolute_location(root('apple-touch-icon.png'), TouchIcon, [])
  155	},
  156	html_post(head,
  157		  [ link([ rel('shortcut icon'), href(FavIcon) ]),
  158		    link([ rel('apple-touch-icon'), href(TouchIcon) ])
  159		  ]).
 upper_header(+Options)//
Emit the small blue header with Did You Know? and search box
  165upper_header(Options) -->
  166	{ http_link_to_id(plweb_search, [], Action),
  167	  option(for(Search), Options, '')
  168	},
  169	html(div(id('upper-header'),
  170		 table(id('upper-header-contents'),
  171		       tr([ td(id('dyknow-container'),
  172			       \did_you_know_script('dyknow-container')),
  173			    td(id('search-container'),
  174			       [ span(class(lbl), 'Search Documentation:'),
  175				 form([action(Action),id('search-form')],
  176				      [ input([ name(for),
  177						id(for),
  178						value(Search)
  179					      ], []),
  180					input([ id('submit-for'),
  181						type(submit),
  182						value('Search')
  183					      ], []),
  184					\searchbox_script(for)
  185				      ])
  186			       ])
  187			  ])))).
 plweb_search(+Request)
HTTP Handler to search the Prolog website.
  193plweb_search(Request) :-
  194	http_parameters(
  195	    Request,
  196	    [ for(For,
  197		  [ default(''),
  198		    description('String to search for')
  199		  ]),
  200	      in(In,
  201		 [ oneof([all,app,noapp,man,lib,pack,wiki]),
  202		   default(noapp),
  203		   description('Search everying, application only \c
  204		                or manual only')
  205		 ]),
  206	      match(Match,
  207		    [ oneof([name,summary]),
  208		      default(summary),
  209		      description('Match only the name or also the summary')
  210		    ]),
  211	      resultFormat(Format,
  212			   [ oneof(long,summary),
  213			     default(summary),
  214			     description('Return full documentation \c
  215			                  or summary-lines')
  216			   ]),
  217	      page(Page,
  218		   [ integer,
  219		     default(1),
  220		     description('Page of search results to view')
  221		   ])
  222
  223	    ]),
  224	format(string(Title), 'Prolog search -- ~w', [For]),
  225	reply_html_page(pldoc(search(For)),
  226			title(Title),
  227			\search_reply(For,
  228				      [ resultFormat(Format),
  229					search_in(In),
  230					search_match(Match),
  231					header(false),
  232					private(false),
  233					edit(false),
  234					page(Page)
  235				      ])).
 searchbox_script(+Tag)//
Emits the script tag for the searchbox
  242searchbox_script(Tag) -->
  243	html([
  244	    \html_requires(jquery_ui),
  245	    script(type('text/javascript'), {|javascript(Tag)||
  246    $(function() {
  247	function htmlEncode(text) {
  248	  if ( !text ) return "";
  249	  return document.createElement('a')
  250			 .appendChild(document.createTextNode(text))
  251			 .parentNode
  252			 .innerHTML;
  253	}
  254        $("#"+Tag).autocomplete({
  255        minLength: 1,
  256        delay: 0.3,
  257        source: "/autocomplete/ac_predicate",
  258        focus: function(event,ui) {
  259          $("#"+Tag).val(ui.item.label);
  260          return false;
  261        },
  262        select: function(event,ui) {
  263          $("#"+Tag).val(ui.item.label);
  264          window.location.href = ui.item.href;
  265          return false;
  266        }
  267        })
  268        .data("ui-autocomplete")._renderItem = function(ul,item) {
  269        var label = String(htmlEncode(item.label)).replace(
  270            htmlEncode(this.term),
  271            "<span class=\"acmatch\">"+this.term+"</span>");
  272        var tag = item.tag ? " <i>["+item.tag+"]</i>" : "";
  273        return $("<li>")
  274          .append("<a class=\""+item.class+"\">"+label+tag+"</a>")
  275          .appendTo(ul)
  276        };
  277        });
  278|})]).
 tag_line_area//
Emit the Owl logo and tagline area (Robust, mature, free. Prolog for the real world)
  285tag_line_area -->
  286	html(div(id('tag-line-area'),
  287		 [ \swi_logo,
  288		   span(class(tagline),
  289			[ 'Robust, mature, free. ',
  290			  b('Prolog for the real world.')
  291			])
  292		 ])).
 title_area(+Style)
  297title_area(pldoc(file(File, Title))) --> !,
  298	{ file_base_name(File, Base) },
  299	html([ table(id('header-line-area'),
  300		     tr([ td(id('logo'), \swi_logo),
  301			  td(class('primary-header'),
  302			     \page_title(title(Title)))
  303			])),
  304	       div([ class('file-buttons')
  305		   ],
  306		   [ \zoom_button(Base, []),
  307		     \source_button(Base, [])
  308		   ])
  309	     ]).
  310title_area(Style) -->
  311	html(table(id('header-line-area'),
  312		   tr([ td(id('logo'), \swi_logo),
  313			td(class('primary-header'),
  314			   \page_title(Style))
  315		      ]))).
  316
  317page_title(For) -->
  318	plweb:page_title(For), !.
  319page_title(pldoc(search(''))) --> !,
  320	html('How to use the search box').
  321page_title(pldoc(search(For))) --> !,
  322	html(['Search results for ', span(class(for), ['"', For, '"'])]).
  323page_title(pldoc(object(Obj))) -->
  324	object_name(Obj,
  325		    [ style(title)
  326		    ]), !.
  327page_title(title(Title)) --> !,
  328	html(Title).
  329page_title(user(login)) --> !,
  330	html('Login to www.swi-prolog.org').
  331page_title(user(logout)) --> !,
  332	html('Logged out from www.swi-prolog.org').
  333page_title(user(create_profile)) --> !,
  334	html('Create user profile').
  335page_title(user(view_profile(UUID))) --> !,
  336	{ site_user_property(UUID, name(Name)) },
  337	html('Profile for user ~w'-[Name]).
  338page_title(user(list)) --> !,
  339	html('Registered site users').
  340page_title(news(fresh)) --> !,
  341	html('News').
  342page_title(news(all)) --> !,
  343	html('News archive').
  344page_title(news(Id)) -->
  345	{ post(Id, title, Title) },
  346	html(Title).
  347page_title(pack(list)) -->
  348	html('Packs (add-ons) for SWI-Prolog').
  349page_title(wiki(sandbox)) -->
  350	html('PlDoc wiki sandbox').
  351page_title(wiki(edit(Action, Location))) -->
  352	html([Action, ' wiki page ', Location]).
  353page_title(wiki(_Path, Title)) -->
  354	html(Title).
  355page_title(tags(list)) -->
  356	html('Tags').
  357page_title(download(_Dir, Title)) -->
  358	html(Title).
  359page_title(dir_index(_Dir, Title)) -->
  360	html(Title).
  361page_title(Term) -->
  362	html('Title for ~q'-[Term]).
 todays_logo(-File:atom, -AltText:atom) is det
succeeds if File is the relative name of the appropriate version of the swi-Prolog logo for the day and AltText is the alt text
  371todays_logo('christmas.png', 'Merry Christmas.') :-
  372	todays_holiday(christmas).
  373todays_logo('koningsdag.png', 'Kings day in the Netherlands') :-
  374	todays_holiday(koningsdag).
  375todays_logo('santiklaas.png', 'St. Nicholas\' eve in the Netherlands') :-
  376	todays_holiday(santiklaas).
  377todays_logo('carnivalswipl.png', 'Carnival in the Netherlands') :-
  378	todays_holiday(carnival).
  379todays_logo('halloween.png', 'Hoooo.... on Halloween') :-
  380	todays_holiday(halloween).
  381todays_logo('chinesenewyear.png', 'Chinese New Year') :-
  382	todays_holiday(chinese_new_year).
  383todays_logo('liberationday.png', 'Liberation Day in the Netherlands') :-
  384	todays_holiday(liberation_day).
  385todays_logo('swipl.png', 'SWI-Prolog owl logo') :-
  386	todays_holiday(_).
 swi_logo//
Embed the SWI-Prolog logo.
  392swi_logo -->
  393	{ todays_logo(File, Alt),
  394	  http_absolute_location(icons(File), Logo, [])
  395	},
  396	html(a(href('http://www.swi-prolog.org'),
  397	       img([ class(owl),
  398		     src(Logo),
  399		     alt(Alt),
  400		     title(Alt)
  401		   ], []))).
 menubar(+Style)// is semidet
Emits a menubar. Style is the page style
  408menubar(Style) -->
  409	{ menu(Style, Menu) },
  410	html_requires(jquery),
  411	html_requires(jq('menu.js')),
  412	html(div(id(menubar),
  413		 div(class([menubar, 'fixed-width']),
  414		     ul(class('menubar-container'),
  415			\menu(Menu, 1))))).
  416
  417menu([], _) --> !.
  418menu([H|T], Level) --> !, menu(H, Level), menu(T, Level).
  419menu(Label = Link + SubMenu, Level) --> !,
  420	submenu(Label, Level, SubMenu, Link).
  421menu(Label = SubMenu, Level) -->
  422	{ is_list(SubMenu)
  423	}, !,
  424	submenu(Label, Level, SubMenu, -).
  425menu(Label = Link, _) -->
  426	{ atom(Link),
  427	  uri_is_global(Link), !,
  428	  http_absolute_location(icons('ext-link.png'), IMG, [])
  429	}, !,
  430	html(li([ a(href(Link),
  431		    [ Label,
  432		      img([ class('ext-link'),
  433			    src(IMG),
  434			    alt('External')
  435			  ])
  436		    ])
  437		])).
  438menu(_Label = (-), _) --> !,
  439	[].
  440menu(Label = Link, 1) -->
  441	{ upcase_atom(Label, LABEL) },
  442	html(li(a(href(Link), LABEL))).
  443menu(Label = Link, _) -->
  444	html(li(a(href(Link), Label))).
  445
  446submenu(Label, Level, SubMenu, -) --> !,
  447	{ SubLevel is Level+1 },
  448	html(li([ \submenu_label(Label, Level),
  449		  ul(\menu(SubMenu, SubLevel))
  450		])).
  451submenu(Label, Level, SubMenu, HREF) -->
  452	{ SubLevel is Level+1 },
  453	html(li([ a(href(HREF), \submenu_label(Label, Level)),
  454		  ul(\menu(SubMenu, SubLevel))
  455		])).
  456
  457submenu_label(Label, Level) -->
  458	{ Level =< 1,
  459	  upcase_atom(Label, LABEL)
  460	}, !,
  461	html(LABEL).
  462submenu_label(Label, _) -->
  463	html([Label, span(class(arrow), &('#x25B6'))]).
  464
  465
  466menu(Style,
  467     [ 'Home'                = '/',
  468       'Download' =
  469       [ 'SWI-Prolog'	     = '/Download.html',
  470	 'Sources/building'  = '/build/',
  471	 'Docker images'     = '/Docker.html',
  472	 'Add-ons'           = '/pack/list',
  473	 'Browse GIT'	     = 'https://github.com/SWI-Prolog'
  474       ],
  475       'Documentation' =
  476       [ 'Manual'              = '/pldoc/refman/',
  477	 'Packages'	       = '/pldoc/package/',
  478	 'FAQ'                 = '/FAQ/',
  479	 'Command line'        = '/pldoc/man?section=cmdline',
  480	 'PlDoc'               = '/pldoc/package/pldoc.html',
  481	 'Bluffers' =
  482	 [ 'Prolog syntax'     = '/pldoc/man?section=syntax',
  483	   'PceEmacs'          = '/pldoc/man?section=emacsbluff',
  484	   'HTML generation'   = '/pldoc/man?section=htmlwrite'
  485	 ],
  486	 'License'             = '/license.html',
  487	 'Publications'        = '/Publications.html',
  488	 'Rev 7 Extensions'    = '/pldoc/man?section=extensions'
  489       ],
  490       'Tutorials' =
  491       [ 'Beginner' =
  492	 [ 'Getting started'   = '/pldoc/man?section=quickstart',
  493	   'Learn Prolog Now!' = 'http://lpn.swi-prolog.org/',
  494	   'Simply Logical'    = 'http://book.simply-logical.space/',
  495	   'Debugger'          = '/pldoc/man?section=debugoverview',
  496	   'Development tools' = '/IDE.html'
  497	 ],
  498	 'Advanced' =
  499	 [ 'Modules'           = 'http://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/tutorials/swiplmodtut.html',
  500	   'Grammars (DCGs)'   = 'http://www.pathwayslms.com/swipltuts/dcg/',
  501	   'clp(fd)'	       = 'http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html',
  502	   'Printing messages' = 'http://www.pathwayslms.com/swipltuts/message/index.html',
  503	   'PlDoc'             = 'http://chiselapp.com/user/ttmrichter/repository/swipldoctut/doc/tip/doc/tutorial.html'
  504	 ],
  505	 'Web applications' =
  506	 [ 'Web applications'  = 'http://www.pathwayslms.com/swipltuts/html/index.html',
  507	   'Let\'s Encrypt!'   = 'https://github.com/triska/letswicrypt',
  508	   'Pengines'	       = '/pengines/'
  509	 ],
  510	 'Semantic web' =
  511	 [ 'ClioPatria'	       = 'https://cliopatria.swi-prolog.org/tutorial/',
  512	   'RDF namespaces'    = '/howto/UseRdfMeta.html'
  513	 ],
  514	 'Graphics' =
  515	 [ 'XPCE'              = '/download/xpce/doc/coursenotes/coursenotes.pdf',
  516	   'GUI options'       = '/Graphics.html'
  517	 ],
  518	 'Machine learning' =
  519	 [ 'Probabilistic Logic Programming' =
  520			         'http://cplint.ml.unife.it/'
  521	 ],
  522	 'External collections' =
  523	 [ 'Meta level tutorials' = 'https://www.metalevel.at/prolog'
  524	 ],
  525	 'For packagers' =
  526	 [ 'Linux packages'    = '/build/guidelines.html'
  527	 ]
  528       ],
  529       'Community' =           '/community.html' +
  530       [ 'IRC'                 = 'http://webchat.freenode.net/?channels=##prolog',
  531	 'Forum & mailing list'= 'https://swi-prolog.discourse.group',
  532	 'News'                = '/news/archive',
  533	 'Report a bug'	       = '/bug.html',
  534	 'Submit a patch'      = '/howto/SubmitPatch.html',
  535	 'Submit an add-on'    = '/howto/Pack.html',
  536	 'Roadmap (on GitHub)' = 'https://github.com/SWI-Prolog/roadmap',
  537	 'External links'      = '/Links.html',
  538	 'Contributing'        = '/contributing.html',
  539	 'Code of Conduct'     = '/Code-of-Conduct.html',
  540	 'Contributors'        = '/Contributors.html',
  541	 'SWI-Prolog items'    = '/loot.html'
  542       ],
  543       'Users' =
  544       [ 'Semantic web'        = '/web/index.html',
  545	 'Students'            = '/students/index.html',
  546	 'Researchers'         = '/research/index.html',
  547	 'Commercial users'    = '/commercial/index.html',
  548	 'Dog food'            = '/dogfood.html',
  549	 'Is SWIPL right for me?' = '/pldoc/man?section=swiorother'
  550       ],
  551       'Wiki' =
  552       [ LoginLabel            = LoginURL,
  553	 'Edit this page'      = EditHREF,
  554	 'View changes'	       = '/wiki/changes',
  555	 'Sandbox'             = '/wiki/sandbox',
  556	 'Wiki help'           = '/wiki/',
  557	 'All tags'            = '/list-tags'
  558       ]
  559     ]) :-
  560	http_current_request(Request),
  561	memberchk(request_uri(ReqURL), Request),
  562	(   functor(Style, wiki, _)
  563	->  http_link_to_id(wiki_edit,
  564			    [location(ReqURL)], EditHREF)
  565	;   EditHREF = (-)
  566	),
  567	(   site_user_logged_in(_)
  568	->  LoginLabel = 'Logout',
  569	    http_link_to_id(logout, ['openid.return_to'(ReqURL)], LoginURL)
  570	;   LoginLabel = 'Login',
  571	    (	http_link_to_id(logout, [], ReqURL)
  572	    ->	RetURL = '/'		% HOME
  573	    ;	RetURL = ReqURL
  574	    ),
  575	    http_link_to_id(plweb_login_page,
  576			    ['openid.return_to'(RetURL)], LoginURL)
  577	).
 blurb//
Emit the blurb
  583blurb -->
  584	html({|html||
  585    <div id="blurb">
  586      <div>
  587	 SWI-Prolog offers a comprehensive free Prolog environment.
  588	 Since its start in 1987, SWI-Prolog development has been driven
  589	 by the needs of real world applications. SWI-Prolog is widely
  590	 used in research and education as well as commercial applications.
  591	 Join over a million users who have downloaded SWI-Prolog.
  592	 <a href="/features.html">more ...</a>
  593      </div>
  594    </div>
  595	     |}).
 cta_area//
Emit the Call To Action - the 3 big buttons on homepage
  601cta_area -->
  602	html({|html(_)||
  603    <table id='cta-container'>
  604      <tr>
  605        <td style="text-align:left">
  606	      <a href="Download.html">Download SWI-Prolog</a>
  607        <td style="text-align:center">
  608	      <a href="pldoc/man?section=quickstart">Get Started</a>
  609        <td style="text-align:right">
  610	      <a href="http://swish.swi-prolog.org">Try SWI-Prolog online</a>
  611      </tr>
  612    </table>|}).
 enhanced_search_area//
Emit the large size search area at bottom of home page
  619enhanced_search_area -->
  620	{ http_link_to_id(plweb_search, [], Action) },
  621	html({|html(Action)||
  622	      <div id='enhanced-search-container'>
  623	        <div>
  624	          <span class='lbl'>SEARCH DOCUMENTATION:</span>
  625	          <form  id="search-form-enhanced" action="Action">
  626	            <input name="for" type='text' id="forenhanced">
  627	            <input type="image" src="/icons/go.png" alt='Search'>
  628	          </form>
  629	        </div>
  630	      </div>|}),
  631	searchbox_script(forenhanced)