View source with formatted comments or as raw
    1/*  Part of ClioPatria SeRQL and SPARQL server
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2010-2018, University of Amsterdam,
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(cp_menu,
   37          [ cp_menu//0
   38          ]).   39:- use_module(library(http/html_write)).   40:- use_module(library(http/html_head)).   41:- use_module(library(http/http_dispatch)).   42:- use_module(library(pairs)).   43:- use_module(library(apply)).   44:- use_module(library(uri)).   45:- use_module(library(ctypes)).   46:- use_module(user(user_db)).   47:- use_module(cliopatria(hooks)).   48
   49/** <module> ClioPatria menu-bar
   50
   51This  module  provides  the   ClioPatria    application   menu-bar.  The
   52application menu is attached by cliopatria(skin)  to all HTML pages that
   53match the style cliopatria(_) (see reply_html_page/3).
   54
   55@see    The menu is built using CSS from
   56        http://denilsonsa.selfip.org/~denilson/menu/menu.html
   57*/
   58
   59%!  cp_menu//
   60%
   61%   HTML Components that emits the ClioPatria   menu.  The menu is a
   62%   standard nested HTML =ul= list, turned   into  a horizontal menu
   63%   using CSS. The menu can be   extended and controlled using three
   64%   hooks in the module =cliopatria=:
   65%
   66%       * cliopatria:menu_item/2 defines the menu-items present
   67%       * cliopatria:menu_label/2 assigns non-standard labels
   68%       * cliopatria:menu_popup_order/2 defines the order of the popups
   69
   70cp_menu -->
   71    { findall(Key-Item, current_menu_item(Key, Item), Pairs0),
   72      sort(Pairs0, Pairs),
   73      group_pairs_by_key(Pairs, ByKey),
   74      sort_menu_popups(ByKey, Menu)
   75    },
   76    html_requires(css('menu.css')),
   77    html(ul(id(nav),
   78            \menu(Menu))).
   79
   80menu([]) --> !.
   81menu([_-[Item]|T]) -->
   82    !,
   83    menu_item(Item),
   84    menu(T).
   85menu([Key-Items|T]) -->
   86    { menu_label(Key, Key, Label) },
   87    html(li([ a([Label]),
   88              ul(\menu_items(Items))
   89            ])),
   90    menu(T).
   91
   92menu_items([]) --> [].
   93menu_items([H|T]) --> menu_item(H), menu_items(T).
   94
   95menu_item(item(_Rank, Spec, Label, Options)) -->
   96    { atom(Spec) },
   97    !,
   98    { (   \+ sub_atom(Spec, 0, _, _, 'http://'),
   99          catch(http_location_by_id(Spec, Location), E,
  100                (   print_message(informational, E),
  101                    fail))
  102      ->  true
  103      ;   Location = Spec
  104      )
  105    },
  106    html(li(a([href(Location)|Options], Label))).
  107
  108
  109%!  current_menu_item(-PopupKey, -Item) is nondet.
  110%
  111%   Enumerate the menu-items.
  112%
  113%   @param PopupKey is the id  of  a   popup.  The  label thereof is
  114%   computed by menu_label/3 and the ordering by menu_popup_order/2.
  115%   @param Item is a term item(Rank, Location, Label).
  116
  117current_menu_item(Key, item(Rank, Location, Label, Options)) :-
  118    menu_item(Spec, DefLabel),
  119    rank(Spec, Rank, Where, Options),
  120    (   Where = Key/Location
  121    ->  menu_label(Location, DefLabel, Label)
  122    ;   Where = Location,
  123        Key = Location,
  124        menu_label(Location, DefLabel, Label)
  125    ).
  126
  127rank(Rank=Spec, Rank, Where, Options) :-
  128    !,
  129    item_options(Spec, Where, Options).
  130rank(Spec,      0,    Where, Options) :-
  131    item_options(Spec, Where, Options).
  132
  133item_options(Spec+Option, Where, [Option|T]) :-
  134    !,
  135    item_options(Spec, Where, T).
  136item_options(Where, Where, []).
  137
  138
  139%!  menu_item(Item, ?Label) is nondet.
  140%
  141%   Define a menu-item for  the   ClioPatria  application menu. This
  142%   predicate is hooked by cliopatria:menu_item/2.
  143%
  144%   @param Item is of the form Rank=Popup/Handler, where Handler is
  145%   the identifier of the HTTP handler (see http_handler/3).
  146%
  147%   @param Label is the label of the popup.
  148
  149menu_item(Item, Label) :-
  150    cliopatria:menu_item(Item, Label).
  151
  152menu_item(100=repository/load_file_form,                'Load local file').
  153menu_item(200=repository/load_url_form,                 'Load from HTTP').
  154menu_item(300=repository/load_library_rdf_form,         'Load from library').
  155menu_item(400=repository/remove_statements_form,        'Remove triples').
  156menu_item(500=repository/clear_repository_form,         'Clear repository').
  157
  158menu_item(100=query/yasgui_editor,                      'YASGUI SPARQL Editor').
  159menu_item(200=query/query_form,                         'Simple Form').
  160
  161menu_item(100=places/home,                              'Home').
  162menu_item(200=places/list_graphs,                       'Graphs').
  163menu_item(200=places/list_prefixes,                     'Prefixes').
  164
  165menu_item(100=admin/list_users,                         'Users').
  166menu_item(200=admin/settings,                           'Settings').
  167menu_item(300=admin/statistics,                         'Statistics').
  168
  169menu_item(100=user/login_form+class(login),             'Login') :-
  170    \+ someone_logged_on.
  171menu_item(100=current_user/user_logout,                 'Logout') :-
  172    someone_logged_on.
  173menu_item(200=current_user/change_password_form,        'Change password') :-
  174    local_user_logged_on.
  175menu_item(300=current_user/my_openid_page,              'My OpenID page') :-
  176    open_id_user(_).
  177
  178sort_menu_popups(List, Sorted) :-
  179    map_list_to_pairs(popup_order, List, Keyed),
  180    keysort(Keyed, KeySorted),
  181    pairs_values(KeySorted, Sorted).
  182
  183popup_order(Key-Members, Order-(Key-Members)) :-
  184    (   menu_popup_order(Key, Order)
  185    ->  true
  186    ;   Order = 550                 % between application and help
  187    ).
  188
  189%!  menu_popup_order(+Item, -Location)
  190%
  191%   Provide numeric locations for the   popup-items.  This predicate
  192%   can be hooked by cliopatria:menu_popup_order/2.
  193
  194menu_popup_order(Popup, Order) :-
  195    cliopatria:menu_popup_order(Popup, Order),
  196    !.
  197menu_popup_order(places,       100).
  198menu_popup_order(admin,        200).
  199menu_popup_order(repository,   300).
  200menu_popup_order(query,        400).
  201menu_popup_order(application,  500).
  202menu_popup_order(help,         600).
  203menu_popup_order(user,         700).
  204menu_popup_order(current_user, 800).
  205
  206%!  menu_label(+Id, +Default, -Label) is det.
  207
  208menu_label(Item, _Default, Label) :-
  209    cliopatria:menu_label(Item, Label),
  210    !.
  211menu_label(current_user, _Default, Label) :-
  212    logged_on(User, X),
  213    X \== User,
  214    !,
  215    (   user_property(User, realname(RealName))
  216    ->  true
  217    ;   RealName = 'My account'
  218    ),
  219    (   user_property(User, url(URL))
  220    ->  Label = a(href(URL), i(RealName))
  221    ;   Label = i(RealName)
  222    ).
  223menu_label(_, Default, Label) :-
  224    id_to_label(Default, Label).
  225
  226%!  id_to_label(+HandlerID, -Label) is det.
  227%
  228%   Computes a default label  from   the  HandlerID. Underscores are
  229%   mapped to spaces and the first character is capitalised.
  230
  231id_to_label(Atom, Capital) :-
  232    atom_codes(Atom, Codes0),
  233    maplist(underscore_to_space, Codes0, Codes),
  234    (   maplist(is_upper, Codes)
  235    ->  Capital = Atom
  236    ;   Codes = [First|Rest]
  237    ->  code_type(First, to_lower(Up)),
  238        UpCodes = [Up|Rest],
  239        atom_codes(Capital, UpCodes)
  240    ;   Capital = Atom
  241    ).
  242
  243underscore_to_space(0'_, 32) :- !.
  244underscore_to_space(X, X).
  245
  246%!  local_user_logged_on is semidet.
  247%
  248%   True if the currently logged on user is a local user (as opposed
  249%   to an OpenID accredited logon).
  250
  251local_user_logged_on :-
  252    logged_on(User, X),
  253    X \== User,
  254    \+ ( uri_components(User, Components),
  255         uri_data(scheme, Components, Scheme),
  256         nonvar(Scheme)
  257       ).
  258
  259%!  someone_logged_on is semidet.
  260%
  261%   True if some user is logged on.
  262
  263someone_logged_on :-
  264    logged_on(User, X),
  265    X \== User.
  266
  267                 /*******************************
  268                 *            OpenID            *
  269                 *******************************/
  270
  271:- http_handler(root(my_openid_page), my_openid_page, []).  272
  273my_openid_page(Request) :-
  274    open_id_user(User),
  275    http_redirect(see_other, User, Request).
  276
  277open_id_user(User) :-
  278    logged_on(User, X),
  279    X \== User,
  280    uri_components(User, Components),
  281    uri_data(scheme, Components, Scheme),
  282    nonvar(Scheme)