Chris@0
|
1 /* $Id$
|
Chris@0
|
2
|
Chris@0
|
3 Part of SWI-Prolog
|
Chris@0
|
4
|
Chris@0
|
5 Author: Jan Wielemaker
|
Chris@0
|
6 E-mail: wielemak@science.uva.nl
|
Chris@0
|
7 WWW: http://www.swi-prolog.org
|
Chris@0
|
8 Copyright (C): 1985-2007, University of Amsterdam
|
Chris@0
|
9
|
Chris@0
|
10 This program is free software; you can redistribute it and/or
|
Chris@0
|
11 modify it under the terms of the GNU General Public License
|
Chris@0
|
12 as published by the Free Software Foundation; either version 2
|
Chris@0
|
13 of the License, or (at your option) any later version.
|
Chris@0
|
14
|
Chris@0
|
15 This program is distributed in the hope that it will be useful,
|
Chris@0
|
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@0
|
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@0
|
18 GNU General Public License for more details.
|
Chris@0
|
19
|
Chris@0
|
20 You should have received a copy of the GNU Lesser General Public
|
Chris@0
|
21 License along with this library; if not, write to the Free Software
|
Chris@0
|
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Chris@0
|
23
|
Chris@0
|
24 As a special exception, if you link this library with other files,
|
Chris@0
|
25 compiled with a Free Software compiler, to produce an executable, this
|
Chris@0
|
26 library does not by itself cause the resulting executable to be covered
|
Chris@0
|
27 by the GNU General Public License. This exception does not however
|
Chris@0
|
28 invalidate any other reasons why the executable file might be covered by
|
Chris@0
|
29 the GNU General Public License.
|
Chris@0
|
30 */
|
Chris@0
|
31
|
Chris@0
|
32 :- module(http_user, []).
|
Chris@0
|
33
|
Chris@0
|
34 :- use_module(server).
|
Chris@0
|
35 :- use_module(xml_result).
|
Chris@0
|
36 :- use_module(library('http/http_open')).
|
Chris@0
|
37 :- use_module(library('http/thread_httpd')).
|
Chris@0
|
38 :- use_module(library('http/html_write')).
|
Chris@0
|
39 :- use_module(library('http/mimetype')).
|
Chris@0
|
40 :- use_module(library('http/http_dispatch')).
|
Chris@0
|
41 :- use_module(library('http/http_session')).
|
Chris@0
|
42 :- use_module(http_data).
|
Chris@0
|
43 :- use_module(library(settings)).
|
Chris@0
|
44 :- use_module(user_db).
|
Chris@0
|
45 :- use_module(library(debug)).
|
Chris@0
|
46 :- use_module(http_admin).
|
Chris@0
|
47 :- use_module(library('semweb/rdf_db')).
|
Chris@0
|
48 :- use_module(library(url)).
|
Chris@0
|
49
|
Chris@0
|
50 :- http_handler('/', home, []).
|
Chris@0
|
51 :- http_handler('/sidebar.html', sidebar, []).
|
Chris@0
|
52 :- http_handler('/welcome.html', welcome, []).
|
Chris@0
|
53 :- http_handler('/user/statistics', statistics, []).
|
Chris@0
|
54 :- http_handler('/user/construct', construct_form, []).
|
Chris@0
|
55 :- http_handler('/user/query', query_form, []).
|
Chris@0
|
56 :- http_handler('/user/select', select_form, []).
|
Chris@0
|
57 :- http_handler('/user/loadFile', load_file_form, []).
|
Chris@0
|
58 :- http_handler('/user/loadURL', load_url_form, []).
|
Chris@0
|
59 :- http_handler('/user/loadBaseOntology', load_base_ontology_form, []).
|
Chris@0
|
60 :- http_handler('/user/clearRepository', clear_repository_form, []).
|
Chris@0
|
61 :- http_handler('/user/removeStatements', remove_statements_form, []).
|
Chris@0
|
62
|
Chris@0
|
63 :- http_handler('/documentation.html',
|
Chris@0
|
64 http_reply_file(serql('serql.html'), []), []).
|
Chris@0
|
65 :- http_handler('/rdfql.css',
|
Chris@0
|
66 http_reply_file(serql('rdfql.css'), []), []).
|
Chris@0
|
67
|
Chris@0
|
68
|
Chris@0
|
69 %% home(+Request)
|
Chris@0
|
70 %
|
Chris@0
|
71 % Print the home page.
|
Chris@0
|
72 %
|
Chris@0
|
73 % NOTE: a frameset must _not_ have a body!
|
Chris@0
|
74
|
Chris@0
|
75 home(_Request) :-
|
Chris@0
|
76 ( setting(serql_parms:title, Title)
|
Chris@0
|
77 -> true
|
Chris@0
|
78 ; Title = 'SWI-Prolog Semantic Web Server'
|
Chris@0
|
79 ),
|
Chris@0
|
80 phrase(html([ head(title(Title)),
|
Chris@0
|
81 frameset([cols('200,*')],
|
Chris@0
|
82 [ frame([ src('sidebar.html'),
|
Chris@0
|
83 name(sidebar)
|
Chris@0
|
84 ]),
|
Chris@0
|
85 frame([ src('welcome.html'),
|
Chris@0
|
86 name(main)
|
Chris@0
|
87 ])
|
Chris@0
|
88 ])
|
Chris@0
|
89 ]), HTML),
|
Chris@0
|
90 format('Content-type: text/html~n~n'),
|
Chris@0
|
91 print_html(HTML).
|
Chris@0
|
92
|
Chris@0
|
93 %% sidebar(+Request)
|
Chris@0
|
94 %
|
Chris@0
|
95 % HTTP handler to emit the left bar menu (frame content).
|
Chris@0
|
96
|
Chris@0
|
97 sidebar(_Request) :-
|
Chris@0
|
98 findall(Path-Label, action(Path, Label), Actions),
|
Chris@0
|
99 reply_page('Sidebar',
|
Chris@0
|
100 [ \current_user,
|
Chris@0
|
101 hr([]),
|
Chris@0
|
102 \action('welcome.html', 'Home'),
|
Chris@0
|
103 \cond_action(login),
|
Chris@0
|
104 \cond_action(logout),
|
Chris@0
|
105 \cond_action(change_password),
|
Chris@0
|
106 hr([])
|
Chris@0
|
107 | \actions(Actions)
|
Chris@0
|
108 ]).
|
Chris@0
|
109
|
Chris@0
|
110 :- multifile
|
Chris@0
|
111 serql_http:sidebar_menu/2.
|
Chris@0
|
112
|
Chris@0
|
113 action('user/query', 'Query database').
|
Chris@0
|
114 action(-,-).
|
Chris@0
|
115 action('user/loadFile', 'Upload a file').
|
Chris@0
|
116 action('user/loadURL', 'Load from HTTP').
|
Chris@0
|
117 action('user/loadBaseOntology', 'Load base ontology').
|
Chris@0
|
118 action(-,-).
|
Chris@0
|
119 action('user/removeStatements', 'Remove statements').
|
Chris@0
|
120 action('user/clearRepository', 'Clear the repository').
|
Chris@0
|
121 action(-,-).
|
Chris@0
|
122 action('user/statistics', 'Statistics').
|
Chris@0
|
123 action('admin/listUsers', 'Users ...').
|
Chris@0
|
124 action('admin/settings', 'Settings ...').
|
Chris@0
|
125 action('documentation.html', 'Documentation').
|
Chris@0
|
126 action(Path, Label) :-
|
Chris@0
|
127 serql_http:sidebar_menu(Path, Label).
|
Chris@0
|
128
|
Chris@0
|
129
|
Chris@0
|
130 current_user -->
|
Chris@0
|
131 { catch(logged_on(User), _, fail),
|
Chris@0
|
132 ( user_property(User, realname(RealName))
|
Chris@0
|
133 -> true
|
Chris@0
|
134 ; RealName = User
|
Chris@0
|
135 ),
|
Chris@0
|
136 user_property(User, url(URL))
|
Chris@0
|
137 }, !,
|
Chris@0
|
138 html(center(i(a([target(main), href(URL)], RealName)))).
|
Chris@0
|
139 current_user -->
|
Chris@0
|
140 html(center(font(color(red), i('<not logged in>')))).
|
Chris@0
|
141
|
Chris@0
|
142 cond_action(login) -->
|
Chris@0
|
143 ( { catch(logged_on(_User), _, fail)
|
Chris@0
|
144 }
|
Chris@0
|
145 -> []
|
Chris@0
|
146 ; action('user/form/login', 'Login')
|
Chris@0
|
147 ).
|
Chris@0
|
148 cond_action(logout) -->
|
Chris@0
|
149 ( { catch(logged_on(_User), _, fail)
|
Chris@0
|
150 }
|
Chris@0
|
151 -> action('user/logout', 'Logout')
|
Chris@0
|
152 ; []
|
Chris@0
|
153 ).
|
Chris@0
|
154 cond_action(change_password) -->
|
Chris@0
|
155 ( { catch(logged_on(_User), _, fail)
|
Chris@0
|
156 }
|
Chris@0
|
157 -> action('admin/form/changePassword', 'Change password')
|
Chris@0
|
158 ; []
|
Chris@0
|
159 ).
|
Chris@0
|
160
|
Chris@0
|
161 %% welcome(+Request)
|
Chris@0
|
162 %
|
Chris@0
|
163 % Reply with the normal welcome page. If there is no user we
|
Chris@0
|
164 % reply with the `create admin user' page.
|
Chris@0
|
165
|
Chris@0
|
166 welcome(Request) :-
|
Chris@0
|
167 ( current_user(_)
|
Chris@0
|
168 -> http_reply_file(serql('welcome.html'), [cache(false)], Request)
|
Chris@0
|
169 ; throw(http_reply(moved_temporary('admin/form/createAdmin')))
|
Chris@0
|
170 ).
|
Chris@0
|
171
|
Chris@0
|
172
|
Chris@0
|
173 /*******************************
|
Chris@0
|
174 * STATISTICS *
|
Chris@0
|
175 *******************************/
|
Chris@0
|
176
|
Chris@0
|
177 %% statistics(+Request)
|
Chris@0
|
178 %
|
Chris@0
|
179 % Provide elementary statistics on the server.
|
Chris@0
|
180
|
Chris@0
|
181 statistics(_Request) :-
|
Chris@0
|
182 findall(File-Triples,
|
Chris@0
|
183 rdf_statistics(triples_by_file(File, Triples)),
|
Chris@0
|
184 UnsortedPairs),
|
Chris@0
|
185 findall(Index-Count,
|
Chris@0
|
186 rdf_statistics(lookup(Index, Count)),
|
Chris@0
|
187 Lookup),
|
Chris@0
|
188 rdf_statistics(triples(Total)),
|
Chris@0
|
189 rdf_statistics(core(Core)),
|
Chris@0
|
190 sort(UnsortedPairs, Pairs),
|
Chris@0
|
191 reply_page('RDF statistics',
|
Chris@0
|
192 [ h1([id(stattitle)], 'RDF statistics'),
|
Chris@0
|
193 ol([id(toc)],
|
Chris@0
|
194 [
|
Chris@0
|
195 li(a([href('#ntriples')],'Triples in database')),
|
Chris@0
|
196 li(a([href('#callstats')],'Call statistics')),
|
Chris@0
|
197 li(a([href('#sessions')],'Active sessions')),
|
Chris@0
|
198 li(a([href('#serverstats')],'Server statistics'))
|
Chris@0
|
199 ]),
|
Chris@0
|
200 h4([id(ntriples)], 'Triples in database'),
|
Chris@0
|
201 p('The RDF store contains ~D triples in ~D bytes memory'-[Total, Core]),
|
Chris@0
|
202 table([ id(filesourcetable),
|
Chris@0
|
203 border(1),
|
Chris@0
|
204 cellpadding(2)
|
Chris@0
|
205 ],
|
Chris@0
|
206 [ tr([ th('Source'), th(colspan(2), 'Triples') ])
|
Chris@0
|
207 | \triples_by_file(Pairs, Total)
|
Chris@0
|
208 ]),
|
Chris@0
|
209 h4([id(callstats)],'Call statistics'),
|
Chris@0
|
210 table([ border(1),
|
Chris@0
|
211 cellpadding(2)
|
Chris@0
|
212 ],
|
Chris@0
|
213 [ tr([ th(colspan(3), 'Indexed'),
|
Chris@0
|
214 th('Calls')
|
Chris@0
|
215 ]),
|
Chris@0
|
216 \lookup_statistics(Lookup)
|
Chris@0
|
217 ]),
|
Chris@0
|
218 \current_sessions,
|
Chris@0
|
219 \server_statistics
|
Chris@0
|
220 ]).
|
Chris@0
|
221
|
Chris@0
|
222 triples_by_file([], Total) -->
|
Chris@0
|
223 html(tr([ th([align(right), id(total)], 'Total:'),
|
Chris@0
|
224 \nc('~D', Total)
|
Chris@0
|
225 ])).
|
Chris@0
|
226 triples_by_file([File-Triples|T], Total) -->
|
Chris@0
|
227 html(tr([ td(align(right), a(href(File), File)),
|
Chris@0
|
228 \nc('~D', Triples),
|
Chris@0
|
229 td(\unload_button(File))
|
Chris@0
|
230 ])),
|
Chris@0
|
231 triples_by_file(T, Total).
|
Chris@0
|
232
|
Chris@0
|
233
|
Chris@0
|
234 unload_button(File) -->
|
Chris@0
|
235 { www_form_encode(File, Encoded),
|
Chris@0
|
236 atom_concat('../servlets/unloadSource?\
|
Chris@0
|
237 resultFormat=html&\
|
Chris@0
|
238 source=', Encoded, URL)
|
Chris@0
|
239 },
|
Chris@0
|
240 html(a(href(URL), 'Unload')).
|
Chris@0
|
241
|
Chris@0
|
242
|
Chris@0
|
243 lookup_statistics([]) -->
|
Chris@0
|
244 [].
|
Chris@0
|
245 lookup_statistics([rdf(S,P,O)-Count|T]) -->
|
Chris@0
|
246 html(tr([ td(S), td(P), td(O), \nc('~D', Count)])),
|
Chris@0
|
247 lookup_statistics(T).
|
Chris@0
|
248
|
Chris@0
|
249 % current_sessions//0
|
Chris@0
|
250 %
|
Chris@0
|
251 % Create a table of currently logged on users.
|
Chris@0
|
252
|
Chris@0
|
253 current_sessions -->
|
Chris@0
|
254 { findall(S, session(S), Sessions0),
|
Chris@0
|
255 sort(Sessions0, Sessions),
|
Chris@0
|
256 Sessions \== [], !
|
Chris@0
|
257 },
|
Chris@0
|
258 html([ h4([id(sessions)], 'Active sessions'),
|
Chris@0
|
259 table([ id(sessiontable),
|
Chris@0
|
260 border(1),
|
Chris@0
|
261 cellpadding(2)
|
Chris@0
|
262 ],
|
Chris@0
|
263 [ %caption('Active sessions'),
|
Chris@0
|
264 tr([th('User'), th('Real Name'), th('On since'), th('Idle'), th('From')])
|
Chris@0
|
265 | \sessions(Sessions)
|
Chris@0
|
266 ])
|
Chris@0
|
267 ]).
|
Chris@0
|
268 current_sessions -->
|
Chris@0
|
269 html(p('No users logged in')).
|
Chris@0
|
270
|
Chris@0
|
271 session(s(Idle, User, SessionID, Peer)) :-
|
Chris@0
|
272 http_current_session(SessionID, peer(Peer)),
|
Chris@0
|
273 http_current_session(SessionID, idle(Idle)),
|
Chris@0
|
274 ( user_property(User, session(SessionID))
|
Chris@0
|
275 -> true
|
Chris@0
|
276 ; User = (-)
|
Chris@0
|
277 ).
|
Chris@0
|
278
|
Chris@0
|
279 sessions([]) --> [].
|
Chris@0
|
280 sessions([H|T]) --> session(H), sessions(T).
|
Chris@0
|
281
|
Chris@0
|
282 session(s(Idle, -, _SessionID, Peer)) -->
|
Chris@0
|
283 html(tr([td(-), td(-), td(-), td(\idle(Idle)), td(\ip(Peer))])).
|
Chris@0
|
284 session(s(Idle, User, _SessionID, Peer)) -->
|
Chris@0
|
285 { ( user_property(User, realname(RealName))
|
Chris@0
|
286 -> true
|
Chris@0
|
287 ; RealName = '?'
|
Chris@0
|
288 ),
|
Chris@0
|
289 ( user_property(User, connection(OnSince, _Idle))
|
Chris@0
|
290 -> true
|
Chris@0
|
291 ; OnSince = 0
|
Chris@0
|
292 )
|
Chris@0
|
293 },
|
Chris@0
|
294 html(tr([td(User), td(RealName), td(\date(OnSince)), td(\idle(Idle)), td(\ip(Peer))])).
|
Chris@0
|
295
|
Chris@0
|
296 idle(Time) -->
|
Chris@0
|
297 { Secs is round(Time),
|
Chris@0
|
298 Min is Secs // 60,
|
Chris@0
|
299 Sec is Secs mod 60
|
Chris@0
|
300 },
|
Chris@0
|
301 html('~`0t~d~2|:~`0t~d~5|'-[Min, Sec]).
|
Chris@0
|
302
|
Chris@0
|
303 date(Date) -->
|
Chris@0
|
304 { format_time(string(S), '%+', Date)
|
Chris@0
|
305 },
|
Chris@0
|
306 html(S).
|
Chris@0
|
307
|
Chris@0
|
308 ip(ip(A,B,C,D)) --> !,
|
Chris@0
|
309 html('~d.~d.~d.~d'-[A,B,C,D]).
|
Chris@0
|
310 ip(IP) -->
|
Chris@0
|
311 html('~w'-[IP]).
|
Chris@0
|
312
|
Chris@0
|
313
|
Chris@0
|
314 % server_statistics//0
|
Chris@0
|
315 %
|
Chris@0
|
316 % Provide statistics on the HTTP server
|
Chris@0
|
317
|
Chris@0
|
318 server_statistics -->
|
Chris@0
|
319 { serql_server_property(port(Port)),
|
Chris@0
|
320 serql_server_property(started(StartTime)),
|
Chris@0
|
321 format_time(string(ST), '%+', StartTime),
|
Chris@0
|
322 http_workers(Port, NWorkers),
|
Chris@0
|
323 findall(ID, http_current_worker(Port, ID), Workers),
|
Chris@0
|
324 statistics(heapused, Heap)
|
Chris@0
|
325 },
|
Chris@0
|
326 html([ h4([id(serverstats)], 'Server statistics'),
|
Chris@0
|
327 table([ border(1),
|
Chris@0
|
328 cellpadding(2)
|
Chris@0
|
329 ],
|
Chris@0
|
330 [ tr([ th([align(right), colspan(3)], 'Port:'),
|
Chris@0
|
331 td(colspan(3), Port)
|
Chris@0
|
332 ]),
|
Chris@0
|
333 tr([ th([align(right), colspan(3)], 'Started:'),
|
Chris@0
|
334 td(colspan(3), ST)
|
Chris@0
|
335 ]),
|
Chris@0
|
336 tr([ th([align(right), colspan(3)], 'Heap memory:'),
|
Chris@0
|
337 \nc('~D', Heap, [align(left), colspan(3)])
|
Chris@0
|
338 ]),
|
Chris@0
|
339 tr([ th([align(right), colspan(3)], '# worker threads:'),
|
Chris@0
|
340 td(colspan(3), NWorkers)
|
Chris@0
|
341 ]),
|
Chris@0
|
342 tr(th(colspan(6), 'Statistics by worker')),
|
Chris@0
|
343 tr([ th('Thread'),
|
Chris@0
|
344 th('CPU'),
|
Chris@0
|
345 th(''),
|
Chris@0
|
346 th('Local'),
|
Chris@0
|
347 th('Global'),
|
Chris@0
|
348 th('Trail')
|
Chris@0
|
349 ])
|
Chris@0
|
350 | \http_workers(Workers)
|
Chris@0
|
351 ])
|
Chris@0
|
352 ]).
|
Chris@0
|
353
|
Chris@0
|
354 http_workers([]) -->
|
Chris@0
|
355 [].
|
Chris@0
|
356 http_workers([H|T]) -->
|
Chris@0
|
357 { thread_statistics(H, locallimit, LL),
|
Chris@0
|
358 thread_statistics(H, globallimit, GL),
|
Chris@0
|
359 thread_statistics(H, traillimit, TL),
|
Chris@0
|
360 thread_statistics(H, localused, LU),
|
Chris@0
|
361 thread_statistics(H, globalused, GU),
|
Chris@0
|
362 thread_statistics(H, trailused, TU),
|
Chris@0
|
363 thread_statistics(H, cputime, CPU),
|
Chris@0
|
364 sformat(Time, '~2f', [CPU])
|
Chris@0
|
365 },
|
Chris@0
|
366 html([ tr([ td(rowspan(2), H),
|
Chris@0
|
367 td([rowspan(2), align(right)], Time),
|
Chris@0
|
368 th('In use'),
|
Chris@0
|
369 \nc('~D', LU),
|
Chris@0
|
370 \nc('~D', GU),
|
Chris@0
|
371 \nc('~D', TU)
|
Chris@0
|
372 ]),
|
Chris@0
|
373 tr([ th('Limit'),
|
Chris@0
|
374 \nc('~D', LL),
|
Chris@0
|
375 \nc('~D', GL),
|
Chris@0
|
376 \nc('~D', TL)
|
Chris@0
|
377 ])
|
Chris@0
|
378 ]),
|
Chris@0
|
379 http_workers(T).
|
Chris@0
|
380
|
Chris@0
|
381 %% construct_form(+Request)
|
Chris@0
|
382 %
|
Chris@0
|
383 % Provide a page for issuing a =CONSTRUCT= query.
|
Chris@0
|
384
|
Chris@0
|
385 construct_form(_Request) :-
|
Chris@0
|
386 catch(logged_on(User), _, User=anonymous),
|
Chris@0
|
387 reply_page('Specify a query',
|
Chris@0
|
388 [ h1(align(center), 'Interactive SeRQL CONSTRUCT query'),
|
Chris@0
|
389
|
Chris@0
|
390 p(['A ', \serql_doc_link('CONSTRUCT'),
|
Chris@0
|
391 ' generates an RDF graph']),
|
Chris@0
|
392
|
Chris@0
|
393 form([ name(query),
|
Chris@0
|
394 action('../evaluateGraphQuery'),
|
Chris@0
|
395 method('GET')
|
Chris@0
|
396 ],
|
Chris@0
|
397 [ \hidden(repository, default),
|
Chris@0
|
398 table(align(center),
|
Chris@0
|
399 [ \store_recall(User, construct, 3-2),
|
Chris@0
|
400 tr([ td(colspan(6),
|
Chris@0
|
401 textarea([ name(query),
|
Chris@0
|
402 rows(15),
|
Chris@0
|
403 cols(80)
|
Chris@0
|
404 ],
|
Chris@0
|
405 'CONSTRUCT '))
|
Chris@0
|
406 ]),
|
Chris@0
|
407 tr([ td([ \small('QLang: '),
|
Chris@0
|
408 \query_language
|
Chris@0
|
409 ]),
|
Chris@0
|
410 td([ \small('Format: '),
|
Chris@0
|
411 \result_format
|
Chris@0
|
412 ]),
|
Chris@0
|
413 td([ \small('Serial.: '),
|
Chris@0
|
414 \serialization
|
Chris@0
|
415 ]),
|
Chris@0
|
416 td([ \small('Res.: '),
|
Chris@0
|
417 \resource_menu
|
Chris@0
|
418 ]),
|
Chris@0
|
419 td([ \small('Entail.: '),
|
Chris@0
|
420 \entailment
|
Chris@0
|
421 ]),
|
Chris@0
|
422 td(align(right),
|
Chris@0
|
423 [ input([ type(reset),
|
Chris@0
|
424 value('Reset')
|
Chris@0
|
425 ]),
|
Chris@0
|
426 input([ type(submit),
|
Chris@0
|
427 value('Go!')
|
Chris@0
|
428 ])
|
Chris@0
|
429 ])
|
Chris@0
|
430 ])
|
Chris@0
|
431 ])
|
Chris@0
|
432 ]),
|
Chris@0
|
433 \script
|
Chris@0
|
434 ]).
|
Chris@0
|
435
|
Chris@0
|
436 store_recall(anonymous, _, _) -->
|
Chris@0
|
437 [].
|
Chris@0
|
438 store_recall(User, Type, SL-SR) -->
|
Chris@0
|
439 html(tr([ td(colspan(SL),
|
Chris@0
|
440 [ b('Store as: '),
|
Chris@0
|
441 input([ name(storeAs),
|
Chris@0
|
442 size(40)
|
Chris@0
|
443 ])
|
Chris@0
|
444 ]),
|
Chris@0
|
445 td([ colspan(SR),
|
Chris@0
|
446 align(right)
|
Chris@0
|
447 ],
|
Chris@0
|
448 \recall(User, Type))
|
Chris@0
|
449 ])).
|
Chris@0
|
450
|
Chris@0
|
451
|
Chris@0
|
452 recall(User, Type) -->
|
Chris@0
|
453 { findall(Name-Query, stored_query(Name, User, Type, Query), Pairs),
|
Chris@0
|
454 Pairs \== []
|
Chris@0
|
455 },
|
Chris@0
|
456 html([ b('Recall: '),
|
Chris@0
|
457 select(name(recall),
|
Chris@0
|
458 [ option([selected], '')
|
Chris@0
|
459 | \stored_queries(Pairs, 1)
|
Chris@0
|
460 ])
|
Chris@0
|
461 ]).
|
Chris@0
|
462 recall(_, _) -->
|
Chris@0
|
463 [].
|
Chris@0
|
464
|
Chris@0
|
465 stored_queries([], _) -->
|
Chris@0
|
466 [].
|
Chris@0
|
467 stored_queries([Name-Query|T], I) -->
|
Chris@0
|
468 { I2 is I + 1,
|
Chris@0
|
469 atom_concat(f, I, FName),
|
Chris@0
|
470 js_quoted(Query, QuotedQuery),
|
Chris@0
|
471 sformat(Script,
|
Chris@0
|
472 'function ~w()\n\
|
Chris@0
|
473 { document.query.query.value=\'~w\';\n\
|
Chris@0
|
474 }\n',
|
Chris@0
|
475 [ FName, QuotedQuery ]),
|
Chris@0
|
476 assert(script_fragment(Script)),
|
Chris@0
|
477 sformat(Call, '~w()', [FName])
|
Chris@0
|
478 },
|
Chris@0
|
479 html(option([onClick(Call)], Name)),
|
Chris@0
|
480 stored_queries(T, I2).
|
Chris@0
|
481
|
Chris@0
|
482
|
Chris@0
|
483 :- thread_local
|
Chris@0
|
484 script_fragment/1.
|
Chris@0
|
485
|
Chris@0
|
486 script -->
|
Chris@0
|
487 { findall(S, retract(script_fragment(S)), Fragments),
|
Chris@0
|
488 Fragments \== []
|
Chris@0
|
489 }, !,
|
Chris@0
|
490 [ '\n<script language="JavaScript">\n'
|
Chris@0
|
491 ],
|
Chris@0
|
492 Fragments,
|
Chris@0
|
493 [ '\n</script>\n'
|
Chris@0
|
494 ].
|
Chris@0
|
495 script -->
|
Chris@0
|
496 [].
|
Chris@0
|
497
|
Chris@0
|
498 %% js_quoted(+Raw, -Quoted)
|
Chris@0
|
499 %
|
Chris@0
|
500 % Quote text for use in JavaScript. Quoted does _not_ include the
|
Chris@0
|
501 % leading and trailing quotes.
|
Chris@0
|
502
|
Chris@0
|
503 js_quoted(Raw, Quoted) :-
|
Chris@0
|
504 atom_codes(Raw, Codes),
|
Chris@0
|
505 phrase(js_quote_codes(Codes), QuotedCodes),
|
Chris@0
|
506 atom_codes(Quoted, QuotedCodes).
|
Chris@0
|
507
|
Chris@0
|
508 js_quote_codes([]) -->
|
Chris@0
|
509 [].
|
Chris@0
|
510 js_quote_codes([0'\r,0'\n|T]) --> !,
|
Chris@0
|
511 "\\n",
|
Chris@0
|
512 js_quote_codes(T).
|
Chris@0
|
513 js_quote_codes([H|T]) -->
|
Chris@0
|
514 js_quote_code(H),
|
Chris@0
|
515 js_quote_codes(T).
|
Chris@0
|
516
|
Chris@0
|
517 js_quote_code(0'') --> !,
|
Chris@0
|
518 "\\'".
|
Chris@0
|
519 js_quote_code(0'\\) --> !,
|
Chris@0
|
520 "\\\\".
|
Chris@0
|
521 js_quote_code(0'\n) --> !,
|
Chris@0
|
522 "\\n".
|
Chris@0
|
523 js_quote_code(0'\r) --> !,
|
Chris@0
|
524 "\\r".
|
Chris@0
|
525 js_quote_code(0'\t) --> !,
|
Chris@0
|
526 "\\t".
|
Chris@0
|
527 js_quote_code(C) -->
|
Chris@0
|
528 [C].
|
Chris@0
|
529
|
Chris@0
|
530 %% query_form(+Request)
|
Chris@0
|
531 %
|
Chris@0
|
532 % Provide a page for issuing a =SELECT= query.
|
Chris@0
|
533
|
Chris@0
|
534 query_form(_Request) :-
|
Chris@0
|
535 catch(logged_on(User), _, User=anonymous),
|
Chris@0
|
536 reply_page('Specify a query',
|
Chris@0
|
537 [ form([ name(query),
|
Chris@0
|
538 action('../evaluateQuery'),
|
Chris@0
|
539 method('GET')
|
Chris@0
|
540 ],
|
Chris@0
|
541 [ \hidden(repository, default),
|
Chris@0
|
542 \hidden(serialization, rdfxml),
|
Chris@0
|
543 h1(align(center),
|
Chris@0
|
544 [ 'Interactive ',
|
Chris@0
|
545 \query_language,
|
Chris@0
|
546 ' query'
|
Chris@0
|
547 ]),
|
Chris@0
|
548 table(align(center),
|
Chris@0
|
549 [ \store_recall(User, select, 3-2),
|
Chris@0
|
550 tr([ td(colspan(5),
|
Chris@0
|
551 textarea([ name(query),
|
Chris@0
|
552 rows(15),
|
Chris@0
|
553 cols(80)
|
Chris@0
|
554 ],
|
Chris@0
|
555 ''))
|
Chris@0
|
556 ]),
|
Chris@0
|
557 tr([ td([ \small('Result format: '),
|
Chris@0
|
558 \result_format
|
Chris@0
|
559 ]),
|
Chris@0
|
560 td([ \small('Resource: '),
|
Chris@0
|
561 \resource_menu
|
Chris@0
|
562 ]),
|
Chris@0
|
563 td([ \small('Entailment: '),
|
Chris@0
|
564 \entailment
|
Chris@0
|
565 ]),
|
Chris@0
|
566 td(align(right),
|
Chris@0
|
567 [ input([ type(reset),
|
Chris@0
|
568 value('Reset')
|
Chris@0
|
569 ]),
|
Chris@0
|
570 input([ type(submit),
|
Chris@0
|
571 value('Go!')
|
Chris@0
|
572 ])
|
Chris@0
|
573 ])
|
Chris@0
|
574 ])
|
Chris@0
|
575 ])
|
Chris@0
|
576 ]),
|
Chris@0
|
577 \script
|
Chris@0
|
578 ]).
|
Chris@0
|
579
|
Chris@0
|
580
|
Chris@0
|
581 %% select_form(+Request)
|
Chris@0
|
582 %
|
Chris@0
|
583 % Provide a page for issuing a =SELECT= query
|
Chris@0
|
584
|
Chris@0
|
585 select_form(_Request) :-
|
Chris@0
|
586 catch(logged_on(User), _, User=anonymous),
|
Chris@0
|
587 reply_page('Specify a query',
|
Chris@0
|
588 [ h1(align(center), 'Interactive SeRQL SELECT query'),
|
Chris@0
|
589
|
Chris@0
|
590 p(['A ', \serql_doc_link('SELECT'),
|
Chris@0
|
591 ' generates a table']),
|
Chris@0
|
592
|
Chris@0
|
593 form([ name(query),
|
Chris@0
|
594 action('../servlets/evaluateTableQuery'),
|
Chris@0
|
595 method('GET')
|
Chris@0
|
596 ],
|
Chris@0
|
597 [ \hidden(repository, default),
|
Chris@0
|
598 \hidden(serialization, rdfxml),
|
Chris@0
|
599 table(align(center),
|
Chris@0
|
600 [ \store_recall(User, select, 3-2),
|
Chris@0
|
601 tr([ td(colspan(6),
|
Chris@0
|
602 textarea([ name(query),
|
Chris@0
|
603 rows(15),
|
Chris@0
|
604 cols(80)
|
Chris@0
|
605 ],
|
Chris@0
|
606 'SELECT '))
|
Chris@0
|
607 ]),
|
Chris@0
|
608 tr([ td([ \small('Result format: '),
|
Chris@0
|
609 \result_format
|
Chris@0
|
610 ]),
|
Chris@0
|
611 td([ \small('Language: '),
|
Chris@0
|
612 \query_language
|
Chris@0
|
613 ]),
|
Chris@0
|
614 td([ \small('Resource: '),
|
Chris@0
|
615 \resource_menu
|
Chris@0
|
616 ]),
|
Chris@0
|
617 td([ \small('Entailment: '),
|
Chris@0
|
618 \entailment
|
Chris@0
|
619 ]),
|
Chris@0
|
620 td(align(right),
|
Chris@0
|
621 [ input([ type(reset),
|
Chris@0
|
622 value('Reset')
|
Chris@0
|
623 ]),
|
Chris@0
|
624 input([ type(submit),
|
Chris@0
|
625 value('Go!')
|
Chris@0
|
626 ])
|
Chris@0
|
627 ])
|
Chris@0
|
628 ])
|
Chris@0
|
629 ])
|
Chris@0
|
630 ]),
|
Chris@0
|
631 \script
|
Chris@0
|
632 ]).
|
Chris@0
|
633
|
Chris@0
|
634
|
Chris@0
|
635 serql_doc_link(Label) -->
|
Chris@0
|
636 { setting(serql_parms:serql_documentation_url, URL)
|
Chris@0
|
637 },
|
Chris@0
|
638 html(a([href(URL)], Label)).
|
Chris@0
|
639
|
Chris@0
|
640 serialization -->
|
Chris@0
|
641 html(select(name(serialization),
|
Chris@0
|
642 [ option([selected], rdfxml),
|
Chris@0
|
643 option([], ntriples),
|
Chris@0
|
644 option([], n3)
|
Chris@0
|
645 ])).
|
Chris@0
|
646
|
Chris@0
|
647 result_format -->
|
Chris@0
|
648 html(select(name(resultFormat),
|
Chris@0
|
649 [ option([], xml),
|
Chris@0
|
650 option([selected], html)/*,
|
Chris@0
|
651 option([], rdf)*/
|
Chris@0
|
652 ])).
|
Chris@0
|
653
|
Chris@0
|
654 query_language -->
|
Chris@0
|
655 html(select(name(queryLanguage),
|
Chris@0
|
656 [ option([selected], 'SeRQL'),
|
Chris@0
|
657 option([], 'SPARQL')
|
Chris@0
|
658 ])).
|
Chris@0
|
659
|
Chris@0
|
660 resource_menu -->
|
Chris@0
|
661 html(select(name(resourceFormat),
|
Chris@0
|
662 [ option([value(plain)], plain),
|
Chris@0
|
663 option([value(ns), selected], 'ns:local'),
|
Chris@0
|
664 option([value(nslabel)], 'ns:label')
|
Chris@0
|
665 ])).
|
Chris@0
|
666
|
Chris@0
|
667 entailment -->
|
Chris@0
|
668 { findall(E, serql:entailment(E, _), Es)
|
Chris@0
|
669 },
|
Chris@0
|
670 html(select(name(entailment),
|
Chris@0
|
671 \entailments(Es))).
|
Chris@0
|
672
|
Chris@0
|
673 entailments([]) -->
|
Chris@0
|
674 [].
|
Chris@0
|
675 entailments([E|T]) -->
|
Chris@0
|
676 ( { setting(serql_parms:default_entailment, E)
|
Chris@0
|
677 }
|
Chris@0
|
678 -> html(option([selected], E))
|
Chris@0
|
679 ; html(option([], E))
|
Chris@0
|
680 ),
|
Chris@0
|
681 entailments(T).
|
Chris@0
|
682
|
Chris@0
|
683 small(Text) -->
|
Chris@0
|
684 html(font(size(-1), Text)).
|
Chris@0
|
685
|
Chris@0
|
686
|
Chris@0
|
687 %% load_file_form(+Request)
|
Chris@0
|
688 %
|
Chris@0
|
689 % Provide a form for uploading triples from a local file.
|
Chris@0
|
690
|
Chris@0
|
691 load_file_form(_Request) :-
|
Chris@0
|
692 reply_page('Upload RDF',
|
Chris@0
|
693 [ h3(align(center), 'Upload an RDF document'),
|
Chris@0
|
694
|
Chris@0
|
695 p(['Upload a document using POST to /servlets/uploadData. \
|
Chris@0
|
696 Alternatively you can use ',
|
Chris@0
|
697 a(href=loadURL,loadURL), ' to load data from a \
|
Chris@0
|
698 web server.'
|
Chris@0
|
699 ]),
|
Chris@0
|
700
|
Chris@0
|
701 form([ action('../servlets/uploadData'),
|
Chris@0
|
702 method('POST'),
|
Chris@0
|
703 enctype('multipart/form-data')
|
Chris@0
|
704 ],
|
Chris@0
|
705 [ \hidden(resultFormat, html),
|
Chris@0
|
706 table([tr([ td(align(right), 'File:'),
|
Chris@0
|
707 td(input([ name(data),
|
Chris@0
|
708 type(file),
|
Chris@0
|
709 size(50)
|
Chris@0
|
710 ]))
|
Chris@0
|
711 ]),
|
Chris@0
|
712 tr([ td(align(right), 'BaseURI:'),
|
Chris@0
|
713 td(input([ name(baseURI),
|
Chris@0
|
714 size(50)
|
Chris@0
|
715 ]))
|
Chris@0
|
716 ]),
|
Chris@0
|
717 tr([ td([align(right), colspan(2)],
|
Chris@0
|
718 input([ type(submit),
|
Chris@0
|
719 value('Upload now')
|
Chris@0
|
720 ]))
|
Chris@0
|
721 ])
|
Chris@0
|
722 ])
|
Chris@0
|
723 ])
|
Chris@0
|
724 ]).
|
Chris@0
|
725
|
Chris@0
|
726
|
Chris@0
|
727 %% load_url_form(+Request)
|
Chris@0
|
728 %
|
Chris@0
|
729 % Provide a form for uploading triples from a URL.
|
Chris@0
|
730
|
Chris@0
|
731 load_url_form(_Request) :-
|
Chris@0
|
732 reply_page('Load RDF from HTTP server',
|
Chris@0
|
733 [ h3(align(center), 'Load RDF from HTTP server'),
|
Chris@0
|
734 form([ action('../servlets/uploadURL'),
|
Chris@0
|
735 method('GET')
|
Chris@0
|
736 ],
|
Chris@0
|
737 [ \hidden(resultFormat, html),
|
Chris@0
|
738 table([tr([ td(align(right), 'URL:'),
|
Chris@0
|
739 td(input([ name(url),
|
Chris@0
|
740 value('http://'),
|
Chris@0
|
741 size(50)
|
Chris@0
|
742 ]))
|
Chris@0
|
743 ]),
|
Chris@0
|
744 tr([ td(align(right), 'BaseURI:'),
|
Chris@0
|
745 td(input([ name(baseURI),
|
Chris@0
|
746 size(50)
|
Chris@0
|
747 ]))
|
Chris@0
|
748 ]),
|
Chris@0
|
749 tr([ td([align(right), colspan(2)],
|
Chris@0
|
750 input([ type(submit),
|
Chris@0
|
751 value('Upload now')
|
Chris@0
|
752 ]))
|
Chris@0
|
753 ])
|
Chris@0
|
754 ])
|
Chris@0
|
755 ])
|
Chris@0
|
756 ]).
|
Chris@0
|
757
|
Chris@0
|
758
|
Chris@0
|
759 %% load_base_ontology_form(+Request)
|
Chris@0
|
760 %
|
Chris@0
|
761 % Provide a form for loading an ontology from the archive.
|
Chris@0
|
762
|
Chris@0
|
763 load_base_ontology_form(_Request) :- !,
|
Chris@0
|
764 authorized(read(status, listBaseOntologies)),
|
Chris@0
|
765 reply_page('Load base ontology',
|
Chris@0
|
766 [ h3(align(center), 'Load ontology from repository'),
|
Chris@0
|
767
|
Chris@0
|
768 p('This page allows loading one of the ontologies \
|
Chris@0
|
769 provided with the toolkit.'),
|
Chris@0
|
770
|
Chris@0
|
771 form([ action('../servlets/loadBaseOntology'),
|
Chris@0
|
772 method('GET')
|
Chris@0
|
773 ],
|
Chris@0
|
774 [ \hidden(resultFormat, html),
|
Chris@0
|
775 b('Ontology'),
|
Chris@0
|
776 select(name(ontology),
|
Chris@0
|
777 [ option([], '')
|
Chris@0
|
778 | \base_ontologies
|
Chris@0
|
779 ]),
|
Chris@0
|
780 input([ type(submit),
|
Chris@0
|
781 value('Load')
|
Chris@0
|
782 ])
|
Chris@0
|
783 ])
|
Chris@0
|
784 ]).
|
Chris@0
|
785
|
Chris@0
|
786
|
Chris@0
|
787 base_ontologies -->
|
Chris@0
|
788 { get_base_ontologies(Rows)
|
Chris@0
|
789 },
|
Chris@0
|
790 base_ontologies(Rows).
|
Chris@0
|
791
|
Chris@0
|
792 get_base_ontologies(List) :-
|
Chris@0
|
793 catch(findall(row(O), serql_base_ontology(O), List), _, fail), !.
|
Chris@0
|
794 get_base_ontologies(Rows) :-
|
Chris@0
|
795 server_url('/servlets/listBaseOntologies?resultFormat=xml', URL),
|
Chris@0
|
796 debug(base_ontologies, 'Opening ~w', [URL]),
|
Chris@0
|
797 http_open(URL, In,
|
Chris@0
|
798 [ % request_header('Cookie', Cookie)
|
Chris@0
|
799 ]),
|
Chris@0
|
800 debug(base_ontologies, '--> Reading from ~w', [In]),
|
Chris@0
|
801 xml_read_result_table(In, Rows, _VarNames).
|
Chris@0
|
802
|
Chris@0
|
803 base_ontologies([]) -->
|
Chris@0
|
804 [].
|
Chris@0
|
805 base_ontologies([row(H)|T]) -->
|
Chris@0
|
806 html(option([], H)),
|
Chris@0
|
807 base_ontologies(T).
|
Chris@0
|
808
|
Chris@0
|
809
|
Chris@0
|
810 %% clear_repository_form(+Request)
|
Chris@0
|
811 %
|
Chris@0
|
812 % HTTP handle presenting a form to clear the repository.
|
Chris@0
|
813
|
Chris@0
|
814 clear_repository_form(_Request) :-
|
Chris@0
|
815 reply_page('Load base ontology',
|
Chris@0
|
816 [ h3(align(center), 'Clear entire repository'),
|
Chris@0
|
817
|
Chris@0
|
818 p(['This operation removes ', b(all), ' triples from \
|
Chris@0
|
819 the RDF store.']),
|
Chris@0
|
820
|
Chris@0
|
821 form([ action('../servlets/clearRepository'),
|
Chris@0
|
822 method('GET')
|
Chris@0
|
823 ],
|
Chris@0
|
824 [ \hidden(repository, default),
|
Chris@0
|
825 \hidden(resultFormat, html),
|
Chris@0
|
826 input([ type(submit),
|
Chris@0
|
827 value('Clear repository now')
|
Chris@0
|
828 ])
|
Chris@0
|
829 ])
|
Chris@0
|
830 ]).
|
Chris@0
|
831
|
Chris@0
|
832
|
Chris@0
|
833 %% remove_statements_form(+Request)
|
Chris@0
|
834 %
|
Chris@0
|
835 % HTTP handler providing a form to remove RDF statements.
|
Chris@0
|
836
|
Chris@0
|
837 remove_statements_form(_Request) :-
|
Chris@0
|
838 reply_page('Load base ontology',
|
Chris@0
|
839 [ h3(align(center), 'Remove statements'),
|
Chris@0
|
840
|
Chris@0
|
841 p('Remove matching triples from the database. The three \
|
Chris@0
|
842 fields are in ntriples notation. Omitted fields \
|
Chris@0
|
843 match any value.'),
|
Chris@0
|
844
|
Chris@0
|
845 form([ action('../servlets/removeStatements'),
|
Chris@0
|
846 method('GET')
|
Chris@0
|
847 ],
|
Chris@0
|
848 [ \hidden(repository, default),
|
Chris@0
|
849 \hidden(resultFormat, html),
|
Chris@0
|
850 table([ tr([ th(align(right), 'Subject: '),
|
Chris@0
|
851 td(input([ name(subject),
|
Chris@0
|
852 size(50)
|
Chris@0
|
853 ]))
|
Chris@0
|
854 ]),
|
Chris@0
|
855 tr([ th(align(right), 'Predicate: '),
|
Chris@0
|
856 td(input([ name(predicate),
|
Chris@0
|
857 size(50)
|
Chris@0
|
858 ]))
|
Chris@0
|
859 ]),
|
Chris@0
|
860 tr([ th(align(right), 'Object: '),
|
Chris@0
|
861 td(input([ name(object),
|
Chris@0
|
862 size(50)
|
Chris@0
|
863 ]))
|
Chris@0
|
864 ]),
|
Chris@0
|
865 tr([ td([ align(right),
|
Chris@0
|
866 colspan(2)
|
Chris@0
|
867 ],
|
Chris@0
|
868 input([ type(submit),
|
Chris@0
|
869 value('Remove')
|
Chris@0
|
870 ]))
|
Chris@0
|
871 ])
|
Chris@0
|
872 ])
|
Chris@0
|
873 ])
|
Chris@0
|
874 ]).
|
Chris@0
|
875
|
Chris@0
|
876
|
Chris@0
|
877 /*******************************
|
Chris@0
|
878 * UTIL *
|
Chris@0
|
879 *******************************/
|
Chris@0
|
880
|
Chris@0
|
881 actions([]) -->
|
Chris@0
|
882 [].
|
Chris@0
|
883 actions([Path-Label|T]) -->
|
Chris@0
|
884 action(Path, Label),
|
Chris@0
|
885 actions(T).
|
Chris@0
|
886
|
Chris@0
|
887 %% action(+URL, +Label)// is det
|
Chris@0
|
888 %
|
Chris@0
|
889 % Add an action to the sidebar. URL is one of
|
Chris@0
|
890 %
|
Chris@0
|
891 % $ =-= :
|
Chris@0
|
892 % Add a horizontal rule (<hr>)
|
Chris@0
|
893 % $ Atom :
|
Chris@0
|
894 % Create a link to the given URL, targetting the main
|
Chris@0
|
895 % window.
|
Chris@0
|
896 % $ HTML DOM :
|
Chris@0
|
897 % Insert given HTML
|
Chris@0
|
898
|
Chris@0
|
899 action(-, -) --> !,
|
Chris@0
|
900 html(hr([])).
|
Chris@0
|
901 action(-, Label) --> !,
|
Chris@0
|
902 html([ hr([]),
|
Chris@0
|
903 center(b(Label)),
|
Chris@0
|
904 hr([])
|
Chris@0
|
905 ]).
|
Chris@0
|
906 action(URL, Label) -->
|
Chris@0
|
907 { atom(URL) }, !,
|
Chris@0
|
908 html([a([target=main, href=URL], Label), br([])]).
|
Chris@0
|
909 action(Action, _) -->
|
Chris@0
|
910 html(Action),
|
Chris@0
|
911 html(br([])).
|
Chris@0
|
912
|
Chris@0
|
913 %% nc(+Format, +Value)// is det.
|
Chris@0
|
914 %
|
Chris@0
|
915 % Numeric cell. The value is formatted using Format and
|
Chris@0
|
916 % right-aligned in a table cell (td).
|
Chris@0
|
917
|
Chris@0
|
918 nc(Fmt, Value) -->
|
Chris@0
|
919 nc(Fmt, Value, []).
|
Chris@0
|
920
|
Chris@0
|
921 nc(Fmt, Value, Options) -->
|
Chris@0
|
922 { sformat(Txt, Fmt, [Value]),
|
Chris@0
|
923 ( memberchk(align(_), Options)
|
Chris@0
|
924 -> Opts = Options
|
Chris@0
|
925 ; Opts = [align(right)|Options]
|
Chris@0
|
926 )
|
Chris@0
|
927 },
|
Chris@0
|
928 html(td(Opts, Txt)).
|
Chris@0
|
929
|
Chris@0
|
930
|
Chris@0
|
931 %% hidden(+Name, +Value)// is det.
|
Chris@0
|
932 %
|
Chris@0
|
933 % Create a hidden input field with given name and value
|
Chris@0
|
934
|
Chris@0
|
935 hidden(Name, Value) -->
|
Chris@0
|
936 html(input([ type(hidden),
|
Chris@0
|
937 name(Name),
|
Chris@0
|
938 value(Value)
|
Chris@0
|
939 ])).
|
Chris@0
|
940
|
Chris@0
|
941
|
Chris@0
|
942 server_url(Local, URL) :-
|
Chris@0
|
943 setting(http:server_url, Base),
|
Chris@0
|
944 atom_concat(Base, Local, URL).
|
Chris@0
|
945
|
Chris@0
|
946
|
Chris@0
|
947 /*******************************
|
Chris@0
|
948 * EMIT *
|
Chris@0
|
949 *******************************/
|
Chris@0
|
950
|
Chris@0
|
951 reply_page(Title, Content) :-
|
Chris@0
|
952 phrase(page(title(Title), Content), HTML),
|
Chris@0
|
953 format('Content-type: text/html~n~n'),
|
Chris@0
|
954 print_html(HTML).
|
Chris@0
|
955
|
Chris@0
|
956
|
Chris@0
|
957 /*******************************
|
Chris@0
|
958 * PCEEMACS SUPPORT *
|
Chris@0
|
959 *******************************/
|
Chris@0
|
960
|
Chris@0
|
961 :- multifile
|
Chris@0
|
962 emacs_prolog_colours:goal_colours/2,
|
Chris@0
|
963 prolog:called_by/2.
|
Chris@0
|
964
|
Chris@0
|
965
|
Chris@0
|
966 emacs_prolog_colours:goal_colours(reply_page(_, HTML),
|
Chris@0
|
967 built_in-[classify, Colours]) :-
|
Chris@0
|
968 catch(html_write:html_colours(HTML, Colours), _, fail).
|
Chris@0
|
969
|
Chris@0
|
970 prolog:called_by(reply_page(_, HTML), Called) :-
|
Chris@0
|
971 catch(phrase(html_write:called_by(HTML), Called), _, fail).
|