Commit 4485b6b0c90bce520852b6c9426ba99cea38088e

Authored by totoro
1 parent fc5a84fc

add List(CoreAttrs) in anonymous aggregation of Webargvalue to allow better formatting of seletor

Showing 2 changed files with 5564 additions and 5558 deletions   Show diff stats
web/CXM_dojo.anubis
1 -/*  
2 - * Created by PyramIDE.  
3 - * User: Steve Marechal  
4 - * Date: 11/06/2008  
5 - * Time: 09:54  
6 - *  
7 - */  
8 -  
9 -read tools/basis.anubis  
10 -read tools/base64.anubis  
11 -read locale/L3LanguageInfo.anubis  
12 -read system/string.anubis  
13 -read system/logger.anubis  
14 -  
15 -read calexium_lib/web/CXM_common.anubis  
16 -read calexium_lib/web/CXM_making_a_web_site.anubis  
17 -read calexium_lib/web/CXM_multihost_http_server.anubis  
18 -read calexium_lib/net_services_protocols/logger_service.anubis  
19 -  
20 -public type Dojo_Grid_Data :  
21 - grid_data(String).  
22 -  
23 -public type Position_Direction:  
24 - brup,  
25 - brleft,  
26 - blup,  
27 - blright,  
28 - trdown,  
29 - trleft,  
30 - tldown,  
31 - tlright.  
32 -  
33 -define String  
34 - pos_dir_to_str  
35 - (  
36 - Position_Direction pos  
37 - )=  
38 - if pos is  
39 - {  
40 - brup then "br-up",  
41 - brleft then "br-left",  
42 - blup then "bl-up",  
43 - blright then "bl-right",  
44 - trdown then "tr-down",  
45 - trleft then "tr-left",  
46 - tldown then "tl-down",  
47 - tlright then "tl-right"  
48 - }.  
49 -  
50 -  
51 -  
52 -public define HTML_Off_Form  
53 - dojo_button  
54 - (  
55 - String name,  
56 - String execute,  
57 - String id,  
58 - )  
59 - =  
60 - literal("  
61 - <button dojoType=\"dijit.form.Button\" id=\""+id+"\" onclick=\""+execute+"\">"+name+"</button>")  
62 -.  
63 -  
64 -public type Input_Type:  
65 - file,  
66 - text,  
67 - password.  
68 -  
69 -public type InputDial:  
70 - input_dial(HtmlId id, Input_Type input_type, String label, Maybe(String) class),  
71 - input_date(HtmlId id, String label),  
72 - input_combo(HtmlId id, String label, List((WebArgValue,String)) list_data),  
73 - input_check(HtmlId id, String label, Bool checked),  
74 - input_hidden(HtmlId id, WebArgValue value).  
75 -  
76 -  
77 -define List(HTML_Off_Form)  
78 - format_list_data  
79 - (  
80 - List((WebArgValue,String)) list_data,  
81 - List(HTML_Off_Form) result_list  
82 - )=  
83 - if list_data is  
84 - {  
85 - [] then result_list,  
86 - [h . t] then  
87 - if h is (wa, label) then  
88 - format_list_data(t, [literal("<option value=\"" + wa.value + "\">" + label + "</option>") . result_list])  
89 - }.  
90 -  
91 -public define HTML_Off_Form  
92 - dojo_combobox  
93 - (  
94 - WebArgName the_name,  
95 - HtmlId the_id,  
96 - String label,  
97 - List((WebArgValue,String)) list_data,  
98 - )=  
99 - sequence([  
100 - literal("<label for=\"" + the_id.id + "\">" + label + "</label>  
101 - <select id=\""+the_id.id+"\"  
102 - name=\"" + the_name.name + "\"  
103 - dojoType=\"dijit.form.ComboBox\"  
104 - autoComplete=\"false\">"),  
105 - sequence((format_list_data(list_data, []))),  
106 - literal("</select>")  
107 - ]).  
108 -  
109 -define HTML_Off_Form  
110 - _maybe_label  
111 - (  
112 - String label_text,  
113 - HtmlId html_id  
114 - ) =  
115 - if length(label_text) > 0 then literal("<label for=\"" + html_id.id + "\">" + label_text + "</label>")  
116 - else literal("").  
117 -  
118 -public define HTML_Off_Form  
119 - dojo_checkbox  
120 - (  
121 - WebArgName the_name,  
122 - HtmlId the_id,  
123 - String label,  
124 - WebArgValue val,  
125 - Bool checked,  
126 - )=  
127 - sequence([  
128 - _maybe_label(label, the_id),  
129 - literal("<input type=\"checkbox\" name=\"" + the_name.name + "\" id=\"" + the_id.id + "\" value=\"" + val.value + "\""  
130 - + (if checked then " checked=\"checked\" " else "") + " dojoType=\"dijit.form.CheckBox\" />"),  
131 - ]).  
132 -  
133 -  
134 -define HTML_Off_Form  
135 - input_in_dialog  
136 - (  
137 - InputDial input_data  
138 - )=  
139 - if input_data is  
140 - {  
141 - input_dial(html_id, input, label, class) then  
142 - sequence([  
143 - literal("<div id=\"" + html_id.id +"_block\"" +  
144 - if class is  
145 - {  
146 - failure then " class=\"dojo_diag\"",  
147 - success(class_name) then " class=\"dojo_diag block_"+ class_name +"\""  
148 - }+"><label for=\"" + html_id.id + "\" id=\"label_" + html_id.id + "\"" +  
149 - if class is  
150 - {  
151 - failure then "",  
152 - success(class_name) then " class=\"label_" + class_name + "\""  
153 - }+">" + label + "</label>"),  
154 - literal("<input dojoType=dijit.form.TextBox " +  
155 - if input is  
156 - {  
157 - file then "type=\"file\"",  
158 - text then "type=\"text\"",  
159 - password then "type=\"password\""  
160 - } +  
161 - " name=\""+html_id.id+"\" id=\""+html_id.id+"\" /></div>")  
162 - ]),  
163 -  
164 - input_date(html_id, label) then  
165 - sequence([  
166 - literal("<div id=\"" + html_id.id +"_block\" class=\"dojo_diag\" ><label for=\"" + html_id.id + "\"> " + label + "</label>"),  
167 - literal("<div id=\""+html_id.id+"\" type=\"text\" name=\"date1\"  
168 - dojoType=\"dijit.form.DateTextBox\">  
169 - </div></div>"  
170 - )  
171 - ]),  
172 -  
173 - input_combo(the_id, label, list_data) then  
174 - sequence([  
175 - literal("<div id=\"" + the_id.id +"_block\" class=\"dojo_diag\">"),  
176 - dojo_combobox(wan(the_id.id), the_id, label, list_data),  
177 - literal("</div>")  
178 - ]),  
179 -  
180 - input_check(the_id, label, checked) then  
181 - sequence([  
182 - literal("<div id=\"" + the_id.id +"_block\" class=\"dojo_diag\">"),  
183 - dojo_checkbox(wan(the_id.id), the_id, label, wav("1"), checked),  
184 - literal("</div>"),  
185 - ]),  
186 -  
187 - input_hidden(the_id, val) then  
188 - literal("<input type=\"hidden\" id=\"" + the_id.id +"\" name=\"" + the_id.id +"\" value=\"" + val.value + "\" class=\"dojo_diag\" />"),  
189 - }  
190 -.  
191 -  
192 -define List(HTML_Off_Form)  
193 - inputs_in_dialog  
194 - (  
195 - List(InputDial) inputs_data  
196 - )=  
197 - if inputs_data is  
198 - {  
199 - [] then [],  
200 - [h . t] then [input_in_dialog(h) . inputs_in_dialog(t)]  
201 - }.  
202 -  
203 -public define HTML_Off_Form  
204 - dijit_dialog  
205 - (  
206 - String name,  
207 - String dialog_id,  
208 - String execute,  
209 - String ok_label,  
210 - Maybe(String) cancel,  
211 - List(InputDial) inputs_data,  
212 - Maybe(String) do_cancel  
213 - )  
214 - =  
215 - sequence([  
216 - div([attr("dojoType", "dijit.Dialog"), id(dialog_id), title(name), attr("execute", execute)],  
217 - sequence([  
218 - sequence(inputs_in_dialog(inputs_data)),  
219 - literal("<button dojoType=dijit.form.Button type=\"submit\" class=\"dialog_ok\">" + ok_label + "</button>" +  
220 - if cancel is  
221 - {  
222 - failure then "",  
223 - success(cancel_label) then "<button dojoType=dijit.form.Button type=\"cancel\" class=\"dialog_cancel\" onclick=\"" +  
224 - if do_cancel is  
225 - {  
226 - failure then "dijit.byId('"+ dialog_id +"').hide()",  
227 - success(to_do_cancel) then to_do_cancel  
228 - }+ "\">" + cancel_label + "</button>"  
229 - }),  
230 - literal("<br/>")  
231 - ])  
232 - )  
233 - ])  
234 -.  
235 -  
236 -public define HTML_Off_Form  
237 - dojo_dialog  
238 - (  
239 - String name,  
240 - String dialog_id,  
241 - String execute,  
242 - String ok_label,  
243 - Maybe(String) cancel,  
244 - List(InputDial) inputs_data,  
245 - Maybe(String) do_cancel  
246 - )  
247 - =  
248 - sequence[  
249 - dojo_button(name,"dijit.byId('"+dialog_id+"').show()", dialog_id + "_button"),  
250 - dijit_dialog(name, dialog_id, execute, ok_label, cancel, inputs_data, do_cancel)  
251 - ]  
252 -.  
253 -  
254 -  
255 -  
256 -  
257 -public type DojoGridEditor:  
258 - inputEditor,  
259 - boolEditor,  
260 - selectEditor(List(String) options),  
261 - alwaysOnEditor.  
262 -  
263 -public type DojoGridDefaultColumn:  
264 - dojo_grid_default_column(  
265 - String styles,  
266 - Maybe(String) width,  
267 - Maybe(DojoGridEditor) editor).  
268 -  
269 -public type DojoGridColumn:  
270 - dojo_grid_column( String label,  
271 - String field_name,  
272 - Maybe(String) width,  
273 - Maybe(DojoGridEditor) editor).  
274 -  
275 -public type DojoGridView:  
276 - dojo_grid_view(  
277 - Maybe(DojoGridDefaultColumn) default_column,  
278 - List(DojoGridColumn) columns).  
279 -  
280 -public type DojoGridLayout:  
281 - dojo_grid_layout(  
282 - Maybe(String) selectable_row_header_width,  
283 - List(DojoGridView) views).  
284 -  
285 -define String to_String(DojoGridEditor editor) =  
286 - "editor: " +  
287 - if editor is  
288 - {  
289 - inputEditor then "dojox.grid.editors.Input",  
290 - boolEditor then "dojox.grid.editors.Bool",  
291 - selectEditor(options) then "dojox.grid.editors.Select, options: [" + join(",", map((String o) |-> "\"" + o + "\"", options)) + "]",  
292 - alwaysOnEditor then "dojox.grid.editors.AlwaysOn"  
293 - }.  
294 -  
295 -define String to_String(DojoGridView view) =  
296 - "{ " + (if view.default_column is success(col) then  
297 - (if col is dojo_grid_default_column(styles, mb_width, mb_editor) then  
298 - "defaultCell: {"  
299 - + "styles: \"" + styles + "\""  
300 - + (if mb_width is success(w) then ", width=\"" + w + "\"" else "")  
301 - + (if mb_editor is success(e) then ", " + to_String(e) else "")  
302 - + "}, ")  
303 - else "")  
304 - + "cells: [[" + join(",", map((DojoGridColumn col) |->  
305 - if col is dojo_grid_column(label, field, mb_width, mb_editor) then  
306 - "{"  
307 - + "name: \"" + label + "\""  
308 - + "field: \"" + field + "\""  
309 - + (if mb_width is success(w) then ", width=\"" + w + "\"" else "")  
310 - + (if mb_editor is success(e) then ", " + to_String(e) else "")  
311 - + "}",  
312 - view.columns)) + "]]"  
313 - +"}".  
314 -  
315 -  
316 -public define String  
317 - dojo_make_grid_script  
318 - (  
319 - HtmlId html_id,  
320 - DojoGridLayout layout,  
321 - String layout_name,  
322 - String store_name,  
323 - Bool can_edit  
324 - )  
325 - =  
326 -"<script type=\"text/javascript\">  
327 - " + layout_name + " = ["  
328 - + (if layout.selectable_row_header_width is success(w) then "{ type: 'dojox.GridRowView', width: '" + w + "'}, " else "")  
329 - + join(", ", map(to_String, layout.views))  
330 - + "];  
331 -</script>".  
332 -  
333 -public define HTML_Off_Form  
334 - dojo_make_grid_script  
335 - (  
336 - HtmlId html_id,  
337 - List(String) columns,  
338 - Bool can_edit  
339 - )  
340 - =  
341 - literal(  
342 -"<script type=\"text/javascript\">  
343 - var cols = ["+join(",", map((String col) |-> "\"" + col + "\"", columns)) + "];  
344 - dojo.addOnLoad(function(){  
345 - init_dojo_grid(\""+html_id.id+"\", cols, "+ (if can_edit then "1" else "0")+");  
346 - });  
347 -</script>").  
348 -  
349 -public define HTML_Off_Form  
350 - dojo_grid  
351 - (  
352 - HtmlId html_id,  
353 - Int rowsPerPage,  
354 - List(Table_Option) attributes,  
355 - )=  
356 - table([attr("dojoType", "dojox.grid.DataGrid"), attr("id", html_id.id), attr("jsId", html_id.id),  
357 - class("soria"), attr("singleClickEdit", "true"), attr("rowsPerPage", to_decimal(rowsPerPage)) . attributes],  
358 - empty, [], empty).  
359 -  
360 -  
361 -public define HTML_Off_Form  
362 - dojo_grid  
363 - (  
364 - HtmlId html_id,  
365 - List(CoreAttrs) attributes,  
366 -// List(GridColumn) columns,  
367 - String colum1,  
368 - String colum2,  
369 - String colum3,  
370 - String colum4,  
371 - Bool can_edit  
372 - )  
373 - =  
374 - sequence([  
375 - literal(  
376 -  
377 -"<script type=\"text/javascript\">  
378 - dojo.addOnLoad(function(){  
379 - init_dojo_grid(\""+html_id.id+"\", \""+colum1+"\",\""+colum2+"\", \""+colum3+"\", \""+colum4+"\", "+ (if can_edit then "1" else "0")+");  
380 - });  
381 -</script>"),  
382 - div_empty([id(html_id.id) . attributes /*attr("dojoType", "dojox.Grid"), */]),  
383 - ]).  
384 -//<div id=\"gridContainer\"></div>").  
385 -  
386 -  
387 -public define HTML_Off_Form  
388 - dojo_message_box  
389 - (  
390 - HTML_Off_Form name1,  
391 - HTML_Off_Form name2,  
392 - )  
393 - =  
394 - sequence([  
395 - literal("<br/>"),  
396 - div([class("message_box")],  
397 - sequence([  
398 - div([id("node3"), class("box nopad hidden")], name1),  
399 - div([id("node4"), class("box two nopad")], name2),  
400 - ])),  
401 - literal("<br/>"),  
402 - ]).  
403 -  
404 -  
405 -  
406 -public define HTML_Off_Form  
407 - dojo_tooltip  
408 - (  
409 - String title,  
410 - String keyword,  
411 - ) =  
412 - actioner(same,same, link([id("dojo_tip_" + keyword),class("dojoToolTip")],title, success(title)), "show_address_mailing", [("address_mailing", keyword)], []).  
413 - //actioner(same, same, push_button([id("dojo_tip_" + keyword), class("in"), event(onclick,"new_search(this)")], keyword), "", [], []).  
414 -  
415 -  
416 -public type BorderContainerRegion:  
417 - center,  
418 - top,  
419 - bottom,  
420 - leading,  
421 - trailing,  
422 - left,  
423 - right.  
424 -  
425 -define String  
426 - to_String  
427 - (  
428 - BorderContainerRegion region  
429 - )=  
430 - if region is  
431 - {  
432 - center then "center",  
433 - top then "top",  
434 - bottom then "bottom",  
435 - leading then "leading",  
436 - trailing then "trailing",  
437 - left then "left",  
438 - right then "right"  
439 - }.  
440 -  
441 -public type BorderContainerDesign:  
442 - headline,  
443 - sidebar.  
444 -  
445 -define String  
446 - to_String  
447 - (  
448 - BorderContainerDesign design  
449 - )=  
450 - if design is  
451 - {  
452 - headline then "headline",  
453 - sidebar then "sidebar"  
454 - }.  
455 -  
456 -  
457 -public define HTML_Off_Form  
458 - dojo_ContentPane  
459 - (  
460 - List(CoreAttrs) attributes,  
461 - BorderContainerRegion region,  
462 - Bool splitter,  
463 - HTML_Off_Form content  
464 - ) =  
465 - div([ attr("dojoType", "dijit.layout.ContentPane"),  
466 - attr("region", to_String(region)),  
467 - attr("splitter", if splitter then "true" else "false") . attributes ],  
468 - content).  
469 -  
470 -public define HTML_In_Form  
471 - dojo_ContentPane  
472 - (  
473 - List(CoreAttrs) attributes,  
474 - BorderContainerRegion region,  
475 - Bool splitter,  
476 - HTML_In_Form content  
477 - ) =  
478 - div([ attr("dojoType", "dijit.layout.ContentPane"),  
479 - attr("region", to_String(region)),  
480 - attr("splitter", if splitter then "true" else "false") . attributes ],  
481 - content).  
482 -  
483 -public define HTML_Off_Form  
484 - dojo_TabContainer  
485 - (  
486 - List(CoreAttrs) attributes,  
487 - HTML_Off_Form content  
488 - ) =  
489 - div([attr("dojoType", "dijit.layout.TabContainer") . attributes ],  
490 - content).  
491 -  
492 -  
493 -public define HTML_Off_Form  
494 - dojo_BorderContainer  
495 - (  
496 - List(CoreAttrs) attributes,  
497 - Maybe(String) the_title,  
498 - BorderContainerDesign design,  
499 - Bool live_splitter,  
500 - Bool persist,  
501 - Bool closable,  
502 - String container,  
503 - HTML_Off_Form content  
504 - ) =  
505 - with the_attributes = (List(CoreAttrs)) [attr("dojoType", "dijit.layout.BorderContainer"), attr("dojoAttachPoint", container),  
506 - attr("design", to_String(design)), attr("liveSplitters", live_splitter), attr("persist", persist),  
507 - attr("closable",closable) . attributes ],  
508 - total_attributes = if the_title is  
509 - {  
510 - failure then the_attributes,  
511 - success(t) then [title(t) . the_attributes]  
512 - },  
513 - div(total_attributes, content).  
514 -  
515 -public define HTML_In_Form  
516 - dojo_BorderContainer  
517 - (  
518 - List(CoreAttrs) attributes,  
519 - Maybe(String) the_title,  
520 - BorderContainerDesign design,  
521 - Bool live_splitter,  
522 - Bool persist,  
523 - Bool closable,  
524 - String container,  
525 - HTML_In_Form content  
526 - ) =  
527 - with the_attributes = (List(CoreAttrs)) [attr("dojoType", "dijit.layout.BorderContainer"), attr("dojoAttachPoint", container),  
528 - attr("design", to_String(design)), attr("liveSplitters", live_splitter), attr("persist", persist),  
529 - attr("closable",closable) . attributes ],  
530 - total_attributes = if the_title is  
531 - {  
532 - failure then the_attributes,  
533 - success(t) then [title(t) . the_attributes]  
534 - },  
535 - div(total_attributes, content).  
536 -  
537 -public define HTML_Off_Form  
538 - dojo_tree  
539 - (  
540 - List(CoreAttrs) attributes,  
541 - )=  
542 - div_empty(attributes).  
543 -  
544 -  
545 -  
546 -public define HTML_Off_Form  
547 - dojo_Toolbar  
548 - (  
549 - List(CoreAttrs) attributes,  
550 - HTML_Off_Form content  
551 - )=  
552 - div([attr("dojoType", "dijit.Toolbar") . attributes ],  
553 - content).  
554 -  
555 -  
556 -public define HTML_Off_Form  
557 - dojo_tooltip  
558 - (  
559 - List(CoreAttrs) attributes,  
560 - List(Text_Option) txt_attr,  
561 - HtmlId html_id,  
562 - String label,  
563 - HTML_Off_Form tooltip_content,  
564 - )=  
565 - sequence([  
566 - text([id(html_id.id) . txt_attr], label),  
567 - div([id(html_id.id + "_tt"), attr("connectId", html_id.id), attr("dojoType", "dijit.Tooltip") . attributes], tooltip_content)  
568 - ]).  
569 -  
570 -  
571 -public define HTML_Off_Form  
572 - dojo_button  
573 - (  
574 - HtmlId html_id,  
575 -// Maybe(String) class,  
576 - String name,  
577 - String iconclass,  
578 - Maybe(String) tip_msg,  
579 - String execute,  
580 - )=  
581 - literal("  
582 - <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" >"  
583 - + name  
584 - + "<script type=\"dojo/method\" event=\"onClick\">"  
585 - + execute  
586 - + "</script>"  
587 - + "</button>" +  
588 - if tip_msg is  
589 - {  
590 - failure then "",  
591 - success(tip) then  
592 - "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"  
593 - }).  
594 -  
595 -public define HTML_In_Form  
596 - dojo_button  
597 - (  
598 - HtmlId html_id,  
599 -// Maybe(String) class,  
600 - String name,  
601 - String iconclass,  
602 - Maybe(String) tip_msg,  
603 - String execute,  
604 - )=  
605 - literal("  
606 - <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" >"  
607 - + name  
608 - + "<script type=\"dojo/method\" event=\"onClick\">"  
609 - + execute  
610 - + "</script>"  
611 - + "</button>" +  
612 - if tip_msg is  
613 - {  
614 - failure then "",  
615 - success(tip) then  
616 - "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"  
617 - }).  
618 -  
619 -  
620 -public define HTML_Off_Form  
621 - dojo_declaration  
622 - (  
623 - String name,  
624 - List(CoreAttrs) attributes,  
625 - HTML_Off_Form content  
626 - )=  
627 - div([attr("dojoType", "dijit.Declaration"), attr("widgetClass", name) . attributes ],  
628 - content).  
629 -  
630 -  
631 -public define HTML_In_Form  
632 - dojo_declaration  
633 - (  
634 - String name,  
635 - List(CoreAttrs) attributes,  
636 - HTML_In_Form content  
637 - )=  
638 - div([attr("dojoType", "dijit.Declaration"), attr("widgetClass", name) . attributes ],  
639 - content).  
640 -  
641 -public define HTML_Off_Form  
642 - dojo_editor  
643 - (  
644 - List(CoreAttrs) attributes,  
645 - HtmlId html_id,  
646 - WebArgName input_name,  
647 - HTML_Off_Form text,  
648 - )=  
649 - div([id(html_id.id), attr("name", input_name.name), attr("dojoType", "dijit.Editor")  
650 - ,attr("extraPlugins", "['|', 'foreColor','hiliteColor',{name:'dojox.editor.plugins.FontChoice', command:'fontName', generic:true},'fontSize','formatBlock','|','createLink','insertImage']")  
651 - . attributes], text).  
652 -  
653 - public define HTML_In_Form  
654 - dojo_button  
655 - (  
656 - HtmlId html_id,  
657 - String name,  
658 - String iconclass,  
659 - Maybe(String) tip_msg,  
660 - String execute,  
661 - )=  
662 - literal("<input id=\"realSubmitButton"+ html_id.id + "\" type=\"submit\" style=\"display:none\">  
663 - <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" onclick=\"dojo.byId('realSubmitButton" + html_id.id + "').click();" + execute + "\">" + name + "</button>" +  
664 - if tip_msg is  
665 - {  
666 - failure then "",  
667 - success(tip) then  
668 - "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"  
669 - }).  
670 -  
671 -public define HTML_In_Form  
672 - dojo_checkbox  
673 - (  
674 - List(InputAttrs) attributes,  
675 - WebArgName name,  
676 - HtmlId id,  
677 - String label,  
678 - WebArgValue val,  
679 - Bool checked,  
680 - )=  
681 - check_box_r([attr("dojoType", "dijit.form.CheckBox") . attributes] , label, id, name, val, checked).  
682 -  
683 -public define HTML_In_Form  
684 - dojo_combobox  
685 - (  
686 - List(InputAttrs) attributes,  
687 - WebArgName name,  
688 - HtmlId id,  
689 - String label,  
690 - List((WebArgValue,String)) list_data,  
691 - InitialValue selected,  
692 - )=  
693 - // selector_c([attr("dojoType", "dijit.form.ComboBox") . attributes], label, id, name, 1, list_data, selected, non_mandatory).  
694 - selector_c(attributes, label, id, name, 1, list_data, selected).  
695 -  
696 -public define HTML_Off_Form  
697 - dojo_toaster  
698 - (  
699 - List(CoreAttrs) attributes,  
700 - HtmlId html_id,  
701 - String message_topic,  
702 - Position_Direction position_direction,  
703 - Bool separator,  
704 - Maybe(Int) duration  
705 - )=  
706 - div(append(append(if separator then [attr("separator","&lt;hr&gt;")]  
707 - else [],  
708 - if duration is  
709 - {  
710 - failure then [],  
711 - success(dur) then [attr("duration", abs_to_decimal(dur))]  
712 - }),  
713 - [attr("dojoType", "dojox.widget.Toaster"), attr("messageTopic", message_topic),  
714 - attr("positionDirection", pos_dir_to_str(position_direction)), id(html_id.id)  
715 - . attributes ]),  
716 - literal("")).  
717 -  
718 -public define HTML_Off_Form  
719 - dojo_progressBar  
720 - (  
721 - List(CoreAttrs) attributes,  
722 - List(Text_Option) attributes_text,  
723 - HtmlId html_id,  
724 - String label  
725 - )=  
726 - sequence([  
727 - text([id("text_" + html_id.id), class("progress_bar") . attributes_text], label),  
728 - div([id(html_id.id), class("progress_bar"), attr("indeterminate", "true"), attr("dojoType", "dijit.ProgressBar") . attributes], literal(""))  
729 - ]).  
730 -  
731 -public define HTML_Off_Form  
732 - dojo_progressBar  
733 - (  
734 - List(CoreAttrs) attributes,  
735 - List(Text_Option) attributes_text,  
736 - HtmlId html_id,  
737 - String label,  
738 - Int progress,  
739 - Int maximum  
740 - )=  
741 - sequence([  
742 - text([id("text_" + html_id.id), class("progress_bar") . attributes_text], label),  
743 - div([id(html_id.id),  
744 - class("progress_bar"),  
745 - attr("maximum", abs_to_decimal(maximum)),  
746 - attr("progress", abs_to_decimal(progress)),  
747 - attr("dojoType", "dijit.ProgressBar") . attributes], literal(""))  
748 - ]).  
749 -  
750 -define Maybe(Int)  
751 - string_to_month  
752 - (  
753 - String month_s  
754 - )=  
755 - with month = to_lower(month_s),  
756 - if month = "jan" then success(1)  
757 - else if month = "feb" then success(2)  
758 - else if month = "mar" then success(3)  
759 - else if month = "apr" then success(4)  
760 - else if month = "may" then success(5)  
761 - else if month = "jun" then success(6)  
762 - else if month = "jul" then success(7)  
763 - else if month = "aug" then success(8)  
764 - else if month = "sep" then success(9)  
765 - else if month = "oct" then success(10)  
766 - else if month = "nov" then success(11)  
767 - else if month = "dec" then success(12)  
768 - else failure  
769 - .  
770 -  
771 -  
772 -// 'Thu Jan 14 2010 00:00:00 GMT+0100' must be replaced by '2010-01-14 00:00:00'  
773 -  
774 -  
775 -  
776 -public define Maybe(String)  
777 - dojo_date_to_db_datetime  
778 - (  
779 - String data  
780 - )=  
781 - with list_data = split_by_token(data, ' '),  
782 - if nth(2, list_data) is  
783 - {  
784 - failure then failure,  
785 - success(day) then  
786 - if nth(1, list_data) is  
787 - {  
788 - failure then failure,  
789 - success(month) then  
790 - if nth(3, list_data) is  
791 - {  
792 - failure then failure,  
793 - success(year) then  
794 - if nth(4, list_data) is  
795 - {  
796 - failure then failure,  
797 - success(hour) then  
798 - if string_to_month(month) is  
799 - {  
800 - failure then failure,  
801 - success(month_int) then  
802 - success(year+"-"+month_int+"-"+day+" "+hour)  
803 - }  
804 - }  
805 - }  
806 - }  
807 - }.  
808 -  
809 -public define List(HTML_Head_Tag)  
810 - dojo_defaults  
811 - =  
812 - [  
813 - // js(js_file("js/dojo/dojo.js", [attr("djConfig", "parseOnLoad: true, isDebug: " + (if debug_mode then "true" else "false") + ", usePlainJson: true")])),  
814 - js(js_file("js/dojo/dojo/dojo.js", [attr("djConfig", "parseOnLoad: true, isDebug: false, usePlainJson: true")])),  
815 - js(js_file("js/dojo/dijit/dijit.js")),  
816 - css(css_file("js/dojo/dojo/resources/dojo.css"))  
817 - ].  
818 -  
819 -  
820 -public define List(HTML_Head_Tag)  
821 - dojo_init  
822 - (  
823 - String web_dir,  
824 - String theme_name  
825 - )  
826 - =  
827 - with theme_name =  
828 - if file_exists(web_dir+"/public/js/dojo/dijit/themes/"+theme_name+"/"+theme_name+".css")then theme_name else "claro",  
829 - [ css(css_file("js/dojo/dijit/themes/"+theme_name+"/"+theme_name+".css")) .  
830 - [ css(css_file("js/dojo/dijit/themes/"+theme_name+"/"+theme_name+"_rtl.css")) . dojo_defaults ]  
831 - ]  
832 - . 1 +/*
  2 + * Created by PyramIDE.
  3 + * User: Steve Marechal
  4 + * Date: 11/06/2008
  5 + * Time: 09:54
  6 + *
  7 + */
  8 +
  9 +read tools/basis.anubis
  10 +read tools/base64.anubis
  11 +read locale/L3LanguageInfo.anubis
  12 +read system/string.anubis
  13 +read system/logger.anubis
  14 +
  15 +read calexium_lib/web/CXM_common.anubis
  16 +read calexium_lib/web/CXM_making_a_web_site.anubis
  17 +read calexium_lib/web/CXM_multihost_http_server.anubis
  18 +read calexium_lib/net_services_protocols/logger_service.anubis
  19 +
  20 +public type Dojo_Grid_Data :
  21 + grid_data(String).
  22 +
  23 +public type Position_Direction:
  24 + brup,
  25 + brleft,
  26 + blup,
  27 + blright,
  28 + trdown,
  29 + trleft,
  30 + tldown,
  31 + tlright.
  32 +
  33 +define String
  34 + pos_dir_to_str
  35 + (
  36 + Position_Direction pos
  37 + )=
  38 + if pos is
  39 + {
  40 + brup then "br-up",
  41 + brleft then "br-left",
  42 + blup then "bl-up",
  43 + blright then "bl-right",
  44 + trdown then "tr-down",
  45 + trleft then "tr-left",
  46 + tldown then "tl-down",
  47 + tlright then "tl-right"
  48 + }.
  49 +
  50 +
  51 +
  52 +public define HTML_Off_Form
  53 + dojo_button
  54 + (
  55 + String name,
  56 + String execute,
  57 + String id,
  58 + )
  59 + =
  60 + literal("
  61 + <button dojoType=\"dijit.form.Button\" id=\""+id+"\" onclick=\""+execute+"\">"+name+"</button>")
  62 +.
  63 +
  64 +public type Input_Type:
  65 + file,
  66 + text,
  67 + password.
  68 +
  69 +public type InputDial:
  70 + input_dial(HtmlId id, Input_Type input_type, String label, Maybe(String) class),
  71 + input_date(HtmlId id, String label),
  72 + input_combo(HtmlId id, String label, List((WebArgValue,String)) list_data),
  73 + input_check(HtmlId id, String label, Bool checked),
  74 + input_hidden(HtmlId id, WebArgValue value).
  75 +
  76 +
  77 +define List(HTML_Off_Form)
  78 + format_list_data
  79 + (
  80 + List((WebArgValue,String)) list_data,
  81 + List(HTML_Off_Form) result_list
  82 + )=
  83 + if list_data is
  84 + {
  85 + [] then result_list,
  86 + [h . t] then
  87 + if h is (wa, label) then
  88 + format_list_data(t, [literal("<option value=\"" + wa.value + "\">" + label + "</option>") . result_list])
  89 + }.
  90 +
  91 +public define HTML_Off_Form
  92 + dojo_combobox
  93 + (
  94 + WebArgName the_name,
  95 + HtmlId the_id,
  96 + String label,
  97 + List((WebArgValue,String)) list_data,
  98 + )=
  99 + sequence([
  100 + literal("<label for=\"" + the_id.id + "\">" + label + "</label>
  101 + <select id=\""+the_id.id+"\"
  102 + name=\"" + the_name.name + "\"
  103 + dojoType=\"dijit.form.ComboBox\"
  104 + autoComplete=\"false\">"),
  105 + sequence((format_list_data(list_data, []))),
  106 + literal("</select>")
  107 + ]).
  108 +
  109 +define HTML_Off_Form
  110 + _maybe_label
  111 + (
  112 + String label_text,
  113 + HtmlId html_id
  114 + ) =
  115 + if length(label_text) > 0 then literal("<label for=\"" + html_id.id + "\">" + label_text + "</label>")
  116 + else literal("").
  117 +
  118 +public define HTML_Off_Form
  119 + dojo_checkbox
  120 + (
  121 + WebArgName the_name,
  122 + HtmlId the_id,
  123 + String label,
  124 + WebArgValue val,
  125 + Bool checked,
  126 + )=
  127 + sequence([
  128 + _maybe_label(label, the_id),
  129 + literal("<input type=\"checkbox\" name=\"" + the_name.name + "\" id=\"" + the_id.id + "\" value=\"" + val.value + "\""
  130 + + (if checked then " checked=\"checked\" " else "") + " dojoType=\"dijit.form.CheckBox\" />"),
  131 + ]).
  132 +
  133 +
  134 +define HTML_Off_Form
  135 + input_in_dialog
  136 + (
  137 + InputDial input_data
  138 + )=
  139 + if input_data is
  140 + {
  141 + input_dial(html_id, input, label, class) then
  142 + sequence([
  143 + literal("<div id=\"" + html_id.id +"_block\"" +
  144 + if class is
  145 + {
  146 + failure then " class=\"dojo_diag\"",
  147 + success(class_name) then " class=\"dojo_diag block_"+ class_name +"\""
  148 + }+"><label for=\"" + html_id.id + "\" id=\"label_" + html_id.id + "\"" +
  149 + if class is
  150 + {
  151 + failure then "",
  152 + success(class_name) then " class=\"label_" + class_name + "\""
  153 + }+">" + label + "</label>"),
  154 + literal("<input dojoType=dijit.form.TextBox " +
  155 + if input is
  156 + {
  157 + file then "type=\"file\"",
  158 + text then "type=\"text\"",
  159 + password then "type=\"password\""
  160 + } +
  161 + " name=\""+html_id.id+"\" id=\""+html_id.id+"\" /></div>")
  162 + ]),
  163 +
  164 + input_date(html_id, label) then
  165 + sequence([
  166 + literal("<div id=\"" + html_id.id +"_block\" class=\"dojo_diag\" ><label for=\"" + html_id.id + "\"> " + label + "</label>"),
  167 + literal("<div id=\""+html_id.id+"\" type=\"text\" name=\"date1\"
  168 + dojoType=\"dijit.form.DateTextBox\">
  169 + </div></div>"
  170 + )
  171 + ]),
  172 +
  173 + input_combo(the_id, label, list_data) then
  174 + sequence([
  175 + literal("<div id=\"" + the_id.id +"_block\" class=\"dojo_diag\">"),
  176 + dojo_combobox(wan(the_id.id), the_id, label, list_data),
  177 + literal("</div>")
  178 + ]),
  179 +
  180 + input_check(the_id, label, checked) then
  181 + sequence([
  182 + literal("<div id=\"" + the_id.id +"_block\" class=\"dojo_diag\">"),
  183 + dojo_checkbox(wan(the_id.id), the_id, label, wav("1"), checked),
  184 + literal("</div>"),
  185 + ]),
  186 +
  187 + input_hidden(the_id, val) then
  188 + literal("<input type=\"hidden\" id=\"" + the_id.id +"\" name=\"" + the_id.id +"\" value=\"" + val.value + "\" class=\"dojo_diag\" />"),
  189 + }
  190 +.
  191 +
  192 +define List(HTML_Off_Form)
  193 + inputs_in_dialog
  194 + (
  195 + List(InputDial) inputs_data
  196 + )=
  197 + if inputs_data is
  198 + {
  199 + [] then [],
  200 + [h . t] then [input_in_dialog(h) . inputs_in_dialog(t)]
  201 + }.
  202 +
  203 +public define HTML_Off_Form
  204 + dijit_dialog
  205 + (
  206 + String name,
  207 + String dialog_id,
  208 + String execute,
  209 + String ok_label,
  210 + Maybe(String) cancel,
  211 + List(InputDial) inputs_data,
  212 + Maybe(String) do_cancel
  213 + )
  214 + =
  215 + sequence([
  216 + div([attr("dojoType", "dijit.Dialog"), id(dialog_id), title(name), attr("execute", execute)],
  217 + sequence([
  218 + sequence(inputs_in_dialog(inputs_data)),
  219 + literal("<button dojoType=dijit.form.Button type=\"submit\" class=\"dialog_ok\">" + ok_label + "</button>" +
  220 + if cancel is
  221 + {
  222 + failure then "",
  223 + success(cancel_label) then "<button dojoType=dijit.form.Button type=\"cancel\" class=\"dialog_cancel\" onclick=\"" +
  224 + if do_cancel is
  225 + {
  226 + failure then "dijit.byId('"+ dialog_id +"').hide()",
  227 + success(to_do_cancel) then to_do_cancel
  228 + }+ "\">" + cancel_label + "</button>"
  229 + }),
  230 + literal("<br/>")
  231 + ])
  232 + )
  233 + ])
  234 +.
  235 +
  236 +public define HTML_Off_Form
  237 + dojo_dialog
  238 + (
  239 + String name,
  240 + String dialog_id,
  241 + String execute,
  242 + String ok_label,
  243 + Maybe(String) cancel,
  244 + List(InputDial) inputs_data,
  245 + Maybe(String) do_cancel
  246 + )
  247 + =
  248 + sequence[
  249 + dojo_button(name,"dijit.byId('"+dialog_id+"').show()", dialog_id + "_button"),
  250 + dijit_dialog(name, dialog_id, execute, ok_label, cancel, inputs_data, do_cancel)
  251 + ]
  252 +.
  253 +
  254 +
  255 +
  256 +
  257 +public type DojoGridEditor:
  258 + inputEditor,
  259 + boolEditor,
  260 + selectEditor(List(String) options),
  261 + alwaysOnEditor.
  262 +
  263 +public type DojoGridDefaultColumn:
  264 + dojo_grid_default_column(
  265 + String styles,
  266 + Maybe(String) width,
  267 + Maybe(DojoGridEditor) editor).
  268 +
  269 +public type DojoGridColumn:
  270 + dojo_grid_column( String label,
  271 + String field_name,
  272 + Maybe(String) width,
  273 + Maybe(DojoGridEditor) editor).
  274 +
  275 +public type DojoGridView:
  276 + dojo_grid_view(
  277 + Maybe(DojoGridDefaultColumn) default_column,
  278 + List(DojoGridColumn) columns).
  279 +
  280 +public type DojoGridLayout:
  281 + dojo_grid_layout(
  282 + Maybe(String) selectable_row_header_width,
  283 + List(DojoGridView) views).
  284 +
  285 +define String to_String(DojoGridEditor editor) =
  286 + "editor: " +
  287 + if editor is
  288 + {
  289 + inputEditor then "dojox.grid.editors.Input",
  290 + boolEditor then "dojox.grid.editors.Bool",
  291 + selectEditor(options) then "dojox.grid.editors.Select, options: [" + join(",", map((String o) |-> "\"" + o + "\"", options)) + "]",
  292 + alwaysOnEditor then "dojox.grid.editors.AlwaysOn"
  293 + }.
  294 +
  295 +define String to_String(DojoGridView view) =
  296 + "{ " + (if view.default_column is success(col) then
  297 + (if col is dojo_grid_default_column(styles, mb_width, mb_editor) then
  298 + "defaultCell: {"
  299 + + "styles: \"" + styles + "\""
  300 + + (if mb_width is success(w) then ", width=\"" + w + "\"" else "")
  301 + + (if mb_editor is success(e) then ", " + to_String(e) else "")
  302 + + "}, ")
  303 + else "")
  304 + + "cells: [[" + join(",", map((DojoGridColumn col) |->
  305 + if col is dojo_grid_column(label, field, mb_width, mb_editor) then
  306 + "{"
  307 + + "name: \"" + label + "\""
  308 + + "field: \"" + field + "\""
  309 + + (if mb_width is success(w) then ", width=\"" + w + "\"" else "")
  310 + + (if mb_editor is success(e) then ", " + to_String(e) else "")
  311 + + "}",
  312 + view.columns)) + "]]"
  313 + +"}".
  314 +
  315 +
  316 +public define String
  317 + dojo_make_grid_script
  318 + (
  319 + HtmlId html_id,
  320 + DojoGridLayout layout,
  321 + String layout_name,
  322 + String store_name,
  323 + Bool can_edit
  324 + )
  325 + =
  326 +"<script type=\"text/javascript\">
  327 + " + layout_name + " = ["
  328 + + (if layout.selectable_row_header_width is success(w) then "{ type: 'dojox.GridRowView', width: '" + w + "'}, " else "")
  329 + + join(", ", map(to_String, layout.views))
  330 + + "];
  331 +</script>".
  332 +
  333 +public define HTML_Off_Form
  334 + dojo_make_grid_script
  335 + (
  336 + HtmlId html_id,
  337 + List(String) columns,
  338 + Bool can_edit
  339 + )
  340 + =
  341 + literal(
  342 +"<script type=\"text/javascript\">
  343 + var cols = ["+join(",", map((String col) |-> "\"" + col + "\"", columns)) + "];
  344 + dojo.addOnLoad(function(){
  345 + init_dojo_grid(\""+html_id.id+"\", cols, "+ (if can_edit then "1" else "0")+");
  346 + });
  347 +</script>").
  348 +
  349 +public define HTML_Off_Form
  350 + dojo_grid
  351 + (
  352 + HtmlId html_id,
  353 + Int rowsPerPage,
  354 + List(Table_Option) attributes,
  355 + )=
  356 + table([attr("dojoType", "dojox.grid.DataGrid"), attr("id", html_id.id), attr("jsId", html_id.id),
  357 + class("soria"), attr("singleClickEdit", "true"), attr("rowsPerPage", to_decimal(rowsPerPage)) . attributes],
  358 + empty, [], empty).
  359 +
  360 +
  361 +public define HTML_Off_Form
  362 + dojo_grid
  363 + (
  364 + HtmlId html_id,
  365 + List(CoreAttrs) attributes,
  366 +// List(GridColumn) columns,
  367 + String colum1,
  368 + String colum2,
  369 + String colum3,
  370 + String colum4,
  371 + Bool can_edit
  372 + )
  373 + =
  374 + sequence([
  375 + literal(
  376 +
  377 +"<script type=\"text/javascript\">
  378 + dojo.addOnLoad(function(){
  379 + init_dojo_grid(\""+html_id.id+"\", \""+colum1+"\",\""+colum2+"\", \""+colum3+"\", \""+colum4+"\", "+ (if can_edit then "1" else "0")+");
  380 + });
  381 +</script>"),
  382 + div_empty([id(html_id.id) . attributes /*attr("dojoType", "dojox.Grid"), */]),
  383 + ]).
  384 +//<div id=\"gridContainer\"></div>").
  385 +
  386 +
  387 +public define HTML_Off_Form
  388 + dojo_message_box
  389 + (
  390 + HTML_Off_Form name1,
  391 + HTML_Off_Form name2,
  392 + )
  393 + =
  394 + sequence([
  395 + literal("<br/>"),
  396 + div([class("message_box")],
  397 + sequence([
  398 + div([id("node3"), class("box nopad hidden")], name1),
  399 + div([id("node4"), class("box two nopad")], name2),
  400 + ])),
  401 + literal("<br/>"),
  402 + ]).
  403 +
  404 +
  405 +
  406 +public define HTML_Off_Form
  407 + dojo_tooltip
  408 + (
  409 + String title,
  410 + String keyword,
  411 + ) =
  412 + actioner(same,same, link([id("dojo_tip_" + keyword),class("dojoToolTip")],title, success(title)), "show_address_mailing", [("address_mailing", keyword)], []).
  413 + //actioner(same, same, push_button([id("dojo_tip_" + keyword), class("in"), event(onclick,"new_search(this)")], keyword), "", [], []).
  414 +
  415 +
  416 +public type BorderContainerRegion:
  417 + center,
  418 + top,
  419 + bottom,
  420 + leading,
  421 + trailing,
  422 + left,
  423 + right.
  424 +
  425 +define String
  426 + to_String
  427 + (
  428 + BorderContainerRegion region
  429 + )=
  430 + if region is
  431 + {
  432 + center then "center",
  433 + top then "top",
  434 + bottom then "bottom",
  435 + leading then "leading",
  436 + trailing then "trailing",
  437 + left then "left",
  438 + right then "right"
  439 + }.
  440 +
  441 +public type BorderContainerDesign:
  442 + headline,
  443 + sidebar.
  444 +
  445 +define String
  446 + to_String
  447 + (
  448 + BorderContainerDesign design
  449 + )=
  450 + if design is
  451 + {
  452 + headline then "headline",
  453 + sidebar then "sidebar"
  454 + }.
  455 +
  456 +
  457 +public define HTML_Off_Form
  458 + dojo_ContentPane
  459 + (
  460 + List(CoreAttrs) attributes,
  461 + BorderContainerRegion region,
  462 + Bool splitter,
  463 + HTML_Off_Form content
  464 + ) =
  465 + div([ attr("dojoType", "dijit.layout.ContentPane"),
  466 + attr("region", to_String(region)),
  467 + attr("splitter", if splitter then "true" else "false") . attributes ],
  468 + content).
  469 +
  470 +public define HTML_In_Form
  471 + dojo_ContentPane
  472 + (
  473 + List(CoreAttrs) attributes,
  474 + BorderContainerRegion region,
  475 + Bool splitter,
  476 + HTML_In_Form content
  477 + ) =
  478 + div([ attr("dojoType", "dijit.layout.ContentPane"),
  479 + attr("region", to_String(region)),
  480 + attr("splitter", if splitter then "true" else "false") . attributes ],
  481 + content).
  482 +
  483 +public define HTML_Off_Form
  484 + dojo_TabContainer
  485 + (
  486 + List(CoreAttrs) attributes,
  487 + HTML_Off_Form content
  488 + ) =
  489 + div([attr("dojoType", "dijit.layout.TabContainer") . attributes ],
  490 + content).
  491 +
  492 +
  493 +public define HTML_Off_Form
  494 + dojo_BorderContainer
  495 + (
  496 + List(CoreAttrs) attributes,
  497 + Maybe(String) the_title,
  498 + BorderContainerDesign design,
  499 + Bool live_splitter,
  500 + Bool persist,
  501 + Bool closable,
  502 + String container,
  503 + HTML_Off_Form content
  504 + ) =
  505 + with the_attributes = (List(CoreAttrs)) [attr("dojoType", "dijit.layout.BorderContainer"), attr("dojoAttachPoint", container),
  506 + attr("design", to_String(design)), attr("liveSplitters", live_splitter), attr("persist", persist),
  507 + attr("closable",closable) . attributes ],
  508 + total_attributes = if the_title is
  509 + {
  510 + failure then the_attributes,
  511 + success(t) then [title(t) . the_attributes]
  512 + },
  513 + div(total_attributes, content).
  514 +
  515 +public define HTML_In_Form
  516 + dojo_BorderContainer
  517 + (
  518 + List(CoreAttrs) attributes,
  519 + Maybe(String) the_title,
  520 + BorderContainerDesign design,
  521 + Bool live_splitter,
  522 + Bool persist,
  523 + Bool closable,
  524 + String container,
  525 + HTML_In_Form content
  526 + ) =
  527 + with the_attributes = (List(CoreAttrs)) [attr("dojoType", "dijit.layout.BorderContainer"), attr("dojoAttachPoint", container),
  528 + attr("design", to_String(design)), attr("liveSplitters", live_splitter), attr("persist", persist),
  529 + attr("closable",closable) . attributes ],
  530 + total_attributes = if the_title is
  531 + {
  532 + failure then the_attributes,
  533 + success(t) then [title(t) . the_attributes]
  534 + },
  535 + div(total_attributes, content).
  536 +
  537 +public define HTML_Off_Form
  538 + dojo_tree
  539 + (
  540 + List(CoreAttrs) attributes,
  541 + )=
  542 + div_empty(attributes).
  543 +
  544 +
  545 +
  546 +public define HTML_Off_Form
  547 + dojo_Toolbar
  548 + (
  549 + List(CoreAttrs) attributes,
  550 + HTML_Off_Form content
  551 + )=
  552 + div([attr("dojoType", "dijit.Toolbar") . attributes ],
  553 + content).
  554 +
  555 +
  556 +public define HTML_Off_Form
  557 + dojo_tooltip
  558 + (
  559 + List(CoreAttrs) attributes,
  560 + List(Text_Option) txt_attr,
  561 + HtmlId html_id,
  562 + String label,
  563 + HTML_Off_Form tooltip_content,
  564 + )=
  565 + sequence([
  566 + text([id(html_id.id) . txt_attr], label),
  567 + div([id(html_id.id + "_tt"), attr("connectId", html_id.id), attr("dojoType", "dijit.Tooltip") . attributes], tooltip_content)
  568 + ]).
  569 +
  570 +
  571 +public define HTML_Off_Form
  572 + dojo_button
  573 + (
  574 + HtmlId html_id,
  575 +// Maybe(String) class,
  576 + String name,
  577 + String iconclass,
  578 + Maybe(String) tip_msg,
  579 + String execute,
  580 + )=
  581 + literal("
  582 + <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" >"
  583 + + name
  584 + + "<script type=\"dojo/method\" event=\"onClick\">"
  585 + + execute
  586 + + "</script>"
  587 + + "</button>" +
  588 + if tip_msg is
  589 + {
  590 + failure then "",
  591 + success(tip) then
  592 + "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"
  593 + }).
  594 +
  595 +public define HTML_In_Form
  596 + dojo_button
  597 + (
  598 + HtmlId html_id,
  599 +// Maybe(String) class,
  600 + String name,
  601 + String iconclass,
  602 + Maybe(String) tip_msg,
  603 + String execute,
  604 + )=
  605 + literal("
  606 + <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" >"
  607 + + name
  608 + + "<script type=\"dojo/method\" event=\"onClick\">"
  609 + + execute
  610 + + "</script>"
  611 + + "</button>" +
  612 + if tip_msg is
  613 + {
  614 + failure then "",
  615 + success(tip) then
  616 + "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"
  617 + }).
  618 +
  619 +
  620 +public define HTML_Off_Form
  621 + dojo_declaration
  622 + (
  623 + String name,
  624 + List(CoreAttrs) attributes,
  625 + HTML_Off_Form content
  626 + )=
  627 + div([attr("dojoType", "dijit.Declaration"), attr("widgetClass", name) . attributes ],
  628 + content).
  629 +
  630 +
  631 +public define HTML_In_Form
  632 + dojo_declaration
  633 + (
  634 + String name,
  635 + List(CoreAttrs) attributes,
  636 + HTML_In_Form content
  637 + )=
  638 + div([attr("dojoType", "dijit.Declaration"), attr("widgetClass", name) . attributes ],
  639 + content).
  640 +
  641 +public define HTML_Off_Form
  642 + dojo_editor
  643 + (
  644 + List(CoreAttrs) attributes,
  645 + HtmlId html_id,
  646 + WebArgName input_name,
  647 + HTML_Off_Form text,
  648 + )=
  649 + div([id(html_id.id), attr("name", input_name.name), attr("dojoType", "dijit.Editor")
  650 + ,attr("extraPlugins", "['|', 'foreColor','hiliteColor',{name:'dojox.editor.plugins.FontChoice', command:'fontName', generic:true},'fontSize','formatBlock','|','createLink','insertImage']")
  651 + . attributes], text).
  652 +
  653 + public define HTML_In_Form
  654 + dojo_button
  655 + (
  656 + HtmlId html_id,
  657 + String name,
  658 + String iconclass,
  659 + Maybe(String) tip_msg,
  660 + String execute,
  661 + )=
  662 + literal("<input id=\"realSubmitButton"+ html_id.id + "\" type=\"submit\" style=\"display:none\">
  663 + <button dojoType=\"dijit.form.Button\" id=\"" + html_id.id + "\" iconClass=\"" + iconclass + "\" onclick=\"dojo.byId('realSubmitButton" + html_id.id + "').click();" + execute + "\">" + name + "</button>" +
  664 + if tip_msg is
  665 + {
  666 + failure then "",
  667 + success(tip) then
  668 + "<span dojoType=\"dijit.Tooltip\" connectId=\"" + html_id.id + "\">" + tip + "</span>"
  669 + }).
  670 +
  671 +public define HTML_In_Form
  672 + dojo_checkbox
  673 + (
  674 + List(InputAttrs) attributes,
  675 + WebArgName name,
  676 + HtmlId id,
  677 + String label,
  678 + WebArgValue val,
  679 + Bool checked,
  680 + )=
  681 + check_box_r([attr("dojoType", "dijit.form.CheckBox") . attributes] , label, id, name, val, checked).
  682 +
  683 +public define HTML_In_Form
  684 + dojo_combobox
  685 + (
  686 + List(InputAttrs) attributes,
  687 + WebArgName name,
  688 + HtmlId id,
  689 + String label,
  690 + List((List(CoreAttrs),WebArgValue,String)) list_data,
  691 + InitialValue selected,
  692 + )=
  693 + // selector_c([attr("dojoType", "dijit.form.ComboBox") . attributes], label, id, name, 1, list_data, selected, non_mandatory).
  694 + selector_c(attributes, label, id, name, 1, list_data, selected).
  695 +
  696 +public define HTML_Off_Form
  697 + dojo_toaster
  698 + (
  699 + List(CoreAttrs) attributes,
  700 + HtmlId html_id,
  701 + String message_topic,
  702 + Position_Direction position_direction,
  703 + Bool separator,
  704 + Maybe(Int) duration
  705 + )=
  706 + div(append(append(if separator then [attr("separator","&lt;hr&gt;")]
  707 + else [],
  708 + if duration is
  709 + {
  710 + failure then [],
  711 + success(dur) then [attr("duration", abs_to_decimal(dur))]
  712 + }),
  713 + [attr("dojoType", "dojox.widget.Toaster"), attr("messageTopic", message_topic),
  714 + attr("positionDirection", pos_dir_to_str(position_direction)), id(html_id.id)
  715 + . attributes ]),
  716 + literal("")).
  717 +
  718 +public define HTML_Off_Form
  719 + dojo_progressBar
  720 + (
  721 + List(CoreAttrs) attributes,
  722 + List(Text_Option) attributes_text,
  723 + HtmlId html_id,
  724 + String label
  725 + )=
  726 + sequence([
  727 + text([id("text_" + html_id.id), class("progress_bar") . attributes_text], label),
  728 + div([id(html_id.id), class("progress_bar"), attr("indeterminate", "true"), attr("dojoType", "dijit.ProgressBar") . attributes], literal(""))
  729 + ]).
  730 +
  731 +public define HTML_Off_Form
  732 + dojo_progressBar
  733 + (
  734 + List(CoreAttrs) attributes,
  735 + List(Text_Option) attributes_text,
  736 + HtmlId html_id,
  737 + String label,
  738 + Int progress,
  739 + Int maximum
  740 + )=
  741 + sequence([
  742 + text([id("text_" + html_id.id), class("progress_bar") . attributes_text], label),
  743 + div([id(html_id.id),
  744 + class("progress_bar"),
  745 + attr("maximum", abs_to_decimal(maximum)),
  746 + attr("progress", abs_to_decimal(progress)),
  747 + attr("dojoType", "dijit.ProgressBar") . attributes], literal(""))
  748 + ]).
  749 +
  750 +define Maybe(Int)
  751 + string_to_month
  752 + (
  753 + String month_s
  754 + )=
  755 + with month = to_lower(month_s),
  756 + if month = "jan" then success(1)
  757 + else if month = "feb" then success(2)
  758 + else if month = "mar" then success(3)
  759 + else if month = "apr" then success(4)
  760 + else if month = "may" then success(5)
  761 + else if month = "jun" then success(6)
  762 + else if month = "jul" then success(7)
  763 + else if month = "aug" then success(8)
  764 + else if month = "sep" then success(9)
  765 + else if month = "oct" then success(10)
  766 + else if month = "nov" then success(11)
  767 + else if month = "dec" then success(12)
  768 + else failure
  769 + .
  770 +
  771 +
  772 +// 'Thu Jan 14 2010 00:00:00 GMT+0100' must be replaced by '2010-01-14 00:00:00'
  773 +
  774 +
  775 +
  776 +public define Maybe(String)
  777 + dojo_date_to_db_datetime
  778 + (
  779 + String data
  780 + )=
  781 + with list_data = split_by_token(data, ' '),
  782 + if nth(2, list_data) is
  783 + {
  784 + failure then failure,
  785 + success(day) then
  786 + if nth(1, list_data) is
  787 + {
  788 + failure then failure,
  789 + success(month) then
  790 + if nth(3, list_data) is
  791 + {
  792 + failure then failure,
  793 + success(year) then
  794 + if nth(4, list_data) is
  795 + {
  796 + failure then failure,
  797 + success(hour) then
  798 + if string_to_month(month) is
  799 + {
  800 + failure then failure,
  801 + success(month_int) then
  802 + success(year+"-"+month_int+"-"+day+" "+hour)
  803 + }
  804 + }
  805 + }
  806 + }
  807 + }.
  808 +
  809 +public define List(HTML_Head_Tag)
  810 + dojo_defaults
  811 + =
  812 + [
  813 + // js(js_file("js/dojo/dojo.js", [attr("djConfig", "parseOnLoad: true, isDebug: " + (if debug_mode then "true" else "false") + ", usePlainJson: true")])),
  814 + js(js_file("js/dojo/dojo/dojo.js", [attr("djConfig", "parseOnLoad: true, isDebug: false, usePlainJson: true")])),
  815 + js(js_file("js/dojo/dijit/dijit.js")),
  816 + //css(css_file("js/dojo/dojo/resources/dojo.css"))
  817 + ].
  818 +
  819 +
  820 +public define List(HTML_Head_Tag)
  821 + dojo_init
  822 + (
  823 + String web_dir,
  824 + String theme_name
  825 + )
  826 + =
  827 + with theme_name =
  828 + if file_exists(web_dir+"/public/js/dojo/dijit/themes/"+theme_name+"/"+theme_name+".css")then theme_name else "claro",
  829 + [ css(css_file("js/dojo/dijit/themes/"+theme_name+"/"+theme_name+".css")) .
  830 + [ css(css_file("js/dojo/dijit/themes/"+theme_name+"/"+theme_name+"_rtl.css")) . dojo_defaults ]
  831 + ]
  832 + .
web/CXM_making_a_web_site.anubis
1 -๏ปฟ  
2 -  
3 - *Project* Anubis  
4 -  
5 - *Title* Making interactive Web sites.  
6 -  
7 - *Copyright* Copyright (c) Alain Proutรฉ 2004-2005.  
8 - Copyright (c) Calexium 2007.  
9 -  
10 -  
11 - *Authors* Alain Proutรฉ  
12 - David Renรฉ  
13 -  
14 - *Revised* May 2007  
15 -  
16 -  
17 - *Overview*  
18 -  
19 - In this file we propose simple tools for making well structured interactive and secured  
20 - web sites.  
21 -  
22 -  
23 - ----------------------------------- Table of Contents ---------------------------------  
24 -  
25 - * (1) Structure of a web site.  
26 - ** (1.1) Three sorts of data.  
27 - ** (1.2) How requests are handled.  
28 - ** (1.3) What web pages are made of.  
29 - ** (1.4) Actions.  
30 - ** (1.5) States.  
31 -  
32 - * (2) Carrying on.  
33 - ** (2.1) Describing your web sites.  
34 - ** (2.2) Directories on the server's disk.  
35 - ** (2.3) Starting your web sites.  
36 -  
37 - * (3) The HTML interface.  
38 - ** (3.1) Types used by the HTML interface.  
39 - ** (3.2) ``in form'' versus ``off form''.  
40 - ** (3.3) Defining your own style.  
41 - ** (3.4) Actioners and forms.  
42 - ** (3.5) Local popup.  
43 -  
44 - ---------------------------------------------------------------------------------------  
45 -  
46 -  
47 -read tools/basis.anubis  
48 -read tools/printable_tree.anubis  
49 -read tools/base64.anubis  
50 -read system/string.anubis  
51 -read system/logger.anubis  
52 -read CXM_common.anubis  
53 -read CXM_multihost_http_server.anubis  
54 -read web/mime.anubis  
55 -read CXM_cookies.anubis  
56 -  
57 -  
58 - * (1) Structure of a web site.  
59 -  
60 - First of all we need to explain what a web site should be made of. Ideally, the  
61 - visitor (also called the 'client') should see the web site working as any other  
62 - interactive computer software. So, it should be clear that a 'session' (i.e. a visit  
63 - to the web site, including the consultation of several pages) is some kind of  
64 - conversation between the visitor and the web site, and that the web site should  
65 - maintain a 'current state' of this conversation. At each new request (click) from the  
66 - visitor, this state must be updated. This whole conversation is called a 'session' and  
67 - should not be confused with a single request.  
68 -  
69 -  
70 -  
71 - ** (1.1) Three sorts of data.  
72 -  
73 - All the data needed for putting a web site at work may be dispatched into three  
74 - categories:  
75 -  
76 - 1. Constant data (data that never change). These data may be hard coded into the  
77 - Anubis source files of the web site.  
78 -  
79 - 2. Permanent data (data which always exist independantly of the users connected to  
80 - the web site). These data are normally recorded into data bases.  
81 -  
82 - 3. Session data (data which depend on a particular visitor and which exist only  
83 - during the time he visits the web site). These data are stored into so-called  
84 - 'states'.  
85 -  
86 -  
87 - It is important to determine which data belongs to which category. This is part of your  
88 - design decisions.  
89 -  
90 -  
91 -  
92 - ** (1.2) How requests are handled.  
93 -  
94 - We want to separate the following two functionalities (which are used at each request  
95 - (click) during a single session):  
96 -  
97 - - computing the new state from the previous state and from the client request, and  
98 - updating the data base,  
99 -  
100 - - computing the page to be sent to the client from the new current state and from  
101 - the informations in the data base.  
102 -  
103 -  
104 - The next picture shows the structure we have in mind:  
105 -  
106 -  
107 - request +---------+ HTML page (with a hidden state name)  
108 - .-------------------| client |<--------------.  
109 - | .-----------------| | |  
110 - | | previous state +---------+ |  
111 - | | name (if any) |  
112 - | | | client side  
113 - ............................................................................  
114 - | | | server side  
115 - | | |  
116 - | | .-------------------. |  
117 - | | | previous state | |  
118 - V V V | |  
119 - +---------------+ +---------------+ +--------------+  
120 - | compute state | | server's disk | | compute page |  
121 - +---------------+ +---------------+ +--------------+  
122 - ^ | | ^ ^ ^ ^ ^  
123 - | | | | | | | |  
124 - | | `--------------------+--------------------' | |  
125 - | | new state | | |  
126 - read | `------------------------+--------------------' |  
127 - write | new state name |  
128 - update V |  
129 - +-----------+ |  
130 - | data base |--------------------------------------------'  
131 - +-----------+ read only  
132 -  
133 -  
134 - When the client begins a session, there is no previous state. In this case, a default  
135 - 'initial state' is used instead.  
136 -  
137 - The data base may be updated by 'compute state' box, but should not be update by the  
138 - 'compute page' box. The 'compute page' box should be allowed only to read the data  
139 - base.  
140 -  
141 - In this file, all the above stuff is defined, except the 'compute state' and 'compute  
142 - page' boxes. You just have to provide the function for computing a new state (compute  
143 - state) and the function for computing the page (compute page) from the new state. You  
144 - don't have to worry about state names, saving and retrieving states and the like.  
145 -  
146 -  
147 -  
148 -  
149 -  
150 - ** (1.3) What web pages are made of.  
151 -  
152 - What the client can see in his browser's window may be called a 'page'. Within a page,  
153 - we have several sorts of components:  
154 -  
155 - - 'local' components, i.e. all components which do not open a connection, like  
156 - texts, images, etc... possibly using JavaScript programmation,  
157 -  
158 - - 'actioners', which, when clicked upon, open a connection with our web site; they  
159 - may appear as links or buttons, etc...  
160 -  
161 - - 'foreign links', which when clicked upon, open a connection with another web site  
162 - (or ours eventually).  
163 -  
164 - Of course, what an actioner does is just ask our web site to perform an action. To that  
165 - end, the actioner essentially sends the name of the action to be performed. However, it  
166 - may be necessary to provide additional informations which may be seen as 'operands' of  
167 - the action. In order to attach operands to an action, HTML provides the notion of  
168 - 'form'. Indeed, a form contains essentially a set of input fields into which the client  
169 - may put values for the required operands of the action, and a submit button, which is  
170 - the actioner itself. Notice that a single form may contain several submit buttons,  
171 - which simply means that there are several distincts actions taking the same set of  
172 - operands.  
173 -  
174 - Restrictions must be put on the use of all theses gadgets. Indeed, for example,  
175 - putting a form within another form is officially meaningless in HTML, and the client's  
176 - browser may be seriously disturbed by this. In this file, we propose an interface to  
177 - the HTML language, which forbids such meaningless things, simply by imposing a strict  
178 - typing of HTML concepts.  
179 -  
180 - Each web site may be accessible through two communication channels:  
181 -  
182 - - a non secured channel (HTTP),  
183 - - a secured channel (HTTPS).  
184 -  
185 - Nevertheless, the whole thing should be considered as a single web site. For example,  
186 - you may have a secured page, obtained through HTTPS, containing public images obtained  
187 - through HTTP. An actioner in a non secured page may open a secured connection, and  
188 - conversely.  
189 -  
190 - Summarizing, a web page is made of local elements, foreign links and actioners.  
191 - Actioners receive operands from forms, and they also choose to communicate through the  
192 - non secured or through the secured channel.  
193 -  
194 -  
195 -  
196 - +-------------------+  
197 - | page |  
198 - | | +---------------+  
199 - | +--------------+ | | next page |  
200 - | | form | | | (non secured) |  
201 - | | +----------+ | | HTTP | |  
202 - | | | actioner |---------------------------->| |  
203 - | | +----------+ | | +---------------+  
204 - | | | |  
205 - | | +----------+ | | +---------------+  
206 - | | | actioner |---------------------------->| next page |  
207 - | | +----------+ | | HTTPS | (secured) |  
208 - | | | | | |  
209 - | +--------------+ | | |  
210 - | | +---------------+  
211 - | |  
212 - +-------------------+  
213 -  
214 -  
215 - Notice that actioners need no be necessarily put into forms. In that case, they work as  
216 - ordinary links, but they still may receive operands as we shall see.  
217 -  
218 -  
219 -  
220 -  
221 - ** (1.4) Actions.  
222 -  
223 - The client opens a new connection with our web site whenever he clicks on an  
224 - actioner. The result is that a request is sent, essentially made of a list of 'web  
225 - arguments'. Each web argument is a pair (name,value). One of these web arguments, the  
226 - 'action' web argument (whose name is "a"), determines the action to be performed. The  
227 - other web arguments (not including "s", used to identify the state) are the operands  
228 - for this action.  
229 -  
230 - Hence, the 'compute state' box in the picture above, splits naturally into as many  
231 - sub-boxes as there are actions. For this reason, we define the following type for  
232 - representing actions (where '$State' is the type representing session informations):  
233 -  
234 -public type Web_Action($State):  
235 - http_action (String name, // name of action  
236 - ($State) -> Bool allow, // true if action allowed  
237 - (HTTP_Info http_info,  
238 - List(Web_arg) web_args, // actually only 'operands' web arguments  
239 - $State state) -> $State do_it),  
240 - https_action (String name, // name of action  
241 - ($State) -> Bool allow, // true if action allowed  
242 - (HTTP_Info http_info,  
243 - List(Web_arg) web_args, // actually only 'operands' web arguments  
244 - $State state) -> $State do_it),  
245 - http_https_action (String name,  
246 - ($State) -> Bool allow,  
247 - (HTTP_Info http_info,  
248 - List(Web_arg) web_args,  
249 - $State state) -> $State do_it).  
250 -  
251 - 'http_action's are executed only under HTTP, and 'https_action's are executed only  
252 - under HTTPS. 'http_https_action's may be executed under both types of connections.  
253 -  
254 - Each action has a name, which is used to identify the action. Each action also has a  
255 - function 'allow' whose job is to verify that the action is allowed in the current  
256 - state, and a function 'do_it' for performing the action. The function 'do_it' receives  
257 - a lot of informations:  
258 -  
259 - - 'HTTP informations':  
260 - - the IP address of the client,  
261 - - the URI requested by the client (after redirection),  
262 - - the list of HTTP headers generated by the client's browser,  
263 - - the list of web arguments sent by the client (except "s" and "a"),  
264 - - the previous state (or the 'initial' or 'ticket expired' state if no previous  
265 - state can be found).  
266 -  
267 - In most cases, HTTP informations are not used. This is the reason why they are gathered  
268 - for simplicity into a unique datum of type 'HTTP_Info'.  
269 -  
270 -// For your convenience, we introduce the following simpler variants:  
271 -//  
272 -//public define Web_Action($State)  
273 -// http_action  
274 -// (  
275 -// String name,  
276 -// $State -> Bool allow,  
277 -// (List(Web_arg),$State) -> $State do_it  
278 -// ) =  
279 -// http_action(name,  
280 -// (Maybe($State) ms) |-> if ms is  
281 -// {  
282 -// failure then true,  
283 -// success(s) then allow(s)  
284 -// },  
285 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
286 -// {  
287 -// failure then (failure, []),  
288 -// success(s2) then (success(do_it(l,s2)), [])  
289 -// }).  
290 -//  
291 -//public define Web_Action($State)  
292 -// https_action  
293 -// (  
294 -// String name,  
295 -// $State -> Bool allow,  
296 -// (List(Web_arg),$State) -> $State do_it  
297 -// ) =  
298 -// https_action(name,  
299 -// (Maybe($State) ms) |-> if ms is  
300 -// {  
301 -// failure then true,  
302 -// success(s) then allow(s)  
303 -// },  
304 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
305 -// {  
306 -// failure then (failure, []),  
307 -// success(s2) then (success(do_it(l,s2)), [])  
308 -// }).  
309 -//  
310 -//public define Web_Action($State)  
311 -// http_https_action  
312 -// (  
313 -// String name,  
314 -// $State -> Bool allow,  
315 -// (List(Web_arg),$State) -> $State do_it  
316 -// ) =  
317 -// http_https_action(name,  
318 -// (Maybe($State) ms) |-> if ms is  
319 -// {  
320 -// failure then true,  
321 -// success(s) then allow(s)  
322 -// },  
323 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
324 -// {  
325 -// failure then (failure, []),  
326 -// success(s2) then (success(do_it(l,s2)), [])  
327 -// }).  
328 -  
329 -  
330 -  
331 - When you define your web site, you must provide the list of all the actions of the  
332 - site. When a new state has been computed, a graphical representation of this state  
333 - must be sent to the client. To that end, you must provide a function (named below  
334 - 'compute_page') of type:  
335 -  
336 - $State -> HTTP_Answer  
337 -  
338 - where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML  
339 - pages.  
340 -  
341 -public type HTTP_Answer:...  
342 -  
343 - It should be clear that states and pages are deeply linked together. Indeed, we really  
344 - understand the page shown to the client as a representation of the current state of the  
345 - conversation between the client and the web site, but also containing informations  
346 - taken from the data bases.  
347 -  
348 -  
349 -  
350 -  
351 -  
352 - ** (1.5) States.  
353 -  
354 - Now, we explain how you can define the type (say 'State') to be used as an instance of  
355 - the type parameter '$State'. The following is just a suggestion.  
356 -  
357 - Each state determines a page (since 'compute_page' computes a page from a  
358 - state). However, some components of the state may be independant of the page. It may be  
359 - the case for example for the indication of the natural language used by the  
360 - client. Hence, a state should be made of (at least) two parts:  
361 -  
362 - - informations which are the same for all pages,  
363 - - informations which are particular to each page.  
364 -  
365 - For example, you could define:  
366 -  
367 - type Page: // one alternative per page, with particular informations  
368 - login(...), // in the components  
369 - main_page(...),  
370 - ...etc...  
371 -  
372 - Now, the type 'State' could be defined as follows:  
373 -  
374 - type State:  
375 - state(Language, // informations valid for all pages  
376 - ...,  
377 - Page). // informations particular to a page  
378 -  
379 - However, if you are making a secured web site within which clients should be identified  
380 - (by id and password), it may be a good idea to have two sorts of states, one for non  
381 - identified clients and one for identified clients. In this case, define the type  
382 - 'State' as follows (this is just a suggestion):  
383 -  
384 - type State:  
385 - non_identified(Language),  
386 - identified(String id,  
387 - Language,  
388 - Page).  
389 -  
390 - When a request arrives, check if the previous state is 'identified(...)' or  
391 - 'non_identified(...)', and don't provide access to certain pages to non identified  
392 - clients. This is required for security.  
393 -  
394 - Some more words on security. If your site needs to identify clients, define the  
395 - initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and  
396 - password of the client. If the id and password are correct, then change the state of  
397 - the client to 'identified(...)'. No other action should be able to do that. Now, be  
398 - confident that clients cannot forge states. The only information they have is the name  
399 - of a state, not the state itself which is never sent over the network, but only stored  
400 - on the server's disk. The name of the state is constructed using strong cryptographical  
401 - methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even  
402 - state names cannot be seen by a third party. So, if the system retrieves a previous  
403 - state of the form 'identified(...)', you can be confident that your client is well  
404 - identified, and you can send him confidential informations.  
405 -  
406 - States have a limited life time. It may happen that a client clicks on a button at a  
407 - time its state is out of date. In this case, this system considers that the new state  
408 - is a special state named 'ticket expired'. You must provide a function producing this  
409 - state when you describe your web site. The page corresponding to this state must just  
410 - inform the client that he/she waited a too long time before clicking on a button, and  
411 - has to restart (a new conversation) from the begining.  
412 -  
413 -  
414 -  
415 - * (2) Carrying on.  
416 -  
417 - ** (2.1) Describing your web sites.  
418 -  
419 - Before you may start your web site, you must describe it, i.e. produce a datum of the  
420 - opaque type 'Web_Site'.  
421 -  
422 -public type Web_Site:...  
423 -  
424 - Producing such a datum may be performed by:  
425 -  
426 -public define Web_Site  
427 - make_web_site_description  
428 - (  
429 - List(String) common_names, // for example: ["www.our-business.com",  
430 - // "192.168.0.1"]  
431 - // the second one is just for testing  
432 - String site_directory, // where 'public' and other directories are  
433 - // located (should NOT end with '/')  
434 - String state_directory,  
435 - One -> One init,  
436 - (HTTP_Info,  
437 - List(Web_arg),  
438 - Bool is_https) -> $State initial_state,  
439 - ($State expired,  
440 - Maybe(String),  
441 - HTTP_Info,  
442 - List(Web_arg),  
443 - Bool is_https) -> $State ticket_expired_state,  
444 - (Maybe(String),  
445 - HTTP_Info,  
446 - List(Web_arg),  
447 - Bool is_https) -> $State ticket_lost_state,  
448 - List(Web_Action($State)) actions,  
449 - $State -> HTTP_Answer compute_page,  
450 - $State -> List(HTTP_header) additional_headers,  
451 - Int timeout, // seconds (todo: minutes)  
452 - Redirections redirections,  
453 - String charset,  
454 - List(String) journal_extensions,  
455 - List(String) journal_headers,  
456 - String authorization_secret,  
457 - List(MIME) known_mime_types,  
458 - (String action_name,  
459 - List(Web_arg) args)-> One before_send_file  
460 - ).  
461 -  
462 -  
463 - Explanations:  
464 -  
465 - 'common_names' is the list of names of the site (the name the browser must send as the  
466 - value of the 'Host' HTTP header in order to access the site must be in that list). Such  
467 - a name generally looks like this:  
468 -  
469 - www.somewhere.com  
470 -  
471 - If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of  
472 - the site must be exactly the same as the name on the certificate (which is precisely  
473 - called the 'common name' in the X.509 jargon). If the two names do not match, the site  
474 - will still work, but the transaction will not be transparent to the client. His browser  
475 - will complain that the name of the certificate does not match the name of the site, and  
476 - he will have to accept the certificate manually.  
477 -  
478 - 'site_directory' is the absolute path to the directory where the files needed by the  
479 - site are located. Usually this directory looks like:  
480 -  
481 - my_anubis/web_sites/www.somewhere.com  
482 -  
483 - However, this information is not computed from 'common_name', so that you can change  
484 - the common name (for example temporarily, for networking reasons) without loosing  
485 - access to the files.  
486 -  
487 - 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state  
488 - whose graphical representation is a page explaining to the user that its 'ticket' (or  
489 - 'session information') has expired, and that he/she must close all popup windows and  
490 - start a new session. The arguments of the function contain the previous (expired)  
491 - state and all current informations concerning the user. This arguments may be useful  
492 - for example for producing the expiration message in the language chosen by the user.  
493 - You can also (and this may be much smarter) send a 'ticket prolongation page'  
494 - (including a new login for example), and resume the same conversation, since you have  
495 - all the pertinent informations at hand. In the case the ticket is definitely lost, the  
496 - second fonction 'ticket_lost_state' is used.  
497 -  
498 - Notice that despite the fact that the parameter $State is involved in the arguments of  
499 - the above function, the type 'Web_Site' does not depend on this parameter. This allows  
500 - to produce lists of web site descriptions, where each description may be constructed  
501 - with a different instance of $State. This is required because distinct sites must have  
502 - distinct types of session informations. This is made possible by the fact that the  
503 - type is obscure, and the constructor replaced by a function which assembles  
504 - 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single  
505 - entity not depending on $State. You should have a look to the private part of this file  
506 - if you want more precisions about this programming technique.  
507 -  
508 - 'charset' is a string which will determine the character encoding to be used by the  
509 - browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",  
510 - etc...  
511 -  
512 - 'before_send_file' is a function which is executed just before the HTTP server sends a  
513 - file. It gets an action name and the web arguments received with the request for that  
514 - file. Notice that this action name and these web arguments may be put into a  
515 - 'private_download' element, and will come back to the server at the time of the  
516 - download.  
517 -  
518 -  
519 -  
520 - ** (2.2) Directories on the server's disk.  
521 -  
522 - The description of your site contains the name of the directory within which the  
523 - required files are located. This may be for example:  
524 -  
525 - my_anubis/web_sites/www.our-business.com/  
526 -  
527 - This is called the 'site directory' (for the given site). Within the site directory,  
528 - the following directories are created by this program:  
529 -  
530 - states  
531 - public  
532 - journal  
533 - private_download  
534 - upload_temporary  
535 -  
536 - The directory 'states' is used for storing states (session informations). Out of date  
537 - states are automatically removed after some time.  
538 -  
539 - The tree rooted at 'public' contains files that the server is allowed to send to the  
540 - clients. For security reasons, the server never sends a file which is not within the  
541 - tree whose root is this 'public' directory (except for the 'private download' mecanism;  
542 - see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis')  
543 - must have been recognized before the file may be sent.  
544 -  
545 - The directory 'journal' contains the jounal files. The roles of the remaining  
546 - directories 'private_download' and 'upload_temporary' is explained in  
547 - 'multihost_http_server.anubis', where you will also find further informations on  
548 - 'public' and 'journal'.  
549 -  
550 -  
551 -  
552 -  
553 - ** (2.3) Web servers parameters.  
554 -  
555 - The web servers have several parameters useful for administration. They are described  
556 - as follows:  
557 -  
558 - public type WebServersParameters:  
559 - wsparms(Var(Bool) shutdown_required,  
560 -  
561 -  
562 -  
563 -  
564 - ** (2.4) Starting your web sites.  
565 -  
566 - When you have described all your web sites (you may want to have several web sites, and  
567 - they are distinguished by their 'common name'), you may start them all together using  
568 - 'start_web_sites' below. This function returns a result of the following type:  
569 -  
570 -public type Start_Web_Sites_Result:  
571 - cannot_bind_to_port(Word32),  
572 - cannot_bind_to_port(Word32,Word32),  
573 - ok(Server http_server,  
574 - Server https_server).  
575 -  
576 - Indeed, it may happen that the system cannot bind (begin to listen) to one of the two  
577 - ports (or to both). The main reason is that another server is already listening on that  
578 - port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that  
579 - the 's' bit has not been set for 'user' and 'group' (there is not such problem under  
580 - Windows). Also notice that the Linux kernel may need a rather long time (up to several  
581 - minutes) before liberating a listening port. Now, if the system can bind to the two  
582 - ports, the pair of the two servers is returned. Two tools are useful for manipulating  
583 - servers:  
584 -  
585 - shutdown of type Server -> One  
586 - is_down of type Server -> Bool  
587 -  
588 - They are defined in 'predefined.anubis' (together with the type 'Server').  
589 -  
590 -  
591 -public define Start_Web_Sites_Result  
592 - start_web_sites  
593 - (  
594 - Word32 ip_address, // the IP address shared by the web sites  
595 - Word32 http_port, // usually: 80  
596 - Word32 https_port, // usually: 443  
597 - String ssl_certificate_common_name,  
598 - List(Web_Site) web_sites, // web sites to be started  
599 - (One) -> Bool shutdown_required  
600 - ).  
601 -  
602 - 'ip_address' is the IP address on which the two servers listen. If you put 0, the  
603 - servers listen on all the IP addresses of the machine. This may be useful if the  
604 - machine has several network interfaces.  
605 -  
606 - 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec'  
607 - loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server  
608 - certificate. This is due to a problem of conception of SSL itself. See the book 'SSL  
609 - and TLS' by Eric Rescorla (at Addison Wesley) for more explanations.  
610 -  
611 - Notice that the number of servers is always 2, regardless of the number of web sites  
612 - you are starting.  
613 -  
614 - The dynamic variable 'shutdown_required' may be used to control the shutdown of the two  
615 - servers from within the web site (typically the administration part). The servers will  
616 - shutdown as soon as this variable contains 'true'. So you must provide a variable  
617 - containing 'false' otherwise your servers will not run. You may also use the primitive  
618 - 'must_restart' (see 'predefined.anubis') to control the restarting of your servers.  
619 -  
620 -  
621 -  
622 -  
623 -  
624 -  
625 - * (3) The HTML interface.  
626 -  
627 - We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination  
628 - of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more  
629 - reactive and attractive on the client side.  
630 -  
631 -  
632 - ** (3.1) Types used by the HTML interface.  
633 -  
634 - For easy reference, we gather below the definitions of all the types used by the HTML  
635 - interface, and we comment them immediately.  
636 -  
637 -  
638 -public type HTML_Size:  
639 - absolute(Int), // in pixels  
640 - percentage(Int).  
641 -  
642 -  
643 -public type Text_Option:  
644 - size(Int), // size of character font to use  
645 - font(String), // name of character font to use (such as "helvetica",...)  
646 - color(RGB), // color to be used for characters  
647 - italic,  
648 - oblique,  
649 - small_capitals,  
650 - bold,  
651 - underlined,  
652 - left_justified,  
653 - right_justified,  
654 - justified, // justified on both sides  
655 - line_through,  
656 - nowrap,  
657 - class(String), //CSS class  
658 - id(String),  
659 - style(String),  
660 - title(String),  
661 - attr(String, String).  
662 -  
663 -public define Text_Option  
664 - tooltip(String s) = title(s).  
665 -  
666 - A list of 'Text_Option' must be given with each text you want to put in your page.  
667 -  
668 - This indicate the way of reading text.  
669 -public type Reading_Way:  
670 - ltr, //the text is readable from "Left To Right" like english  
671 - rtl. //the text is readable from "Right To Left" like arabic  
672 -  
673 -  
674 -// Following types are define to prohib any arguments order error  
675 -  
676 -/**  
677 - * String value for 'id' attribut  
678 - */  
679 -public type HtmlId:  
680 - htmlId(String id).  
681 -  
682 -/**  
683 - * String value for 'class' attribut  
684 - */  
685 -public type HtmlClass:  
686 - htmlClass(String class).  
687 -  
688 -/**  
689 - * Name used in arguments list when form is submitted.  
690 - */  
691 -public type WebArgName:  
692 - wan(String name).  
693 -  
694 -/**  
695 - * Value passed to arguments list when form is submitted (for RadioButton and CheckBox).  
696 - */  
697 -public type WebArgValue:  
698 - wav(String value).  
699 -  
700 -/**  
701 - * Initial value of an input field.  
702 - */  
703 -public type InitialValue:  
704 - init(String value).  
705 -  
706 -public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y).  
707 -public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y).  
708 -public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y).  
709 -public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y).  
710 -public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y).  
711 -  
712 -  
713 -public type HtmlEvents:  
714 - // Form element events  
715 - onchange,  
716 - onsubmit,  
717 - onreset,  
718 - onselect,  
719 - onblur,  
720 - onfocus,  
721 - // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)  
722 - onkeydown,  
723 - onkeypress,  
724 - onkeyup,  
725 - // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)  
726 - onclick,  
727 - ondblclick,  
728 - onmousedown,  
729 - onmousemove,  
730 - onmouseout,  
731 - onmouseover,  
732 - onmouseup.  
733 -  
734 -public type CoreAttrs:  
735 - id (String),  
736 - class (String),  
737 - style (String),  
738 - title (String),  
739 - lang (String),  
740 - dir (Reading_Way),  
741 - accesskey (Word8),  
742 - tabindex (Int),  
743 - attr (String, String),  
744 - event (HtmlEvents, String).  
745 -  
746 -public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").  
747 -  
748 -public type InputAttrs:  
749 - class (String),  
750 - style (String),  
751 - title (String),  
752 - lang (String),  
753 - dir (Reading_Way),  
754 - accesskey (Word8),  
755 - tabindex (Int),  
756 - attr (String, String),  
757 - event (HtmlEvents, String).  
758 -  
759 -public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").  
760 -  
761 -public define CoreAttrs  
762 - tooltip(String s) = title(s).  
763 -public define InputAttrs  
764 - tooltip(String s) = title(s).  
765 -  
766 -public type I18n:  
767 - lang (String),  
768 - dir (Reading_Way).  
769 -  
770 -//public type DIV_Option:  
771 -// id (String),  
772 -// class (String),  
773 -// style (String),  
774 -// tooltip (String),  
775 -// lang (String),  
776 -// dir (Reading_Way),  
777 -// attr (String, String),  
778 -// event (HtmlEvents, String).  
779 -//  
780 -  
781 - A list of 'DIV_Option' must be given with each DIV you want to put in your page.  
782 -  
783 -define String event_name  
784 - (  
785 - HtmlEvents e  
786 - ) =  
787 - if e is  
788 - {  
789 - // Form element events  
790 - onchange then "onchange",  
791 - onsubmit then "onsubmit",  
792 - onreset then "onreset",  
793 - onselect then "onselect",  
794 - onblur then "onblur",  
795 - onfocus then "onfocus",  
796 - // Keyboard events  
797 - onkeydown then "onkeydown",  
798 - onkeypress then "onkeypress",  
799 - onkeyup then "onkeyup",  
800 - // Mouse events  
801 - onclick then "onclick",  
802 - ondblclick then "ondblclick",  
803 - onmousedown then "onmousedown",  
804 - onmousemove then "onmousemove",  
805 - onmouseout then "onmouseout",  
806 - onmouseover then "onmouseover",  
807 - onmouseup then "onmouseup"  
808 - }.  
809 -  
810 -public type Table_Option:  
811 - background_color(RGB), // applied to all cells in the table  
812 - background_image(String url),  
813 - border(Int width_of_outer_edge, // if not present, all values are 0  
814 - Int width_of_top_of_relief,  
815 - Int width_of_inner_edge,  
816 - RGB border_color),  
817 - width(Int), // sets a minimal width for the table  
818 - percentage_width(Int),  
819 - attr(String name, String value),  
820 - class(String class_name).  
821 -  
822 -  
823 -public define Table_Option nude = border(0,0,0,rgb(0,0,0)).  
824 -  
825 -  
826 - A list of 'Table_Option' must be given with each table.  
827 -  
828 -  
829 -public type BackgroundOption:  
830 - repeat, // repeat the background in both directions  
831 - repeat_horizontal, // repeat the background only horizontally  
832 - repeat_vertical, // repeat the background only verticall  
833 - no_repeat, // don't repeat the background  
834 - center.  
835 -  
836 -  
837 -public type Cell_Option:  
838 - core_attrs(List(CoreAttrs)),  
839 - left, // put the content of the cell on the left  
840 - h_center, // center the content of the cell horizontally  
841 - right, // put the content of the cell on the right  
842 - top, // put the content of the cell upwards  
843 - v_center, // center the content of tye cell vertically,  
844 - bottom, // put the content of the cell downwards  
845 - base_line, // align the content vertically according to base lines  
846 - background_color(RGB),  
847 - background_image(String url, BackgroundOption),  
848 - width(Int), // sets a minimal width for the cell  
849 - percentage_width(Int),  
850 - height(Int), // sets a minimal height for the cell  
851 - columns(Int), // lets the cell span over several columns  
852 - rows(Int), // lets the cell span over several rows  
853 - nowrap, // do not allow text wrapping within the cell  
854 - class(String class_name).  
855 -  
856 - A list of 'Cell_Option' must be given with each cell and each row in a table. Options  
857 - given with a row apply to all the cells in the row, but are superseded by options given  
858 - with cells, which apply only to the cell they are given with.  
859 -  
860 -  
861 -public type HTML_Cell($T):  
862 - cell(List(Cell_Option) options, $T content).  
863 -  
864 -public type HTML_Header_Cell($T):  
865 - header_cell(List(Cell_Option) options, $T content).  
866 -  
867 - The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form',  
868 - depending on where you put your table (within a form or not within a form). For your  
869 - convenience, we define the following particular case:  
870 -  
871 -public define HTML_Cell($T)  
872 - cell  
873 - (  
874 - $T content  
875 - ) =  
876 - cell([],content).  
877 -  
878 -public define HTML_Header_Cell($T)  
879 - header_cell  
880 - (  
881 - $T content  
882 - ) =  
883 - header_cell([],content).  
884 -  
885 -  
886 -public type HTML_Row($T):  
887 - row(List(Cell_Option) options, List(HTML_Cell($T)) cells).  
888 -  
889 -public type HTML_Header_Row($T):  
890 - empty,  
891 - header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells).  
892 -  
893 -public type HTML_Footer_Row($T):  
894 - empty,  
895 - footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells).  
896 -  
897 - Same remark as for 'HTML_Cell($T)'. We define several convenience functions:  
898 -  
899 -public define HTML_Row($T)  
900 - row  
901 - (  
902 - List(HTML_Cell($T)) cells  
903 - ) =  
904 - row([],cells).  
905 -  
906 -public define HTML_Row($T)  
907 - row  
908 - (  
909 - HTML_Cell($T) cell  
910 - ) =  
911 - row([],[cell]).  
912 -  
913 -public define HTML_Header_Row($T)  
914 - header_row  
915 - (  
916 - List(HTML_Header_Cell($T)) cells  
917 - ) =  
918 - header_row([],cells).  
919 -  
920 -public define HTML_Header_Row($T)  
921 - header_row  
922 - (  
923 - HTML_Header_Cell($T) cell  
924 - ) =  
925 - header_row([],[cell]).  
926 -  
927 -public type Actioner_Connection:  
928 - same, // use same type of connection as current page  
929 - http, // use non secured connection  
930 - https. // use secured connection  
931 -  
932 -public type Other_Window_Option:  
933 - resizable, // the new window may be resized by the client  
934 - scrollbars, // the new window has scrollbars  
935 - width(Int), // the new window has the specified width  
936 - height(Int). // the new window has the specified height  
937 -  
938 -public type Actioner_Target:  
939 - same,  
940 - same (String label),  
941 - other(String window_name, List(Other_Window_Option)).  
942 -  
943 -public type Actioner_Aspect:  
944 - link (List(Text_Option), String text, Maybe(String) name),// hypertext link  
945 - img_link (String img_url, String alt_text),  
946 - push_button (List(CoreAttrs),String text),  
947 - button (String url_off, String url_on), // rollover button  
948 - button (String url_off, String url_on, Int w, Int h), // idem with size  
949 - submit (List(CoreAttrs),String text),  
950 - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices),  
951 - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected).  
952 -  
953 -  
954 -  
955 -public type Actioner_Local_Action:  
956 - close_window.  
957 -  
958 -  
959 -public define Actioner_Aspect  
960 - link  
961 - (  
962 - List(Text_Option) options,  
963 - String text  
964 - ) =  
965 - link(options, text, failure).  
966 -  
967 -public define Actioner_Aspect  
968 - link  
969 - (  
970 - String text  
971 - ) =  
972 - link([], text, failure).  
973 -  
974 -  
975 -public define Actioner_Aspect  
976 - link  
977 - (  
978 - List(Text_Option) options,  
979 - Int i  
980 - ) =  
981 - link(options,to_decimal(i), failure).  
982 -  
983 -public define Actioner_Aspect  
984 - link  
985 - (  
986 - Int i  
987 - ) =  
988 - link([], i).  
989 -  
990 -public define Actioner_Aspect  
991 - button  
992 - (  
993 - String url_img  
994 - ) =  
995 - button(url_img,url_img).  
996 -  
997 - Actioners are explained in details below.  
998 -  
999 -  
1000 -public type TextAreaOption:  
1001 - input_attrs(List(InputAttrs)),  
1002 - disabled,  
1003 - read_only,  
1004 - wrap_lines.  
1005 -  
1006 -public type CSS_Style:  
1007 - text_options(List(Text_Option)).  
1008 -  
1009 -public type CSS_File:  
1010 - css_file(String file_name).  
1011 -  
1012 -public type JS_Attribute:  
1013 - attr (String, String).  
1014 -  
1015 -public type JS_File:  
1016 - js_file(String file_name,  
1017 - List(JS_Attribute) attributes).  
1018 -  
1019 -public type Script:  
1020 - script( String script_type,  
1021 - String content).  
1022 -  
1023 -public define JS_File  
1024 - js_file  
1025 - (  
1026 - String file_name  
1027 - ) =  
1028 - js_file(file_name, []).  
1029 -  
1030 -public type HTML_Meta:...  
1031 -  
1032 -public type HTML_Off_Form:...  
1033 -  
1034 -public type HTML_Head_Tag:  
1035 - meta(HTML_Meta),  
1036 - title(String),  
1037 - js(JS_File),  
1038 - js_inline(Script),  
1039 - css(CSS_File),  
1040 - css_inline(String css_styles) /* Note: <style> and </style> tags are not necessaries */  
1041 - .  
1042 -  
1043 - /* It contains  
1044 - * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ...  
1045 - * - a HTML_Off_Form representing the HTML code for the part of the page we want to display  
1046 - */  
1047 -public type HTML_Partial_Content:  
1048 - partial_content  
1049 - (  
1050 - List(HTML_Head_Tag),  
1051 - HTML_Off_Form  
1052 - )  
1053 - .  
1054 -  
1055 -  
1056 -public define List(HTML_Head_Tag)  
1057 - to_HTML_Head_Tag  
1058 - (  
1059 - List(CSS_File) css_file_list  
1060 - )=  
1061 - map((CSS_File css_f) |-> css(css_f), css_file_list).  
1062 -  
1063 -public define List(HTML_Head_Tag)  
1064 - to_HTML_Head_Tag  
1065 - (  
1066 - List(JS_File) js_file_list  
1067 - )=  
1068 - map((JS_File js_f) |-> js(js_f), js_file_list).  
1069 -  
1070 -public type HTML_In_Form:  
1071 - literal_pt (Printable_tree),  
1072 - literal (String),  
1073 - sequence (List(HTML_In_Form) items),  
1074 - text (List(Text_Option), String the_text),  
1075 - preformated (List(Text_Option), String),  
1076 - paragraph (List(Text_Option), HTML_In_Form content),  
1077 - image (List(CoreAttrs), String url, String alternate),  
1078 - image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
1079 - table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)),  
1080 - center (HTML_In_Form),  
1081 - mail_to (String email, HTML_In_Form element),  
1082 - scroller (Int width, Int height,  
1083 - Int content_width, Int content_height,  
1084 - HTML_In_Form content),  
1085 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1086 - String action_name, List((String,String)) extra_ops,  
1087 - List(Actioner_Local_Action)),  
1088 - foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
1089 - foreign_link (List(Text_Option), String url),  
1090 - foreign_link (List(Text_Option), String url, String name),  
1091 - private_download (String abs_path, String name, String extra_ext,  
1092 - Maybe((String,List((String,String)))) action),  
1093 - text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1094 - text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1095 - password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1096 - text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height),  
1097 - file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width),  
1098 - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices),  
1099 - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected),  
1100 - // List((String,String)) = List((code,name)) where :  
1101 - // code is the web-arg value  
1102 - // name appears in selector  
1103 - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices),  
1104 - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected),  
1105 - radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1106 - radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1107 - check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1108 - check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1109 - div (List(CoreAttrs), HTML_In_Form content),  
1110 - div_empty (List(CoreAttrs)),  
1111 - hidden (HtmlId id, WebArgName name, InitialValue init).  
1112 -  
1113 -  
1114 - 'HTML_In_Form' defines all the elements you may put within a form. We define a  
1115 - convenience function:  
1116 -  
1117 -public define HTML_In_Form literal(Printable_tree t) = literal_pt(t).  
1118 -  
1119 -public define HTML_In_Form image(String url) = image([], url, url).  
1120 -  
1121 -public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height).  
1122 -  
1123 -public define HTML_In_Form  
1124 - foreign_link  
1125 - (  
1126 - Int tsize,  
1127 - String url,  
1128 - String name  
1129 - ) =  
1130 - foreign_link([size(tsize)],url,name).  
1131 -  
1132 -public define HTML_In_Form  
1133 - actioner  
1134 - (  
1135 - Actioner_Connection conn,  
1136 - Actioner_Target targ,  
1137 - Actioner_Aspect asp,  
1138 - String action_name,  
1139 - List((String,String)) extra_ops  
1140 - ) =  
1141 - actioner(conn,targ,asp,action_name,extra_ops,[]).  
1142 -  
1143 -public define HTML_In_Form  
1144 - actioner  
1145 - (  
1146 - Actioner_Connection conn,  
1147 - Actioner_Target targ,  
1148 - Actioner_Aspect asp,  
1149 - ) =  
1150 - actioner(conn, targ, asp, "", [], []).  
1151 -  
1152 -  
1153 -public define HTML_In_Form  
1154 - text_area  
1155 - (  
1156 - WebArgName name,  
1157 - InitialValue init,  
1158 - Int width,  
1159 - Int height  
1160 - ) =  
1161 - text_area([], "", htmlId(""), name,init,width,height).  
1162 -  
1163 -public define HTML_In_Form  
1164 - text_area  
1165 - (  
1166 - List(TextAreaOption) options,  
1167 - WebArgName name,  
1168 - InitialValue init,  
1169 - Int width,  
1170 - Int height  
1171 - ) =  
1172 - text_area(options, "", htmlId(""), name,init,width,height).  
1173 -  
1174 -public define HTML_In_Form  
1175 - table  
1176 - (  
1177 - List(HTML_Row(HTML_In_Form)) rows  
1178 - ) =  
1179 - table([],empty,rows,empty).  
1180 -  
1181 -public define HTML_In_Form  
1182 - table  
1183 - (  
1184 - List(Table_Option) options,  
1185 - List(HTML_Row(HTML_In_Form)) rows  
1186 - ) =  
1187 - table(options,empty,rows,empty).  
1188 -  
1189 -public define HTML_In_Form  
1190 - table  
1191 - (  
1192 - HTML_Header_Row(HTML_In_Form) h_row,  
1193 - List(HTML_Row(HTML_In_Form)) rows  
1194 - ) =  
1195 - table([],h_row,rows,empty).  
1196 -  
1197 -public define HTML_In_Form  
1198 - table  
1199 - (  
1200 - List(Table_Option) options,  
1201 - HTML_Header_Row(HTML_In_Form) h_row,  
1202 - List(HTML_Row(HTML_In_Form)) rows  
1203 - ) =  
1204 - table(options,h_row,rows,empty).  
1205 -  
1206 -public define HTML_In_Form  
1207 - private_download  
1208 - (  
1209 - String abs_path,  
1210 - String name,  
1211 - String extra_ext  
1212 - ) =  
1213 - private_download(abs_path,name,extra_ext,failure).  
1214 -  
1215 -public define HTML_In_Form  
1216 - private_download  
1217 - (  
1218 - String abs_path,  
1219 - String name,  
1220 - String extra_ext,  
1221 - String action_name,  
1222 - List((String,String)) args  
1223 - ) =  
1224 - private_download(abs_path,name,extra_ext,success((action_name,args))).  
1225 -  
1226 -public define HTML_In_Form  
1227 - text  
1228 - (  
1229 - String s  
1230 - ) =  
1231 - text([],s).  
1232 -  
1233 -public define HTML_In_Form  
1234 - radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1235 - = radio_button (options, label_text, htmlId(n.name), n, value, checked).  
1236 -  
1237 -public define HTML_In_Form  
1238 - radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1239 - = radio_button_r (options, label_text, htmlId(n.name), n, value, checked).  
1240 -  
1241 -public define HTML_In_Form  
1242 - check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1243 - = check_box (options, label_text, htmlId(n.name), n, value, checked).  
1244 -  
1245 -public define HTML_In_Form  
1246 - check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1247 - = check_box_r (options, label_text, htmlId(n.name), n, value, checked).  
1248 -  
1249 -public define HTML_In_Form  
1250 - file_upload (WebArgName name, Int width)  
1251 - = file_upload([], "", htmlId(""), name, width).  
1252 -  
1253 -public define HTML_In_Form  
1254 - hidden (WebArgName name, InitialValue init)  
1255 - = if name is wan(web_name) then  
1256 - hidden(htmlId(web_name), name, init).  
1257 -  
1258 -public type HTML_Body:...  
1259 -  
1260 -public type HTML_Off_Form:  
1261 - literal_pt (Printable_tree),  
1262 - literal (String),  
1263 - sequence (List(HTML_Off_Form) items),  
1264 - text (List(Text_Option), String the_text),  
1265 - preformated (List(Text_Option), String),  
1266 - paragraph (List(Text_Option), HTML_Off_Form content),  
1267 - image (List(CoreAttrs), String url, String alternate),  
1268 - image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
1269 - table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)),  
1270 - center (HTML_Off_Form),  
1271 - mail_to (String email, HTML_Off_Form element),  
1272 - scroller (Int width, Int height,  
1273 - Int content_width, Int content_height,  
1274 - HTML_Off_Form content),  
1275 - fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content),  
1276 - fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),  
1277 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1278 - String action_name, List((String,String)) extra_ops,  
1279 - List(Actioner_Local_Action)),  
1280 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1281 - String action_name, List((String,String)) extra_ops,  
1282 - List(Actioner_Local_Action), String form_name),  
1283 - foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
1284 - foreign_link (List(Text_Option), String url),  
1285 - foreign_link (List(Text_Option), String url, String name),  
1286 - private_download (String abs_path, String name, String extra_ext,  
1287 - Maybe((String,List((String,String)))) action),  
1288 - label (String name),  
1289 - form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content),  
1290 - form (HtmlId form_id, List(CoreAttrs),  
1291 - String action_name, List((String,String)) extra_ops,  
1292 - HTML_In_Form content),  
1293 - div (List(CoreAttrs), HTML_Off_Form content),  
1294 - div_empty (List(CoreAttrs)),  
1295 - iframe (List(CoreAttrs),  
1296 - List(CSS_Style) /*styles*/,  
1297 - List(CSS_File) /*css_files*/,  
1298 - List(JS_File) /*js_files*/,  
1299 - HTML_Body /*body*/).  
1300 -  
1301 - 'HTML_Off_Form' defines all the elements you may put outside any form.  
1302 -  
1303 -  
1304 -public define HTML_Off_Form image(String url) = image([], url, url).  
1305 -  
1306 -public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height).  
1307 -  
1308 -public define HTML_Off_Form  
1309 - form  
1310 - (  
1311 - String form_name,  
1312 - List(CoreAttrs) options,  
1313 - HTML_In_Form content  
1314 - ) =  
1315 - form(htmlId(form_name), options, content).  
1316 -  
1317 -public define HTML_Off_Form  
1318 - form  
1319 - (  
1320 - String form_name,  
1321 - List(CoreAttrs) options,  
1322 - String action_name,  
1323 - List((String,String)) extra_ops,  
1324 - HTML_In_Form content  
1325 - ) =  
1326 - form(htmlId(form_name), options, action_name, extra_ops, content).  
1327 -  
1328 -  
1329 -public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t).  
1330 -public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file)  
1331 - = fixed_size_2(width,height,name_of_HTML_file).  
1332 -  
1333 -  
1334 -public define HTML_Off_Form  
1335 - foreign_link  
1336 - (  
1337 - Int tsize,  
1338 - String url,  
1339 - String name  
1340 - ) =  
1341 - foreign_link([size(tsize)],url,name).  
1342 -  
1343 -  
1344 -public define HTML_Off_Form  
1345 - actioner  
1346 - (  
1347 - Actioner_Connection conn,  
1348 - Actioner_Target targ,  
1349 - Actioner_Aspect asp,  
1350 - String action_name,  
1351 - List((String,String)) extra_ops  
1352 - ) =  
1353 - actioner(conn,targ,asp,action_name,extra_ops,[]).  
1354 -  
1355 -public define HTML_Off_Form  
1356 - table  
1357 - (  
1358 - List(HTML_Row(HTML_Off_Form)) rows  
1359 - ) =  
1360 - table([],empty,rows,empty).  
1361 -  
1362 -public define HTML_Off_Form  
1363 - table  
1364 - (  
1365 - List(Table_Option) options,  
1366 - List(HTML_Row(HTML_Off_Form)) rows  
1367 - ) =  
1368 - table(options,empty,rows,empty).  
1369 -  
1370 -public define HTML_Off_Form  
1371 - table  
1372 - (  
1373 - HTML_Header_Row(HTML_Off_Form) h_row,  
1374 - List(HTML_Row(HTML_Off_Form)) rows  
1375 - ) =  
1376 - table([],h_row,rows,empty).  
1377 -  
1378 -public define HTML_Off_Form  
1379 - table  
1380 - (  
1381 - List(Table_Option) options,  
1382 - HTML_Header_Row(HTML_Off_Form) h_row,  
1383 - List(HTML_Row(HTML_Off_Form)) rows  
1384 - ) =  
1385 - table(options,h_row,rows,empty).  
1386 -  
1387 - We add two convenience functions for 'row'. The reason why we add two functions, one  
1388 - for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an  
1389 - arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so,  
1390 - the arguments of the function do not refer to any of the types defined here.  
1391 -  
1392 -public define HTML_Row(HTML_In_Form)  
1393 - row  
1394 - (  
1395 - HTML_In_Form content  
1396 - ) =  
1397 - row([],[cell([],content)]).  
1398 -  
1399 -public define HTML_Row(HTML_Off_Form)  
1400 - row  
1401 - (  
1402 - HTML_Off_Form content  
1403 - ) =  
1404 - row([],[cell([],content)]).  
1405 -  
1406 -  
1407 -public define HTML_Off_Form  
1408 - private_download  
1409 - (  
1410 - String abs_path,  
1411 - String name,  
1412 - String extra_ext  
1413 - ) =  
1414 - private_download(abs_path,name,extra_ext,failure).  
1415 -  
1416 -  
1417 -public define HTML_Off_Form  
1418 - private_download  
1419 - (  
1420 - String abs_path,  
1421 - String name,  
1422 - String extra_ext,  
1423 - String action_name,  
1424 - List((String,String)) args  
1425 - ) =  
1426 - private_download(abs_path,name,extra_ext,success((action_name,args))).  
1427 -  
1428 -public define HTML_Off_Form  
1429 - text  
1430 - (  
1431 - List(Text_Option) lto,  
1432 - Int i  
1433 - ) =  
1434 - text(lto,to_decimal(i)).  
1435 -  
1436 -  
1437 -public define HTML_Off_Form  
1438 - text  
1439 - (  
1440 - Int i  
1441 - ) =  
1442 - text([],i).  
1443 -  
1444 -public define HTML_Off_Form  
1445 - text  
1446 - (  
1447 - String s  
1448 - ) =  
1449 - text([],s).  
1450 -  
1451 - - Cell a gap between two other cells :  
1452 -  
1453 -public define HTML_Cell(HTML_Off_Form)  
1454 - width_gap  
1455 - (  
1456 - Int w  
1457 - ) =  
1458 - cell([width(w)],text([],"")).  
1459 -  
1460 -public define HTML_Cell(HTML_In_Form)  
1461 - width_gap  
1462 - (  
1463 - Int w  
1464 - ) =  
1465 - cell([width(w)],text([],"")).  
1466 -  
1467 -  
1468 - - Row a gap between two other rows :  
1469 -  
1470 -public define HTML_Row(HTML_Off_Form)  
1471 - height_gap  
1472 - (  
1473 - Int h  
1474 - ) =  
1475 - row([],[cell([height(h)],text([],""))]).  
1476 -  
1477 -public define HTML_Row(HTML_In_Form)  
1478 - height_gap  
1479 - (  
1480 - Int h  
1481 - ) =  
1482 - row([],[cell([height(h)],text([],""))]).  
1483 -  
1484 -  
1485 - Notice that the two types have alternatives in common (same name, same arguments types,  
1486 - up to the value of the parameter $T), which correspond to elements which may be put  
1487 - anywhere in the page.  
1488 -  
1489 -  
1490 -public define HTML_Partial_Content  
1491 - partial_content  
1492 - (  
1493 - HTML_Off_Form content  
1494 - )=  
1495 - partial_content([], content).  
1496 -  
1497 -public define HTML_Partial_Content  
1498 - partial_content  
1499 - (  
1500 - List(HTML_Head_Tag) tags,  
1501 - HTML_Partial_Content p_content  
1502 - )=  
1503 - if p_content is partial_content(ptags, html) then  
1504 - partial_content(tags + ptags, html).  
1505 -  
1506 -define HTML_Partial_Content  
1507 - list_to_pcontent  
1508 - (  
1509 - List(HTML_Partial_Content) l_p_content,  
1510 - List(HTML_Head_Tag) so_far_tags,  
1511 - List(HTML_Off_Form) so_far_html  
1512 - )=  
1513 - if l_p_content is  
1514 - {  
1515 - [] then partial_content(so_far_tags, sequence(reverse(so_far_html))),  
1516 - [h . t] then  
1517 - //extract resurgent type and symbols of h  
1518 - if h is partial_content(tags, html) then  
1519 - list_to_pcontent(t, so_far_tags + tags, [html . so_far_html])  
1520 - }.  
1521 -  
1522 -public define HTML_Partial_Content  
1523 - partial_content  
1524 - (  
1525 - List(HTML_Partial_Content) l_p_content  
1526 - )=  
1527 - list_to_pcontent(l_p_content, [], []).  
1528 -  
1529 -  
1530 -  
1531 -define String  
1532 - format  
1533 - (  
1534 - List(Text_Option) l  
1535 - ).  
1536 -  
1537 -  
1538 -  
1539 -  
1540 -define Printable_tree  
1541 - format_css_styles  
1542 - (  
1543 - List(CSS_Style) l  
1544 - ) =  
1545 - if l is  
1546 - {  
1547 - [ ] then [ ],  
1548 - [h . t] then  
1549 - [ if h is  
1550 - {  
1551 - text_options(tos) then  
1552 - [" body, span, p { ", format(tos), " }\n" ]  
1553 - }  
1554 - . format_css_styles(t)]  
1555 - }.  
1556 -  
1557 -  
1558 -  
1559 -public type HTML_Meta:  
1560 - keywords (List(String)),  
1561 - refresh (Actioner_Connection connection,  
1562 - Actioner_Target target,  
1563 - String action_name,  
1564 - Int delay), // in seconds  
1565 - refresh (String url, Int delay), // in seconds  
1566 - meta (String name, String content),  
1567 - http_equiv (String name, String content),  
1568 - generic_meta (List((String,String))),  
1569 - literal (String).  
1570 -  
1571 - Meta tags are put in the 'head' of the HTML page.  
1572 -  
1573 -  
1574 -public type Body_Option:  
1575 - core_attrs(List(CoreAttrs)),  
1576 - background_color (RGB),  
1577 - background_image (String url),  
1578 - background_image (String url, List(BackgroundOption)).  
1579 -  
1580 -public type HTML_Body:  
1581 - body(List(Body_Option) options, HTML_Off_Form content).  
1582 -  
1583 -  
1584 -public type HTTP_Answer:  
1585 - html_page (HTTP_Status /*http_status*/,  
1586 - List(HTML_Head_Tag) /*html <head> tags*/,  
1587 - HTML_Body /*body*/),  
1588 - html_page (HTTP_Status /*http_status*/,  
1589 - String /*title*/,  
1590 - List(HTML_Meta) /*meta_tags*/,  
1591 - List(CSS_Style) /*styles*/,  
1592 - List(CSS_File) /*css_files*/,  
1593 - List(JS_File) /*js_files*/,  
1594 - List(Script) /*script*/,  
1595 - HTML_Body /*body*/),  
1596 - plain_text (HTTP_Status /*http_status*/,  
1597 - String /*text*/),  
1598 - custom_text (HTTP_Status /*http_status*/,  
1599 - String /*mime_type*/,  
1600 - String /*content*/),  
1601 - custom_binary(HTTP_Status /*http_status*/,  
1602 - String /*mime_type*/,  
1603 - ByteArray /*content*/,  
1604 - List(HTTP_header)/*other headers*/),  
1605 - custom_tree (HTTP_Status /*http_status*/,  
1606 - String /*mime_type*/,  
1607 - Printable_tree /*content*/),  
1608 - http_raw (Printable_tree),  
1609 - html_content (HTTP_Status /*http_status*/,  
1610 - HTML_Off_Form).  
1611 -  
1612 -  
1613 -public define HTTP_Answer  
1614 - html_page  
1615 - (  
1616 - String title,  
1617 - List(HTML_Meta) metas,  
1618 - HTML_Body body  
1619 - ) =  
1620 - html_page(http_ok, title,metas,[],[],[],[],body).  
1621 -  
1622 -public define HTTP_Answer  
1623 - html_page  
1624 - (  
1625 - String title,  
1626 - List(HTML_Meta) metas,  
1627 - List(CSS_Style) styles,  
1628 - HTML_Body body  
1629 - ) =  
1630 - html_page(http_ok, title, metas, styles, [], [], [], body).  
1631 -  
1632 - 'HTTP_Answer' represents the final product of the construction of a web page.  
1633 -  
1634 -  
1635 -  
1636 -  
1637 - *** (3.2) ``in form'' versus ``off form''.  
1638 -  
1639 - There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some  
1640 - of them may have a content, which is yet another HTML element (or several). Hence, it  
1641 - is meaningful to say that an element is 'within' another one. Now, putting any element  
1642 - within any other one may be meaningless. For example, an input element must be put  
1643 - within a form (otherwise, it is useless), and a from within another form has no precise  
1644 - meaning (and is forbidden by the HTML specification).  
1645 -  
1646 - Actually, the main criterium is ``within a form or not within a form''. So, HTML  
1647 - elements in a given page are separated into two categories: those who are within a  
1648 - form, and the others. Nevertheless, there are elements which may belong to both  
1649 - categories, like images and texts. We want to make use of the strong typing mecanism of  
1650 - Anubis in order to forbid non meaningful placement of elements.  
1651 -  
1652 - The type 'HTML_In_Form' defines elements to be put within forms. Similarly,  
1653 - 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive,  
1654 - and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course),  
1655 - but the two types are not cross recursive. This is the reason why it is impossible to  
1656 - put a form within a form. In order to construct a web page, you essentially have to  
1657 - produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form').  
1658 -  
1659 - In practice, you don't have to worry so much about these two types, because elements  
1660 - which may be put anywhere are constructed for both types by functions with the same  
1661 - name and the same arguments. Hence, for both types, you just write the same thing. You  
1662 - are warned by the compiler only when you try to put an element at a place it is not  
1663 - allowed.  
1664 -  
1665 -  
1666 -  
1667 - *** (3.3) Defining your own style.  
1668 -  
1669 - We provide generic tools for constructing HTML elements. However, your web site needs  
1670 - to have a ``style''.  
1671 -  
1672 - To that end, you need to write down a set of ``styling functions'', using the tools  
1673 - defined here. These styling functions allow the introduction of your colors and other  
1674 - visual characteristics into the constructed elements once and for all. For example, you  
1675 - may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using  
1676 - some 'text_color'. You may write something like this:  
1677 -  
1678 - define RGB text_color = rgb(10,40,40).  
1679 -  
1680 - define HTML_Off_Form  
1681 - text  
1682 - (  
1683 - String the_text  
1684 - ) =  
1685 - text([font("helvetica"),size(14),color(text_color)],  
1686 - the_text).  
1687 -  
1688 - (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a  
1689 - page, you just write:  
1690 -  
1691 - text("... some text ...")  
1692 -  
1693 - and you don't have to provide the font, size and color for each text. If you want to  
1694 - have several styles of text presentation, you just write several sets of such  
1695 - convenience functions. This also suggests a trick. You may want for example different  
1696 - colors for 'in form' texts and 'off form' texts. This may be achieved automatically by  
1697 - defining two functions as above, with the same name and same argument type, but  
1698 - returning either a 'HTML_In_Form' or a 'HTML_Off_Form'.  
1699 -  
1700 - If this preliminary work is well done, you will not waste your time later when you  
1701 - concentrate on the actual informational content of your pages.  
1702 -  
1703 - This general principle should be applied to all sorts of elements. This is the best  
1704 - thing to do in order to separate the functions defining the visual style from the  
1705 - functions defining the informational content itself, so that changing the style without  
1706 - changing the content becomes easy. This is also the best way for having a clean and  
1707 - easily readable source for your web site.  
1708 -  
1709 -  
1710 -  
1711 -  
1712 -  
1713 - *** (3.4) Actioners and forms.  
1714 -  
1715 - We have gathered several notions from HTML into that of an 'actioner'. An actioner is  
1716 - an HTML element which opens a connection to our server when clicked upon. Actioners may  
1717 - have different visual aspects. They may look like hypertext links or like buttons  
1718 - (rollovers), or even like selectors (with immediate action). In any case, their  
1719 - behavior is the same: they open a connection to our server, and send a set of 'web  
1720 - arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes  
1721 - the action to be performed, and the others should be considered as operands for this  
1722 - action. Actually, the precise behavior of the actioner has several variants.  
1723 -  
1724 - The connection with the server may be secured (HTTPS) or non secured (HTTP). See the  
1725 - type 'Actioner_Connection' above.  
1726 -  
1727 - You must also choose where the answer must be rendered. This may be in the same window  
1728 - or in another window (or frame). If it is in another window, the name of that window  
1729 - must be given. If the window does not exist, the browser will create it. Optionally,  
1730 - you may give the dimensions of the new window and other characteristics. See the type  
1731 - 'Actioner_Target' above.  
1732 -  
1733 - The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the  
1734 - case of a rollover button, you provide the URLs of two images (of the same size)  
1735 - representing the button:  
1736 -  
1737 - url_off: to be used when the mouse is not over the button,  
1738 - url_on: to be used when the mouse is over the button.  
1739 -  
1740 - You can also create rollover buttons without creating images. Just use the second  
1741 - alternative named 'button'. The server creates the images automatically.  
1742 -  
1743 - The purpose of forms is just to give operands to actioners. If the actioner is placed  
1744 - within a form, all the input elements which are within this form provide operands to  
1745 - the actioner (except sometimes when they are not set by the client). If it is not put  
1746 - within a form, the actioner gets no operand, except if the name of a form is explicitly  
1747 - given, in which case the actioner gets all the inputs from that form as  
1748 - operands. Furthermore, you may want to give extra operands to the actioner. This may be  
1749 - useful for separating families of actioners with the same action name. Extra operands  
1750 - 'name=value' must be given in the form of pairs '(name,value)'.  
1751 -  
1752 - Notice that the name of a form may be used by an actioner which is off the form, so as  
1753 - to get the operands provided by this form. Also notice that several actioners may refer  
1754 - to the same form, being either in the form, or referring to the form from the  
1755 - outside. These actioners simply get the same set of operands, even if they correspond  
1756 - to distinct actions.  
1757 -  
1758 - Input elements may be put only within a form.  
1759 -  
1760 -  
1761 -  
1762 - *** (3.5) Local popup.  
1763 -  
1764 - This element looks like a link or a rollover button. When this button is clicked upon,  
1765 - a 'popup window' appears. Actually, this popup window is just a layer in the same HTML  
1766 - page, which becomes suddenly visible. It is realized with a '<div>' HTML tag. In  
1767 - particular, clicking on the button does not open any connection. This is why it is  
1768 - called 'local'. The arguments have the following roles:  
1769 -  
1770 - Actioner_Aspect aspect of the button (same semantics as for actioners)  
1771 - content content of the popup window  
1772 - x, y, position of the popup window on the HTML page (not relative  
1773 - to the button but to the page itself)  
1774 - title title of the popup window  
1775 - color color of the title bar and close button in the popup window.  
1776 - A lightened version of this color is used for the background  
1777 - of the popup window.  
1778 - width width of the title bar  
1779 -  
1780 -  
1781 -  
1782 -  
1783 -  
1784 - --- That's all for the public part ! --------------------------------------------------  
1785 -  
1786 -  
1787 -  
1788 -  
1789 -  
1790 - ----------------------------------- Table of Contents ---------------------------------  
1791 -  
1792 - *** [1] States.  
1793 - *** [1.1] Saving and retrieving states.  
1794 - *** [1.2] Deleting out of date states.  
1795 -  
1796 - *** [2] Tools.  
1797 - *** [2.1] Directories.  
1798 - *** [2.2] Secondary documents.  
1799 -  
1800 - *** [3] Managing web arguments.  
1801 - *** [3.1] Prefixing web arguments names.  
1802 - *** [3.2] Separating web arguments.  
1803 - *** [3.3] Applying an action.  
1804 -  
1805 - *** [4] Web site descriptions and the 'awp handlers'.  
1806 - *** [4.1] The type 'Web_Site'.  
1807 - *** [4.2] Making a web site description.  
1808 - *** [4.3] Starting the servers.  
1809 -  
1810 - *** [5] HTML Formating.  
1811 - *** [5.1] The type 'HTML_Any($T)'.  
1812 - *** [5.2] Formating a color.  
1813 - *** [5.3] Creating buttons.  
1814 - *** [5.4] Formating an actioner.  
1815 - *** [5.5] Formating a private download link.  
1816 - *** [5.6] Formating rows and cells in a table.  
1817 - *** [5.7] Formating elements which may be put anywhere.  
1818 - *** [5.8] Formating 'in form' elements.  
1819 - *** [5.9] Formating 'off form' elements.  
1820 - *** [5.10] Formating meta-tags.  
1821 -  
1822 - ---------------------------------------------------------------------------------------  
1823 -  
1824 -  
1825 -  
1826 -  
1827 -public define String  
1828 - doctype_w3c_header  
1829 - =  
1830 - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "+  
1831 - "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".  
1832 -  
1833 -public define String  
1834 - html_header  
1835 - =  
1836 - "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n".  
1837 -  
1838 -  
1839 - *** [1] States.  
1840 -  
1841 - We have to define functions for saving a state, retrieving a state, deleting out of  
1842 - date states. We need one such function per web site. The types of the first two  
1843 - functions depend on the parameter $State. This is not the case of the third one. The  
1844 - fact that the instance of $State is variable from one web sites to the other implies  
1845 - rather subtle manipulations using full functionality.  
1846 -  
1847 -  
1848 - *** [1.1] Saving and retrieving states.  
1849 -  
1850 - Each state is saved into a file on the server's disk (in the directory represented by  
1851 - the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The  
1852 - state is saved together with a time stamp whose value is obtained by adding the current  
1853 - time to the given timeout for states. The state receives a name obtained by hashing  
1854 - (using sha1) the content of the file itself, and then encoding the hash with  
1855 - 'web_arg_encode'. The name of the file into which the state is saved is the  
1856 - concatenation of "s" and the name of the state.  
1857 -  
1858 -read CXM_web_arg_encode.anubis  
1859 -  
1860 - The tool below constructs the function which is able to save a state on the server's  
1861 - disk.  
1862 -  
1863 -define ($State s) -> String // the function constructed returns the name of the state  
1864 - make_save_state_function  
1865 - (  
1866 - Int timeout,  
1867 - String state_directory  
1868 - ) =  
1869 - ($State s) |->  
1870 - with time_stamp = now+timeout,  
1871 - to_be_saved = (time_stamp,s),  
1872 - state_name = web_arg_encode(sha1(s)),  
1873 - if save(to_be_saved,state_directory+"/s"+state_name) is ok  
1874 - then state_name  
1875 - else (print("Cannot create state file in '"+state_directory+"'.\n"); "").  
1876 -  
1877 -  
1878 - When a request arrives, we need to retrieve the previous state from the server's  
1879 - disk. We receive the name of that state. If the state is out of date, the state file is  
1880 - kept 3 days, and then deleted.  
1881 -  
1882 -type PreviousState($State):  
1883 - not_found, // cannot retrieve the previous state  
1884 - out_of_date($State), // the previous state is out of date  
1885 - still_valid($State). // the previous state is still valid  
1886 -  
1887 -define (String state_name) -> PreviousState($State)  
1888 - make_retrieve_state_function  
1889 - (  
1890 - String state_directory  
1891 - ) =  
1892 - (String state_name) |->  
1893 - with file_path = state_directory+"/s"+state_name,  
1894 - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)  
1895 - then (  
1896 - if d is (time_stamp,s) then  
1897 - if time_stamp < now  
1898 - then (  
1899 - forget(remove(file_path));  
1900 - out_of_date(s)  
1901 - )  
1902 - else still_valid(s) // state has been successfully retrieved  
1903 - )  
1904 - else not_found.  
1905 -  
1906 -  
1907 -  
1908 - *** [1.2] Deleting out of date states.  
1909 -  
1910 - We also need to delete states which are out of date and which will never be deleted by  
1911 - the above method. This may be performed by a machine doing this periodically (say once  
1912 - per states life time period).  
1913 -  
1914 -define (List(String) file_names) -> One  
1915 - make_delete_out_of_date_states_function  
1916 - (  
1917 - Maybe($State) dummy,  
1918 - String state_directory  
1919 - ) =  
1920 - (List(String) file_names) |-df->  
1921 - if file_names is  
1922 - {  
1923 - [ ] then unique,  
1924 - [h . t] then  
1925 - with file_path = state_directory+"/"+h,  
1926 - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)  
1927 - then (  
1928 - if d is (time_stamp,data) then  
1929 - if time_stamp < now  
1930 - then (forget(remove(file_path)); df(t))  
1931 - else df(t)  
1932 - )  
1933 - else (forget(remove(file_path)); df(t))  
1934 - }.  
1935 -  
1936 -  
1937 - The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'.  
1938 -  
1939 - Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the  
1940 - function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler  
1941 - does not accept a parameter in the body of a function (here the parameter is required  
1942 - by the use of 'retrieve') if this parameter does not appear in the type of the  
1943 - function. This is because this would create ambiguities that no explicit typing may  
1944 - ever resolve. If you put a double slash in front of the declaration of 'dummy' above,  
1945 - and if you compile this file, you will get a message like this one:  
1946 -  
1947 - Error in 'making_a_web_site.anubis', line 1300, column 7:  
1948 - A definition may not contain parameters which are not present  
1949 - in the declaration part (hidden parameters):  
1950 - $State  
1951 -  
1952 - The type of the function constructed by 'make_delete_out_of_date_states_function' is  
1953 - independant of the parameter $State. This is important because this allows to create  
1954 - the list of such functions for all web sites. From this list, it is possible to call  
1955 - the functions one after the other, so deleting out of date states for all web  
1956 - sites. Actually, the next function receives a list of pairs (state_directory,function),  
1957 - one for each web site.  
1958 -  
1959 -define One  
1960 - delete_out_of_date_states // for all web sites  
1961 - (  
1962 - List((String, List(String) -> One)) directories_and_functions  
1963 - ) =  
1964 - if directories_and_functions is  
1965 - {  
1966 - [ ] then unique,  
1967 - [h . t] then if h is (state_directory,function) then  
1968 - function(directory_list(state_directory,"s*"));  
1969 - delete_out_of_date_states(t)  
1970 - }.  
1971 -  
1972 -  
1973 - The above function must be called periodically in a separate virtual machine. The  
1974 - period we have choosen is (rather logically) the life time of states itself. This may  
1975 - be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not  
1976 - be really infinite, because the servers may be shutdown. Hence, our loop must test  
1977 - (rather frequently; say every second) if the servers are down. If they are, the loop  
1978 - must be exited.  
1979 -  
1980 -define One  
1981 - delete_states_loop  
1982 - (  
1983 - List((String,List(String) -> One)) directories_and_functions,  
1984 - Int timeout,  
1985 - Int next_time,  
1986 - Server http_server,  
1987 - Server https_server,  
1988 - (One) -> Bool shutdown_required  
1989 - ) =  
1990 - if shutdown_required(unique)  
1991 - then (shutdown(http_server); shutdown(https_server))  
1992 - else unique;  
1993 - if (is_down(http_server) & is_down(https_server))  
1994 - then unique  
1995 - else if now > next_time  
1996 - then  
1997 - (  
1998 - delete_out_of_date_states(directories_and_functions);  
1999 - delete_states_loop(directories_and_functions,  
2000 - timeout,  
2001 - now+timeout,  
2002 - http_server,  
2003 - https_server,  
2004 - shutdown_required)  
2005 - )  
2006 - else  
2007 - (  
2008 - sleep(1000); // sleep just one second and try again  
2009 - delete_states_loop(directories_and_functions,  
2010 - timeout,  
2011 - next_time,  
2012 - http_server,  
2013 - https_server,  
2014 - shutdown_required)  
2015 - ).  
2016 -  
2017 - The above loop must be run in a separate virtual machine. This will be done just after  
2018 - the two servers are started.  
2019 -  
2020 -  
2021 -  
2022 -  
2023 -  
2024 - *** [2] Tools.  
2025 -  
2026 - *** [2.1] Directories.  
2027 -  
2028 - We need a tool for creating directories (if needed).  
2029 -  
2030 - (This tool has been moved to 'tools/basis.anubis').  
2031 -  
2032 -  
2033 -  
2034 -  
2035 - *** [2.2] Secondary documents.  
2036 -  
2037 - Some HTML elements (like '<object>', '<frame>') cannot receive their content directly  
2038 - from the current document, but only through an URL. For this reason, we implement a  
2039 - mecanism for creating secondary documents on the fly. To that end we use the 'private  
2040 - download' mecanism.  
2041 -  
2042 - A secondary document is formated by the same functions as the main document itself. The  
2043 - next function takes an 'off form' element, creates the file containing the secondary  
2044 - document in HTML format, and returns the URL at which the document will be available.  
2045 -  
2046 -define String  
2047 - create_secondary_document  
2048 - (  
2049 - String sd, // site directory  
2050 - String as, // authorization_secret  
2051 - String sn, // state name  
2052 - $T -> Printable_tree format_element,  
2053 - $T content,  
2054 - HTML_Size width  
2055 - ) =  
2056 - with private_download_directory = sd+"/private_download",  
2057 - hash = web_arg_encode(sha1(content)),  
2058 - file_content = (Printable_tree)  
2059 - [doctype_w3c_header,  
2060 - "<html><body><table ",  
2061 - if width is  
2062 - {  
2063 - absolute(w) then ["width=\"",w-25],  
2064 - percentage(w) then ["width=\"95%\""]  
2065 - },"\"><tbody><tr><td align=right>",  
2066 - format_element(content),  
2067 - "</td></tr></tbody></table></body></html>"  
2068 - ],  
2069 - file_name = "sd"+hash+".html",  
2070 - file_path = private_download_directory+"/"+file_name,  
2071 - if write_to_file(file_path,file_content) is  
2072 - {  
2073 - cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "",  
2074 - write_error(n) then print("Error writing file '"+file_path+"'.\n"); "",  
2075 - ok then file_name+"?zauth="+  
2076 - make_authorization(sd,as,private_download_directory+"/"+file_name)  
2077 - }.  
2078 -  
2079 -  
2080 -  
2081 -  
2082 - *** [2.3] Generating unique ids.  
2083 -  
2084 - In order to uniquely name object for JavaScript we generate unique ids from a counter.  
2085 -  
2086 -define Int  
2087 - new_idnum  
2088 - (  
2089 - Var(Int) ic_v // 'idnum' counter variable  
2090 - ) =  
2091 - protect  
2092 - with result = *ic_v+1,  
2093 - ic_v <- result;  
2094 - result.  
2095 -  
2096 -  
2097 -  
2098 -  
2099 -  
2100 -  
2101 - *** [3] Managing web arguments.  
2102 -  
2103 - Web arguments are those pairs 'name=value' which are transmitted through the HTTP  
2104 - protocol. We need precise naming conventions for these web arguments.  
2105 -  
2106 -  
2107 -  
2108 - *** [3.1] Prefixing web arguments names.  
2109 -  
2110 - CR 2008-07-08 Prefixing Removed  
2111 -  
2112 -  
2113 -  
2114 - *** [3.2] Separating web arguments.  
2115 -  
2116 - When a new request arrives, we need to separate the web arguments, that is to say:  
2117 -  
2118 - - find the value of "s", and recover the corresponding state,  
2119 - - find the value of "a", which is the name of the action to be performed,  
2120 - - get the list of all the remaining web arguments (operands of the action).  
2121 -  
2122 - We must also determine if the previous state may be recovered. If it is not the case  
2123 - (either because the previous state name is invalid, or the previous state is out of  
2124 - date), we must check if there is an action name. Indeed, the presence of an action name  
2125 - indicates that the user has clicked on one of our buttons or links. If on the contrary  
2126 - there is no action name the user has just entered our address in his browser. In this  
2127 - last case, we must send the first page of our site (maybe a 'login' page), but if there  
2128 - is an action, we must send a page just saying that the session ticket has expired. If  
2129 - the previous state is recovered and there is no action, the new state is the same as  
2130 - the previous state.  
2131 -  
2132 - The result of the separation of the web arguments is of type:  
2133 -  
2134 -type Separated_Web_Args($State):  
2135 - swa(PreviousState($State) previous_state,  
2136 - Maybe(String) action_name,  
2137 - List(Web_arg) operands).  
2138 -  
2139 -  
2140 -  
2141 - The next function constructs the function which separates the web arguments.  
2142 -  
2143 -define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State)  
2144 - make_separate_web_args_function  
2145 - (  
2146 - String state_directory,  
2147 - String -> PreviousState($State) retrieve_state,  
2148 - String website_name  
2149 - ) =  
2150 - (List(Web_arg) lwa, HTTP_Info info) |-swaf->  
2151 - if lwa is  
2152 - {  
2153 - [ ] then  
2154 - //  
2155 - // no web arg found => no previous state and no action  
2156 - //  
2157 - if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is  
2158 - {  
2159 - failure then swa(not_found,failure,[]),  
2160 - success(cookie) then swa(retrieve_state(value(cookie)),failure,[])  
2161 - },  
2162 -  
2163 - //swa(failure,failure,[]),  
2164 -  
2165 - [wa_1 . wa_others] then  
2166 - //  
2167 - // at least one web arg =>  
2168 - // separate other web args, and insert the first one as needed  
2169 - //  
2170 - if (Separated_Web_Args($State))swaf(wa_others, info) is  
2171 - {  
2172 - swa(ps1, // possible previous state  
2173 - an1, // maybe an action name  
2174 - op1) // operands so far  
2175 - then  
2176 - if wa_1 is  
2177 - {  
2178 - web_arg(n, value) then  
2179 - with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n,  
2180 - if name = "a" then  
2181 - swa(ps1,success(value),op1)  
2182 - else if name = "t" then  
2183 - swa(ps1,an1,[web_arg("target",value) . op1])  
2184 - else  
2185 - swa(ps1,an1,[web_arg(name,value) . op1]),  
2186 -  
2187 - upload(n,v,t) then  
2188 - swa(ps1,an1,[wa_1 . op1])  
2189 - }  
2190 - }  
2191 - }.  
2192 -  
2193 -  
2194 -  
2195 -  
2196 -  
2197 -  
2198 - *** [3.3] Applying an action.  
2199 -  
2200 - When the web arguments are separated (and their names cleaned up from prefixes), we may  
2201 - apply the action to the operands and the current state. We search for the action to be  
2202 - applied in the list of actions. If no action is found, the new state is the same as  
2203 - the previous state. Also, we deny the application of an HTTP action if the request  
2204 - arrives through the HTTPS channel and conversely.  
2205 -  
2206 -  
2207 -define ($State previous,  
2208 - String action_name,  
2209 - HTTP_Info http_info,  
2210 - List(Web_arg) lwa,  
2211 - Bool is_https) -> $State  
2212 - make_apply_action_function  
2213 - (  
2214 - List(Web_Action($State)) actions_list  
2215 - ) =  
2216 - with f =  
2217 - ($State previous,  
2218 - String action_name,  
2219 - HTTP_Info http_info,  
2220 - List(Web_arg) lwa,  
2221 - Bool is_https,  
2222 - List(Web_Action($State)) actions) |-f->  
2223 - //println("Looking for action ["+action_name+"]");  
2224 - if actions is  
2225 - {  
2226 - [ ] then print("action '"+action_name+  
2227 - "' not found.\n"); previous,  
2228 - [ac1 . others] then if ac1 is  
2229 - {  
2230 - http_action(an,allow,do_it) then  
2231 - if an = action_name  
2232 - then if is_https  
2233 - then (print("HTTP action '"+an+  
2234 - "' called through HTTPS (denied).\n");  
2235 - previous)  
2236 - else if allow(previous)  
2237 - then do_it(http_info,lwa,previous)  
2238 - else previous  
2239 - else f(previous,action_name,http_info,lwa,is_https,others),  
2240 -  
2241 - https_action(an,allow,do_it) then  
2242 - if an = action_name  
2243 - then if is_https  
2244 - then if allow(previous)  
2245 - then do_it(http_info,lwa,previous)  
2246 - else previous  
2247 - else (print("HTTPS action '"+an+  
2248 - "' called through HTTP (denied).\n");  
2249 - previous)  
2250 - else f(previous,action_name,http_info,lwa,is_https,others),  
2251 -  
2252 - http_https_action(an,allow,do_it) then  
2253 - if an = action_name  
2254 - then  
2255 - //println("Action ["+action_name+"] found");  
2256 - if allow(previous)  
2257 - then do_it(http_info,lwa,previous)  
2258 - else previous  
2259 - else f(previous,action_name,http_info,lwa,is_https,others),  
2260 -  
2261 - }  
2262 - },  
2263 - ($State previous,  
2264 - String action_name,  
2265 - HTTP_Info http_info,  
2266 - List(Web_arg) lwa,  
2267 - Bool is_https) |->  
2268 - f(previous, action_name, http_info, lwa, is_https, actions_list).  
2269 -  
2270 -  
2271 -  
2272 -  
2273 -  
2274 -  
2275 -  
2276 -  
2277 - *** [4] Web site descriptions and the 'awp handlers'.  
2278 -  
2279 - *** [4.1] The type 'Web_Site'.  
2280 -  
2281 - The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We  
2282 - need another one, because, we have some extra informations to record for each site.  
2283 -  
2284 -public type Web_Site:  
2285 - web_site((Word32,Word32) -> Web_Site_Description description,  
2286 - List(String) -> One delete_out_of_date).  
2287 -  
2288 -  
2289 -  
2290 -  
2291 - *** [4.2] Making a web site description.  
2292 -  
2293 - Below is the function which creates a web site description. It first creates (if  
2294 - needed) the directories for the site, then constructs the tool functions for the site,  
2295 - and the site handler. Finally, it constructs the web site description.  
2296 -  
2297 - We gather common (constant) informations in the following type:  
2298 -  
2299 -public type CommonInfo:  
2300 - info(String common_name,  
2301 - Word32 http_port,  
2302 - Word32 https_port,  
2303 - String site_directory,  
2304 - String authorization_secret  
2305 - ).  
2306 -  
2307 - We need a forward declaration.  
2308 -  
2309 -public define Printable_tree  
2310 - format  
2311 - (  
2312 - CommonInfo cinfo,  
2313 - String state_name,  
2314 - List(HTTP_header) headers,  
2315 - HTTP_Answer page,  
2316 - Bool is_https,  
2317 - String charset  
2318 - ).  
2319 -  
2320 -  
2321 -define Printable_tree  
2322 - format  
2323 - (  
2324 - HTML_Size s  
2325 - ) =  
2326 - if s is  
2327 - {  
2328 - absolute(x) then ["\"",x,"\""],  
2329 - percentage(x) then ["\"",x,"%\""]  
2330 - }.  
2331 -  
2332 -define List(HTTP_header)  
2333 - make_state_cookie_headers  
2334 - (  
2335 - String website_name,  
2336 - String state_name  
2337 - )  
2338 - =  
2339 - [  
2340 - http_header("Set-Cookie", "state_"+website_name+"="+state_name)  
2341 - ]  
2342 - .  
2343 -  
2344 - public define Web_Site  
2345 - make_web_site_description  
2346 - (  
2347 - List(String) common_names, // for example: ["www.our-business.com",  
2348 - // "192.168.0.1"]  
2349 - // the second one is just for testing  
2350 - String site_directory, // where 'public' and other directories are  
2351 - // located (should NOT end with '/')  
2352 - One -> One init,  
2353 - (HTTP_Info,  
2354 - List(Web_arg),  
2355 - Bool is_https) -> $State initial_state,  
2356 - ($State expired,  
2357 - HTTP_Info,  
2358 - List(Web_arg),  
2359 - Bool is_https) -> $State ticket_expired_state,  
2360 - (HTTP_Info,  
2361 - List(Web_arg),  
2362 - Bool is_https) -> $State ticket_lost_state,  
2363 - List(Web_Action($State)) actions,  
2364 - $State -> HTTP_Answer compute_page,  
2365 - $State -> List(HTTP_header) additional_headers,  
2366 - Int timeout, // seconds (todo: minutes)  
2367 - Redirections redirections,  
2368 - String charset,  
2369 - List(String) journal_extensions,  
2370 - List(String) journal_headers,  
2371 - String authorization_secret,  
2372 - List(MIME) known_mime_types,  
2373 - (String action_name,  
2374 - List(Web_arg) args)-> One before_send_file  
2375 - ).  
2376 -  
2377 -  
2378 -public define Web_Site  
2379 - make_web_site_description  
2380 - (  
2381 - String website_name,  
2382 - List(String) common_names, // for example: ["www.our-business.com"]  
2383 - String site_directory,  
2384 - String state_directory,  
2385 - One -> One init,  
2386 - (HTTP_Info,  
2387 - List(Web_arg),  
2388 - Bool is_https) -> $State initial_state,  
2389 - ($State expired,  
2390 - Maybe(String),  
2391 - HTTP_Info,  
2392 - List(Web_arg),  
2393 - Bool is_https) -> $State ticket_expired_state,  
2394 - (Maybe(String),  
2395 - HTTP_Info,  
2396 - List(Web_arg),  
2397 - Bool is_https) -> $State ticket_lost_state,  
2398 - List(Web_Action($State)) actions,  
2399 - $State -> HTTP_Answer compute_page,  
2400 - $State -> List(HTTP_header) additional_headers,  
2401 - Int timeout,  
2402 - Redirections redirections,  
2403 - String charset,  
2404 - List(String) journal_extensions,  
2405 - List(String) journal_headers,  
2406 - String secret,  
2407 - List(MIME) known_mime_types,  
2408 - (String action_name,  
2409 - List(Web_arg) args) -> One before_send_file  
2410 - //Bool using_state_cookies  
2411 - ) =  
2412 - init(unique);  
2413 -  
2414 -  
2415 - //  
2416 - // make required directories (if needed)  
2417 - //  
2418 - with //web_sites_directory = (String) make_directory(my_anubis_directory+"/web_sites"),  
2419 - base_directory = (String) make_directory(site_directory),  
2420 - // state_directory = make_directory(site_directory+"/states"),  
2421 - forget((String)make_directory(site_directory+"/public"));  
2422 - //  
2423 - // construct tool functions  
2424 - // TODO 'make_separate_web_args_function' must retrieve state_cookies before parsing web_args if using_state_cookies is true  
2425 - with save_state = make_save_state_function(timeout, state_directory),  
2426 - retrieve_state = make_retrieve_state_function(state_directory),  
2427 - separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name),  
2428 - apply_action = make_apply_action_function(actions),  
2429 - //  
2430 - // construct the site handler  
2431 - //  
2432 - site_handler = (Word32 http_port, Word32 https_port) |->  
2433 - ((String host_name,  
2434 - HTTP_Info http_info,  
2435 - List(Web_arg) lwa,  
2436 - Bool is_https) |->  
2437 - //(Printable_tree)  
2438 - if separate_web_args(lwa, http_info) is  
2439 - {  
2440 - swa(mb_previous_state, mb_action_name, operands) then  
2441 - with new_state = if mb_previous_state is  
2442 - {  
2443 - not_found then  
2444 - //println("previous state not found");  
2445 - if mb_action_name is  
2446 - {  
2447 - failure then initial_state(http_info, operands, is_https),  
2448 - success(_) then  
2449 - ticket_lost_state(mb_action_name, http_info,operands,is_https)  
2450 - },  
2451 -  
2452 - out_of_date(state) then  
2453 - ticket_expired_state(state, mb_action_name, http_info,operands,is_https),  
2454 -  
2455 - still_valid(state) then  
2456 - if mb_action_name is  
2457 - {  
2458 - failure then state,  
2459 - success(action_name) then  
2460 - apply_action(state,action_name,http_info,operands,is_https)  
2461 - }  
2462 - },  
2463 - //if state_and_headers is (session_ticket, mb_new_state, headers) then  
2464 - with state_name = save_state(new_state),  
2465 - //println("Cookie new STATE NAME "+state_name);  
2466 - with cookie_headers = if mb_action_name is  
2467 - {  
2468 - failure then [],  
2469 - success(action_name) then  
2470 - if substr(action_name, 0, 5)="ajax_" then  
2471 - []  
2472 - else  
2473 - make_state_cookie_headers(website_name, state_name)  
2474 - },  
2475 -  
2476 - format(info(host_name, http_port, https_port, site_directory, secret),  
2477 - state_name,  
2478 - additional_headers(new_state) + cookie_headers,  
2479 - compute_page(new_state),  
2480 - is_https,  
2481 - charset)  
2482 - }),  
2483 - //  
2484 - // make the delete_out_of_date function  
2485 - //  
2486 - delete_out_of_date =  
2487 - make_delete_out_of_date_states_function((Maybe($State))failure,  
2488 - site_directory+"/states"),  
2489 - //  
2490 - // construct the web site description  
2491 - //  
2492 - web_site((Word32 http_port, Word32 https_port) |->  
2493 - web_site_description(common_names,  
2494 - site_directory,  
2495 - redirections,  
2496 - charset,  
2497 - journal_extensions,  
2498 - journal_headers,  
2499 - secret,  
2500 - known_mime_types,  
2501 - site_handler(http_port,https_port),  
2502 - (HTTP_Info http_info, List(Web_arg) lwa) |-> if separate_web_args(lwa, http_info ) is  
2503 - swa(mb_previous_state,mb_action_name,operands) then  
2504 - if mb_action_name is  
2505 - {  
2506 - failure then unique  
2507 - success(an) then before_send_file(an,operands)  
2508 - }  
2509 - //using_state_cookies  
2510 - ),  
2511 - delete_out_of_date).  
2512 -  
2513 -define String  
2514 - _random_string  
2515 - (  
2516 - Int size,  
2517 - String current  
2518 - )=  
2519 - if size = 0 then  
2520 - current  
2521 - else  
2522 - _random_string( size - 1, current + random(9))  
2523 - .  
2524 -  
2525 -public define String  
2526 - generate_random_string  
2527 - (  
2528 - Int size  
2529 - ) =  
2530 - to_string(extract(base64_encode(to_byte_array(_random_string(size, ""))), 0, size)).  
2531 -  
2532 -  
2533 -define String  
2534 - get_site_uid  
2535 - (  
2536 - String site_path  
2537 - )=  
2538 - with file_name = site_path+"/site_UID",  
2539 - if read_from_file(file_name) is  
2540 - {  
2541 - cannot_find_file then  
2542 - println("site UID doesn't exists. Generating it now");  
2543 - with uid = generate_random_string(9),  
2544 - if write_to_file(file_name, to_byte_array(uid)) is  
2545 - {  
2546 - cannot_open_file then println("Can't create site UID here "+file_name);"",  
2547 - write_error(_) then println("Can't write site UID here "+file_name);"",  
2548 - ok then uid  
2549 - }  
2550 - read_error(_) then  
2551 - println("cannot read site UID from "+file_name);""  
2552 - ok(ba) then to_string(ba)  
2553 - }  
2554 - .  
2555 -  
2556 -// Compatibility function for older websites  
2557 -public define Web_Site  
2558 - make_web_site_description  
2559 - (  
2560 - List(String) common_names, // for example: ["www.our-business.com"]  
2561 - String site_directory,  
2562 - String state_directory,  
2563 - One -> One init,  
2564 - (HTTP_Info,  
2565 - List(Web_arg),  
2566 - Bool is_https) -> $State initial_state,  
2567 - ($State expired,  
2568 - Maybe(String),  
2569 - HTTP_Info,  
2570 - List(Web_arg),  
2571 - Bool is_https) -> $State ticket_expired_state,  
2572 - (Maybe(String),  
2573 - HTTP_Info,  
2574 - List(Web_arg),  
2575 - Bool is_https) -> $State ticket_lost_state,  
2576 - List(Web_Action($State)) actions,  
2577 - $State -> HTTP_Answer compute_page,  
2578 - $State -> List(HTTP_header) additional_headers,  
2579 - Int timeout,  
2580 - Redirections redirections,  
2581 - String charset,  
2582 - List(String) journal_extensions,  
2583 - List(String) journal_headers,  
2584 - String secret,  
2585 - List(MIME) known_mime_types,  
2586 - (String action_name,  
2587 - List(Web_arg) args) -> One before_send_file  
2588 - //Bool using_state_cookies  
2589 - )  
2590 - =  
2591 - //generate an unique ID if doesn't exist in root of site_directory  
2592 - with site_UID = get_site_uid(site_directory),  
2593 - println("site_UID : "+site_UID);  
2594 - make_web_site_description(site_UID, common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file)  
2595 - .  
2596 -  
2597 -  
2598 -  
2599 - *** [4.3] Starting the servers.  
2600 -  
2601 -public define Start_Web_Sites_Result  
2602 - start_web_sites  
2603 - (  
2604 - Word32 ip_address, // the IP address shared by the web sites  
2605 - Word32 http_port, // usually: 80  
2606 - Word32 https_port, // usually: 443  
2607 - String ssl_certificate_common_name,  
2608 - List(Web_Site) web_sites, // web sites to be started  
2609 - (One) -> Bool shutdown_required  
2610 - ) =  
2611 - with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port),  
2612 - with http_server_r =  
2613 - start_http_server(ip_address,http_port,  
2614 - map(get_description,web_sites),  
2615 - load_denial_of_service_info),  
2616 - with https_server_r =  
2617 - start_https_server(ip_address,https_port,  
2618 - ssl_certificate_common_name,  
2619 - map(get_description,web_sites),  
2620 - load_denial_of_service_info),  
2621 - if http_server_r is ok(http_server)  
2622 - then  
2623 - (  
2624 - if https_server_r is ok(https_server)  
2625 - then  
2626 - (  
2627 - start_http_servers_tasks(map(get_description,web_sites),  
2628 - [http_server,https_server],  
2629 - 600); // period of 10 minutes  
2630 - delegate  
2631 - delete_states_loop(  
2632 - map((Web_Site ws) |->  
2633 - (site_directory(description(ws)(http_port,https_port))+  
2634 - "/states",delete_out_of_date(ws)),  
2635 - web_sites),  
2636 - 3600*24*3, // keep out of date states 3 days  
2637 - now,  
2638 - http_server,  
2639 - https_server,  
2640 - shutdown_required),  
2641 - ok(http_server,https_server)  
2642 - )  
2643 - else cannot_bind_to_port(https_port)  
2644 - )  
2645 - else  
2646 - (  
2647 - if https_server_r is ok(https_server)  
2648 - then cannot_bind_to_port(http_port)  
2649 - else cannot_bind_to_port(http_port,https_port)  
2650 - ).  
2651 -  
2652 -  
2653 -public define One  
2654 - start_web_sites  
2655 - (  
2656 - Word32 ip_address, // the IP address shared by the web sites  
2657 - Word32 http_port, // usually: 80  
2658 - Word32 https_port, // usually: 443  
2659 - String ssl_certificate_common_name,  
2660 - List(Web_Site) web_sites, // web sites to be started  
2661 - (One) -> Bool shutdown_required,  
2662 - Logger log  
2663 - ) =  
2664 - if (Start_Web_Sites_Result)start_web_sites(ip_address,  
2665 - http_port,  
2666 - https_port,  
2667 - ssl_certificate_common_name,  
2668 - web_sites,  
2669 - shutdown_required) is  
2670 - {  
2671 - cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n),  
2672 - cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m),  
2673 - ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).")  
2674 - }.  
2675 -  
2676 -  
2677 -  
2678 -  
2679 -  
2680 - *** [5] HTML Formating.  
2681 -  
2682 - We need to translate HTML elements as defined above into actual HTML text.  
2683 -  
2684 - Actioners require special informations, which must be transmitted when needed by the  
2685 - 'format' functions:  
2686 -  
2687 - - the 'common name', which is used for URLs,  
2688 - - the HTTP/HTTPS port number,  
2689 - - the 'state name', which must be transmitted when the actioner is clicked upon,  
2690 - - the 'form name' (if any) to which the actioner refers.  
2691 -  
2692 - If the actioner is off form, and if it refers to a form, the name of that form is  
2693 - already known by the actioner. On the contrary, if the actioner is 'in form', it refers  
2694 - implicitly to the form containing it. The name of that form is transmitted to the  
2695 - 'format' functions called from within the formating of that form.  
2696 -  
2697 -  
2698 -  
2699 -  
2700 - *** [5.1] The type 'HTML_Any($T)'.  
2701 -  
2702 - The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The  
2703 - parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'.  
2704 -  
2705 -type HTML_Any($T):  
2706 - any_text (List(Text_Option), String the_text),  
2707 - any_preformated (List(Text_Option), String),  
2708 - any_paragraph (List(Text_Option), $T content),  
2709 - any_image (List(CoreAttrs), String url, String alternate),  
2710 - any_image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
2711 - any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)),  
2712 - any_center ($T),  
2713 - any_mail_to (String email, $T element),  
2714 - any_scroller (Int width, Int height,  
2715 - Int content_width, Int content_height,  
2716 - $T content),  
2717 - any_fixed_size (HTML_Size width, HTML_Size height, $T content),  
2718 - any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),  
2719 - any_actioner (Actioner_Connection,  
2720 - Actioner_Target,  
2721 - Actioner_Aspect,  
2722 - String action_name,  
2723 - List((String,String)) extra_ops,  
2724 - List(Actioner_Local_Action),  
2725 - Maybe(String) form_name),  
2726 - any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
2727 - any_foreign_link (List(Text_Option), String url),  
2728 - any_foreign_link (List(Text_Option), String url, String name),  
2729 - any_private_download (String abs_path, String name, String extra_ext,  
2730 - Maybe((String,List((String,String))))),  
2731 - any_div (List(CoreAttrs), $T element),  
2732 - any_div_empty (List(CoreAttrs)),  
2733 - any_coreattrs (List(CoreAttrs)).  
2734 -  
2735 -  
2736 -  
2737 - *** [5.2] Formating a color.  
2738 -  
2739 - RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters  
2740 - hexadecimal values.  
2741 -  
2742 -define String  
2743 - html_format  
2744 - (  
2745 - RGB color  
2746 - ) =  
2747 - if color is rgb(r,g,b) then  
2748 - "#" + to_hexa(r)  
2749 - + to_hexa(g)  
2750 - + to_hexa(b).  
2751 -  
2752 -  
2753 - The following is a very arbitrary definition of the opposite color. The thing which is  
2754 - important is that it is far from the original, so that characters in 'opposite' color  
2755 - are clearly visible over the original.  
2756 -  
2757 -define RGB  
2758 - opposite  
2759 - (  
2760 - RGB color  
2761 - ) =  
2762 - if color is rgb(r,g,b) then  
2763 - rgb(255-r,  
2764 - 255-g,  
2765 - 255-b).  
2766 -  
2767 -  
2768 -  
2769 -  
2770 - *** [5.3] Creating buttons.  
2771 -  
2772 - We want to be able to create buttons in the form of a pair of images (rollovers)  
2773 - automatically. We use the JPEG interface, because for the time being Anubis cannot  
2774 - handle other kinds of images.  
2775 -  
2776 -  
2777 - Computing printed text length.  
2778 -  
2779 - define Int  
2780 - printed_text_width  
2781 - (  
2782 - Word8 -> Int char_size,  
2783 - List(Word8) l  
2784 - ) =  
2785 - if l is  
2786 - {  
2787 - [] then (Int) 0,  
2788 - [h . t] then char_size(h) + 1+ printed_text_width(char_size,t)  
2789 - }.  
2790 -  
2791 - define Int  
2792 - printed_text_width  
2793 - (  
2794 - SystemFont font,  
2795 - String s  
2796 - ) =  
2797 - printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))),  
2798 - explode(s)).  
2799 -  
2800 -  
2801 -  
2802 - Converting RGB to RGBA.  
2803 -  
2804 -define RGBA  
2805 - to_rgba  
2806 - (  
2807 - RGB color  
2808 - ) =  
2809 - if color is rgb(r,g,b) then rgba(r,g,b,255).  
2810 -  
2811 -  
2812 - Drawing a 'relief'.  
2813 -  
2814 - define One  
2815 - draw_relief  
2816 - (  
2817 - RGBAImage dest,  
2818 - RGBA color,  
2819 - Int contrast,  
2820 - Int x,  
2821 - Int y,  
2822 - Int width,  
2823 - Int height  
2824 - ) =  
2825 - with l = lighten(color,contrast),  
2826 - d = darken(color,contrast),  
2827 - draw_rectangle(dest,rect(x,y,x+width,y+1),l);  
2828 - draw_rectangle(dest,rect(x,y+1,x+1,y+height),l);  
2829 - draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d);  
2830 - draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d).  
2831 -  
2832 -  
2833 - Creating a button background.  
2834 -  
2835 - define RGBAImage  
2836 - create_button_background  
2837 - (  
2838 - RGBA color,  
2839 - Int width,  
2840 - Int height  
2841 - ) =  
2842 - with result = create_rgba_image(width,height,color),  
2843 - draw_relief(result,color,100,0,0,width,height);  
2844 - draw_relief(result,color,70,1,1,width-2,height-2);  
2845 - draw_relief(result,color,55,2,2,width-4,height-4);  
2846 - draw_relief(result,color,35,3,3,width-6,height-6);  
2847 - draw_relief(result,color,20,4,4,width-8,height-8);  
2848 - draw_relief(result,color,10,5,5,width-10,height-10);  
2849 - draw_relief(result,color,5,6,6,width-12,height-12);  
2850 - result.  
2851 -  
2852 -  
2853 - Drawing the text over the background.  
2854 -  
2855 - define One  
2856 - draw_button_text  
2857 - (  
2858 - RGBAImage image,  
2859 - String text,  
2860 - Int text_index,  
2861 - Int pixel_x,  
2862 - Int y,  
2863 - Rectangle clip,  
2864 - RGBA color,  
2865 - SystemFont font,  
2866 - ) =  
2867 - if nth(text_index,text) is  
2868 - {  
2869 - failure then unique,  
2870 - success(c) then  
2871 - with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color),  
2872 - draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font)  
2873 - }.  
2874 -  
2875 - define One  
2876 - draw_button_text  
2877 - (  
2878 - RGBAImage image,  
2879 - String text,  
2880 - Int text_width,  
2881 - RGBA light_color,  
2882 - RGBA dark_color,  
2883 - SystemFont font  
2884 - ) =  
2885 - with image_width = width(image),  
2886 - image_height = height(image),  
2887 - x_pos = (image_width-text_width)>>1,  
2888 - clip = rect(0,0,image_width,image_height),  
2889 - new_light_color = lighten(light_color,150),  
2890 - new_dark_color = darken(dark_color,40),  
2891 - draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font);  
2892 - draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font).  
2893 -  
2894 -  
2895 - The next function creates the two images for a button. The information given is the  
2896 - main color of the button, the text of the button and the minimal width (in pixels) of  
2897 - the button. The function does not create the button if the images already exist. The  
2898 - two images are stored in the directory 'site_directory/buttons'. The names of the files  
2899 - are of the form:  
2900 -  
2901 - bxxxx_off.jpg  
2902 - bxxxx_on.jpg  
2903 -  
2904 - where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like  
2905 - 'rm'), and where 'xxxx' is created from the given informations by the formula:  
2906 -  
2907 - xxxx = web_arg_encode(sha1((color,text,width)))  
2908 -  
2909 - Hence, distinct informations give distinct file names.  
2910 -  
2911 -  
2912 - define String // returns xxxx  
2913 - create_button_images  
2914 - (  
2915 - String site_directory,  
2916 - RGBA color,  
2917 - String text,  
2918 - Int width,  
2919 - SystemFont font  
2920 - ) =  
2921 - with xxxx = web_arg_encode(sha1((color,text,width))),  
2922 - buttons_dir = site_directory+"/public/buttons",  
2923 - off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg",  
2924 - on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg",  
2925 - if file_exists(on_filepath)  
2926 - then xxxx  
2927 - else with  
2928 - text_width = printed_text_width(font,text),  
2929 - button_width = max(width,text_width+12),  
2930 - button_height = (Int)20,  
2931 - light_color = lighten(color,60),  
2932 - very_light_color = lighten(light_color,30),  
2933 - dark_color = darken(color,40),  
2934 - background_off =  
2935 - create_button_background(color,button_width,button_height),  
2936 - background_on =  
2937 - create_button_background(light_color,button_width,button_height),  
2938 -  
2939 - draw_button_text(background_off,text,text_width,very_light_color,dark_color,font);  
2940 - draw_button_text(background_on, text,text_width,very_light_color,dark_color,font);  
2941 - forget(write_image_to_JPEG_file(to_JPEG(background_off),  
2942 - off_filepath,  
2943 - 100));  
2944 - forget(write_image_to_JPEG_file(to_JPEG(background_on),  
2945 - on_filepath,  
2946 - 100));  
2947 - xxxx.  
2948 -  
2949 -  
2950 -  
2951 -  
2952 -  
2953 - *** [5.4] Formating an actioner.  
2954 -  
2955 - An actioner works as follows. Assume first that it refers to a form. When it is clicked  
2956 - upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the  
2957 - form, and submits the form, using the JavaScript command 'form_name.submit()'. If the  
2958 - actioner does not refer to a form, it fires the URL directly via 'href', because in  
2959 - that case, the actioner is always an <a> tag.  
2960 -  
2961 - The URL itself is composed using the connection sort (same, http or https), the common  
2962 - name and port number (if needed), the state name, the action name, and the extra  
2963 - operands, which are put into a query string. It may look like this:  
2964 -  
2965 - http://common_name:port/?s=state_name&a=action_name&oname=value...  
2966 -  
2967 - Each extra operand is a pair of strings: (name,value). It is formated as:  
2968 -  
2969 - &oname=value  
2970 -  
2971 -  
2972 -public define String  
2973 - format_extra_operands  
2974 - (  
2975 - List((String,String)) l  
2976 - ) =  
2977 - if l is  
2978 - {  
2979 - [ ] then "",  
2980 - [h . t] then if h is (n,v) then  
2981 - "&amp;"+n+"="+v+format_extra_operands(t)  
2982 - }.  
2983 -  
2984 -  
2985 - It seams that the standard requires "&amp;" instead of "&" !  
2986 -  
2987 - In case the target is another window, we need to format the options for this window.  
2988 -  
2989 -define String  
2990 - format  
2991 - (  
2992 - List(Other_Window_Option) l  
2993 - ) =  
2994 - if l is  
2995 - {  
2996 - [ ] then "",  
2997 - [h . t] then if h is  
2998 - {  
2999 - resizable then "resizable",  
3000 - scrollbars then "scrollbars",  
3001 - width(w) then "width="+w,  
3002 - height(h2) then "height="+h2  
3003 - } + if t is [ ] then "" else (","+format(t))  
3004 - }.  
3005 -  
3006 -  
3007 -  
3008 - Formating choices for a <select> tag.  
3009 -  
3010 -public define Printable_tree  
3011 - format_choices  
3012 - (  
3013 - List(String) l  
3014 - ) =  
3015 - if l is  
3016 - {  
3017 - [ ] then [ ],  
3018 - [h . t] then ["<option>", h, "</option>\n" . format_choices(t)]  
3019 - }.  
3020 -  
3021 -  
3022 -public define Printable_tree  
3023 - format_choices  
3024 - (  
3025 - List(String) l,  
3026 - InitialValue selected  
3027 - ) =  
3028 - if l is  
3029 - {  
3030 - [ ] then [ ],  
3031 - [h . t] then if h = selected.value  
3032 - then ["<option selected=\"selected\">", h, "</option>\n" . format_choices(t)]  
3033 - else ["<option>", h, "</option>\n" . format_choices(t,selected)]  
3034 - }.  
3035 -  
3036 -  
3037 -public define Printable_tree  
3038 - format_choices  
3039 - (  
3040 - List((WebArgValue,String)) l  
3041 - ) =  
3042 - if l is  
3043 - {  
3044 - [ ] then [ ],  
3045 - [h . t] then  
3046 - if h is (val,item)  
3047 - then ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t)]  
3048 - }.  
3049 -  
3050 -public define Printable_tree  
3051 - format_choices  
3052 - (  
3053 - List((WebArgValue,String)) l,  
3054 - InitialValue selected  
3055 - ) =  
3056 - if l is  
3057 - {  
3058 - [ ] then [ ],  
3059 - [h . t] then  
3060 - if h is (val,item) then  
3061 - if val.value = selected.value  
3062 - then ["<option value=\""+val.value+"\" selected=\"selected\">", item, "</option>\n" . format_choices(t)]  
3063 - else ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t,selected)]  
3064 - }.  
3065 -  
3066 -  
3067 -  
3068 - Note: this counter is private to the virtual machine, hence there is one counter by  
3069 - client and by page : it seems that a new VM (simply a delegate) is started for each request.  
3070 -  
3071 -define Int  
3072 - new_count  
3073 - (  
3074 - Var(Int) count  
3075 - )  
3076 - =  
3077 - count <- *count+1;  
3078 - *count.  
3079 -  
3080 -  
3081 - The next function composes the URL. It is a JavaScript URL when the target is another  
3082 - window.  
3083 -  
3084 -define String  
3085 - make_actioner_url  
3086 - (  
3087 - CommonInfo cinfo,  
3088 - Actioner_Connection connection,  
3089 - Actioner_Target target,  
3090 - String state_name,  
3091 - String action_name,  
3092 - List((String,String)) extra_ops,  
3093 - Bool is_https  
3094 - ) =  
3095 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
3096 - with strict_url =  
3097 - if connection is  
3098 - {  
3099 - same then "/",  
3100 - http then "http://"+common_name+":"+http_port+"/",  
3101 - https then "https://"+common_name+":"+https_port+"/",  
3102 - } +  
3103 - "?a=" + action_name +  
3104 - format_extra_operands(extra_ops),  
3105 - if target is  
3106 - {  
3107 - same then strict_url,  
3108 - same(label) then strict_url+"#"+label,  
3109 - other(wn,ops) then  
3110 -  
3111 - "javascript:void window.open('"+strict_url+"&amp;t="+wn+"','"+  
3112 - "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"  
3113 - }.  
3114 -  
3115 -define String  
3116 - make_foreign_link_url  
3117 - (  
3118 - Actioner_Target target,  
3119 - String url  
3120 - ) =  
3121 - if target is  
3122 - {  
3123 - same then "/",  
3124 - same(label) then "/#"+label,  
3125 - other(wn,ops) then  
3126 -  
3127 - "javascript:void window.open('"+url+"','"+  
3128 - "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"  
3129 - }.  
3130 -  
3131 -  
3132 - Depending on the fact that the actioner refers to a form or not, the URL is used in two  
3133 - different ways. If the actioner does not refer to a form, it is realized by a '<a>'  
3134 - tag, with a 'href' attribute. If it refers to a form, it is still realized by a '<a>'  
3135 - tag, but with no href attribute. In this case, we use the 'onMouseDown' or 'onChange'  
3136 - event handler. The handler calls a JavaScript function which puts the URL as the value  
3137 - of the 'action' attribute of the form, and submits the form.  
3138 -  
3139 -type URL_or_JavaScript:  
3140 - url (String),  
3141 - javascript (Printable_tree script, Printable_tree handler).  
3142 -  
3143 -  
3144 - It was as shown below, in order to allow submission of a form from outside the form,  
3145 - but this makes problems:  
3146 -  
3147 -define URL_or_JavaScript  
3148 - format_action  
3149 - (  
3150 - String the_url,  
3151 - Actioner_Aspect aspect,  
3152 - Maybe(String) mb_id,  
3153 - Maybe(String) mb_form_name,  
3154 - Var(Int) action_count  
3155 - ) =  
3156 - if mb_form_name is  
3157 - {  
3158 - failure then  
3159 - url(the_url),  
3160 - success(form_name) then  
3161 - with n = new_count(action_count),  
3162 - fn_name = "pfu_" + if mb_id is  
3163 - {  
3164 - failure then form_name + "_" + n,  
3165 - success(id) then id,  
3166 - },  
3167 - javascript(  
3168 - [  
3169 - "<script type=\"text/javascript\" language =\"JavaScript\">\n",  
3170 - "function ", fn_name, "() {\n",  
3171 - " var fa = document.forms.",form_name,";\n",  
3172 - " var u = \"",the_url,"\";\n",  
3173 - " fa.action = u;",  
3174 - if aspect is submit(_, _) then " }\n"  
3175 - else "\n fa.submit(); }\n",  
3176 - "</script>\n"  
3177 - ],  
3178 - [fn_name,"();"]  
3179 - )  
3180 - }.  
3181 -  
3182 -  
3183 -  
3184 - Now, we format the actioner according to its aspect.  
3185 -  
3186 -define List(Text_Option)  
3187 - get_text_options  
3188 - (  
3189 - List(Text_Option) l  
3190 - )  
3191 - =  
3192 - if l is  
3193 - {  
3194 - [] then [],  
3195 - [h . t ] then  
3196 - if h is class(_) then  
3197 - get_text_options(t)  
3198 - else if h is id(_) then  
3199 - get_text_options(t)  
3200 - else if h is style(_) then  
3201 - get_text_options(t)  
3202 - else if h is title(_) then  
3203 - get_text_options(t)  
3204 - else  
3205 - [ h . get_text_options(t) ]  
3206 -  
3207 - }.  
3208 -  
3209 - /**  
3210 - * Extract the CSS class list from the list of Text_Option  
3211 - */  
3212 -define List(CoreAttrs)  
3213 - get_css_class  
3214 - (  
3215 - List(Text_Option) l  
3216 - )  
3217 - =  
3218 - if l is  
3219 - {  
3220 - [] then [],  
3221 - [h . t ] then  
3222 -  
3223 -  
3224 - if h is class(name) then  
3225 - [ class(name) . get_css_class(t) ]  
3226 - else if h is id(name) then  
3227 - [ id(name) . get_css_class(t) ]  
3228 - else if h is style(the_style) then  
3229 - [ style(the_style) . get_css_class(t) ]  
3230 - else if h is title(name) then  
3231 - [ tooltip(name) . get_css_class(t) ]  
3232 - else if h is attr(name, value) then  
3233 - [ attr(name, value) . get_css_class(t) ]  
3234 - else  
3235 - get_css_class(t)  
3236 - }  
3237 - .  
3238 -  
3239 -define Printable_tree  
3240 - format  
3241 - (  
3242 - List(Actioner_Local_Action) l  
3243 - ) =  
3244 - if l is  
3245 - {  
3246 - [ ] then [ ],  
3247 - [h . t] then [if h is  
3248 - {  
3249 - close_window then [" window.close(); "]  
3250 - }  
3251 - . format(t)]  
3252 - }.  
3253 -  
3254 -public define String  
3255 - format_attrs  
3256 - (  
3257 - List(CoreAttrs) attributs  
3258 - )=  
3259 - if attributs is  
3260 - {  
3261 - [] then "",  
3262 - [h . t] then  
3263 - with current = if h is  
3264 - {  
3265 - id(id_name) then  
3266 - " id=\"" + id_name + "\"",  
3267 - class(class_name) then  
3268 - " class=\"" + class_name + "\"",  
3269 - style(style_string) then  
3270 - " style=\"" + style_string + "\"",  
3271 -  
3272 - title(title_string) then  
3273 - " title=\"" + title_string + "\"",  
3274 -  
3275 - lang(lang) then  
3276 - " xml:lang=" + lang,  
3277 - dir(reading_Way) then  
3278 - if reading_Way is  
3279 - {  
3280 - ltr then " dir=ltr",  
3281 - rtl then " dir=rtl"  
3282 - },  
3283 -  
3284 - accesskey(key) then  
3285 - " accesskey=\"" + key + "\"",  
3286 - tabindex(index) then  
3287 - " tabindex=\"" + index + "\"",  
3288 -  
3289 - attr(name, value) then  
3290 - " " + name + "=\"" + value + "\"",  
3291 -  
3292 - event(e, value) then  
3293 - " " + event_name(e) + "=\"" + value + "\"",  
3294 - },  
3295 - current + format_attrs(t)  
3296 - }.  
3297 -  
3298 -define String  
3299 - format_attrs  
3300 - (  
3301 - List(InputAttrs) attributs  
3302 - )=  
3303 - if attributs is  
3304 - {  
3305 - [] then "",  
3306 - [h . t] then  
3307 - with current = if h is  
3308 - {  
3309 - class(class_name) then  
3310 - " class=\"" + class_name + "\"",  
3311 - style(style_string) then  
3312 - " style=\"" + style_string + "\"",  
3313 -  
3314 - title(title_string) then  
3315 - " title=\"" + title_string + "\"",  
3316 -  
3317 - lang(lang) then  
3318 - " xml:lang=" + lang,  
3319 - dir(reading_Way) then  
3320 - if reading_Way is  
3321 - {  
3322 - ltr then " dir=ltr",  
3323 - rtl then " dir=rtl"  
3324 - },  
3325 -  
3326 - accesskey(key) then  
3327 - " accesskey=\"" + key + "\"",  
3328 - tabindex(index) then  
3329 - " tabindex=\"" + index + "\"",  
3330 -  
3331 - attr(name, value) then  
3332 - " " + name + "=\"" + value + "\"",  
3333 -  
3334 - event(e, value) then  
3335 - " " + event_name(e) + "=\"" + value + "\"",  
3336 - },  
3337 - current + format_attrs(t)  
3338 - }.  
3339 -  
3340 -define String  
3341 - format_text_options  
3342 - (  
3343 - List(Text_Option) l  
3344 - )  
3345 - =  
3346 - with text_options = get_text_options(l),  
3347 - css_classes = get_css_class(l),  
3348 - if text_options is  
3349 - {  
3350 - [] then "",  
3351 - [_ . _] then " style=\"" + format(text_options) + "\" "  
3352 - }  
3353 - +  
3354 - if css_classes is  
3355 - {  
3356 - [] then "",  
3357 - [_ . _] then format_attrs(css_classes)  
3358 - }.  
3359 -  
3360 -//define String  
3361 -// _format  
3362 -// (  
3363 -// List(CoreAttrs) opt  
3364 -// )=  
3365 -// if opt is  
3366 -// {  
3367 -// [] then "",  
3368 -// [h .t] then  
3369 -// with current = if h is  
3370 -// {  
3371 -// id(id_name) then  
3372 -// " id=\"" + id_name + "\"",  
3373 -// class(class_name) then  
3374 -// " class=\"" + class_name + "\"",  
3375 -// style(style_string) then  
3376 -// " style=\"" + style_string + "\"",  
3377 -//  
3378 -// title(title_string) then  
3379 -// " title=\"" + title_string + "\"",  
3380 -// lang(lang) then  
3381 -// " xml:lang=" + lang,  
3382 -// dir(reading_Way) then  
3383 -// if reading_Way is  
3384 -// {  
3385 -// ltr then " dir=ltr",  
3386 -// rtl then " dir=rtl"  
3387 -// },  
3388 -// attr(name, value) then  
3389 -// " " + name + "=\"" + value + "\"",  
3390 -// event(e, value) then  
3391 -// " " + event_name(e) + "=\"" + value + "\""  
3392 -// },  
3393 -// current + _format(t)  
3394 -// }  
3395 -// .  
3396 -  
3397 -define Printable_tree  
3398 - format_div_option  
3399 - (  
3400 - List(CoreAttrs) options  
3401 - )=  
3402 - ["<div" + format_attrs(options) + ">"] .  
3403 -  
3404 -  
3405 -define Maybe(String)  
3406 - extract_id  
3407 - (  
3408 - List(CoreAttrs) attrbs  
3409 - ) =  
3410 - if attrbs is  
3411 - {  
3412 - [] then failure,  
3413 - [h . t] then  
3414 - if h is id(value) then success(value)  
3415 - else extract_id(t)  
3416 - }.  
3417 -  
3418 -define Maybe(String)  
3419 - extract_id  
3420 - (  
3421 - Actioner_Aspect aspect  
3422 - ) =  
3423 - if aspect is  
3424 - {  
3425 - link(_,_,_) then failure,  
3426 - img_link(_,_) then failure,  
3427 - push_button(opts,_) then extract_id(opts),  
3428 - button(_,_) then failure,  
3429 - button(_,_,_,_) then failure,  
3430 - submit(opts,_) then extract_id(opts),  
3431 - immediate_selector(_,_,_,_) then failure,  
3432 - immediate_selector(_,_,_,_,_) then failure,  
3433 - }.  
3434 -  
3435 -to do Complete format_foreign_link  
3436 -//TODO Complete format_foreign_link  
3437 -define Printable_tree  
3438 - format_foreign_link  
3439 - (  
3440 -// CommonInfo cinfo,  
3441 - Actioner_Target target,  
3442 - Actioner_Aspect aspect,  
3443 - String url,  
3444 - Bool is_https,  
3445 - ) =  
3446 - //if cinfo is info(common_name,http_port,https_port,site_dir,secret) then  
3447 - with full_url = make_foreign_link_url(target,url),  
3448 -// with action = format_action(full_url, aspect, extract_id(aspect), mb_form_name),  
3449 - if aspect is  
3450 - {  
3451 -  
3452 - link(opt, text, mb_name) then  
3453 - with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",  
3454 - [  
3455 - "<a href=\"", full_url, "\"", format_text_options(opt), name_tag, ">",  
3456 - text,  
3457 - "</a>"  
3458 - ],  
3459 - img_link(img,alt_text) then  
3460 - [  
3461 - "<a href=\"", full_url ,"\"><img src=\"", img,  
3462 - "\" alt=\"" + alt_text + "\" border=\"0\"></a>"  
3463 - ],  
3464 - push_button(options, text) then  
3465 - ["<a href=\"",full_url,"\"", format_attrs(options), ">",  
3466 - text, "</a>"  
3467 - ],  
3468 - button(url_off,url_on) then  
3469 - [ ],  
3470 -  
3471 - button(url_off,url_on,w,h) then  
3472 - [ ],  
3473 -  
3474 - submit(options, text) then  
3475 - [ ],  
3476 -  
3477 - immediate_selector(opt,name,size,choices) then  
3478 - [ ],  
3479 - immediate_selector(opt,name,size,choices,selected) then  
3480 - [ ],  
3481 - }.  
3482 -  
3483 -define Printable_tree  
3484 - format_actioner  
3485 - (  
3486 - CommonInfo cinfo,  
3487 - String state_name,  
3488 - Actioner_Connection connection,  
3489 - Actioner_Target target,  
3490 - Actioner_Aspect aspect,  
3491 - String action_name,  
3492 - List((String,String)) extra_ops,  
3493 - List(Actioner_Local_Action) local_actions,  
3494 - Maybe(String) mb_form_name,  
3495 - Bool is_https,  
3496 - Var(Int) action_count  
3497 - ) =  
3498 - if cinfo is info(common_name,http_port,https_port,site_dir,secret) then  
3499 - with url = make_actioner_url(cinfo,connection,target,  
3500 - state_name,action_name,extra_ops,is_https),  
3501 - with action = format_action(url, aspect, extract_id(aspect), mb_form_name, action_count),  
3502 - if aspect is  
3503 - {  
3504 -  
3505 - link(opt, text, mb_name) then  
3506 - with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",  
3507 - [  
3508 - "<a href=\"", url, "\"", format_text_options(opt), name_tag, ">",  
3509 - text,  
3510 - "</a>"  
3511 - ],  
3512 - img_link(img, alt_text) then  
3513 - [  
3514 - "<a href=\"", url ,"\"><img src=\"", img,  
3515 - "\" alt=\"" + alt_text + "\" border=\"0\"></a>"  
3516 - ],  
3517 - push_button(options, text) then  
3518 - [  
3519 - if action is  
3520 - {  
3521 - url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",  
3522 - text, "</a>"  
3523 - ],  
3524 - javascript(s,h) then  
3525 - if action_name = "" then  
3526 - ["<input type=\"button\" value=\"",text,"\"", format_attrs(options), " />"]  
3527 - else  
3528 - [s,"<input type=\"button\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]  
3529 - }  
3530 - ],  
3531 - button(url_off,url_on) then  
3532 - [ if action is  
3533 - {  
3534 - url(u) then ["<a href=\"",u],  
3535 - javascript(s,h) then [s,"<a onMouseDown=\"",h]  
3536 - },  
3537 - "\" style=\"text-decoration:none\">",  
3538 - "<img alt=\"",url_off,"\" src=\"",url_off,"\" border=0",  
3539 - " onMouseOver=\"this.src='",url_on,"'\" ",  
3540 - " onMouseOut=\"this.src='",url_off,"'\">",  
3541 - "</a>"  
3542 - ],  
3543 -  
3544 - button(url_off,url_on,w,h) then  
3545 - [ if action is  
3546 - {  
3547 - url(u) then ["<a href=\"",u],  
3548 - javascript(s,h2) then [s,"<a onMouseDown=\"",h2]  
3549 - },  
3550 - "\" style=\"text-decoration:none\">",  
3551 - "<img width=",w," height=",h," alt=\"",url_off,"\" src=\"",url_off,"\" border=0",  
3552 - " onMouseOver=\"this.src='",url_on,"'\" ",  
3553 - " onMouseOut=\"this.src='",url_off,"'\">",  
3554 - "</a>"  
3555 - ],  
3556 -  
3557 - submit(options, text) then  
3558 - [  
3559 - if action is  
3560 - {  
3561 - url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",  
3562 - text, "</a>"  
3563 - ],  
3564 - javascript(s,h) then  
3565 - if action_name = "" then // special case where URL (so the action_name) is provided by the form itself  
3566 - // so javascript isn't needed. This is the standard HMTL way.  
3567 - ["<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " />"]  
3568 - else  
3569 - [s,"<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]  
3570 - }  
3571 - ],  
3572 -  
3573 - immediate_selector(options,name,size,choices) then  
3574 - [ if action is  
3575 - {  
3576 - url(u) then ["<select href=\"",u]  
3577 - javascript(s,h) then [s,"<select onchange=\"",h]  
3578 - },  
3579 - "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",  
3580 - format_choices(choices),"</select>"  
3581 - ],  
3582 - immediate_selector(options,name,size,choices,selected) then  
3583 - [ if action is  
3584 - {  
3585 - url(u) then ["<select href=\"",u]  
3586 - javascript(s,h) then [s,"<select onchange=\"",h]  
3587 - },  
3588 - "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",  
3589 - format_choices(choices, selected),"</select>"  
3590 - ],  
3591 - }.  
3592 -  
3593 -  
3594 -  
3595 -  
3596 -  
3597 -  
3598 - *** [5.5] Formating a private download link.  
3599 -  
3600 - We get the absolute path of the file to be downloaded, and the name under which it  
3601 - should appear to the client. The function 'format_private_download' creates an  
3602 - hypertext link for downloading the file. The secured mecanism of private download is  
3603 - used. This function is called by the function which formats HTML_Any($T) elements.  
3604 -  
3605 -  
3606 -define Printable_tree  
3607 - format_private_download  
3608 - (  
3609 - CommonInfo cinfo,  
3610 - String sn, // state name  
3611 - String abs_path, // absolute file path on server  
3612 - String name, // name of file as it appears in the browser  
3613 - String extra, // extra extension  
3614 - Maybe((String,List((String,String)))) action  
3615 -  
3616 - ) =  
3617 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
3618 - with private_download_directory = site_directory+"/private_download",  
3619 - with auth = make_authorization(site_directory,secret,abs_path),  
3620 - [  
3621 - "<a href=\"",name,extra,"?zauth=",auth,  
3622 - if action is  
3623 - {  
3624 - failure then [ ]  
3625 - success(a) then if a is (an,args) then  
3626 - ["&amp;a=",an,format_extra_operands(args)]  
3627 - },  
3628 - "\">",  
3629 - name,  
3630 - "</a>"  
3631 - ].  
3632 -  
3633 -  
3634 -  
3635 -  
3636 - *** [5.6] Formating rows and cells in a table.  
3637 -  
3638 -define Int  
3639 - percent  
3640 - (  
3641 - Int p  
3642 - ) =  
3643 - if p < 0 then 0 else if p > 100 then 100 else p.  
3644 -  
3645 -  
3646 -  
3647 -  
3648 - Formating cell options.  
3649 -  
3650 -  
3651 -  
3652 -define String  
3653 - format  
3654 - (  
3655 - BackgroundOption o  
3656 - ) =  
3657 - if o is  
3658 - {  
3659 - repeat then "",  
3660 - repeat_horizontal then "; background-repeat: repeat-x",  
3661 - repeat_vertical then "; background-repeat: repeat-y",  
3662 - no_repeat then "; background-repeat: no-repeat",  
3663 - center then "; background-position: center top"  
3664 - }.  
3665 -  
3666 -define String  
3667 - format  
3668 - (  
3669 - List(BackgroundOption) l  
3670 - ) =  
3671 - if l is  
3672 - {  
3673 - [ ] then "",  
3674 - [h . t] then format(h)+format(t)  
3675 - }.  
3676 -  
3677 -  
3678 -define String  
3679 - format  
3680 - (  
3681 - List(Cell_Option) options  
3682 - ) =  
3683 - if options is  
3684 - {  
3685 - [ ] then "",  
3686 - [h . t] then  
3687 - if h is  
3688 - {  
3689 - core_attrs(core_attr_list) then format_attrs(core_attr_list),  
3690 - left then " align=\"left\"",  
3691 - h_center then " align=\"center\"",  
3692 - right then " align=\"right\"",  
3693 - top then " valign=\"top\"",  
3694 - v_center then " valign=\"middle\"",  
3695 - bottom then " valign=\"bottom\"",  
3696 - base_line then " valign=\"baseline\"",  
3697 - background_color(c) then " bgcolor=\""+html_format(c)+"\"",  
3698 - background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"",  
3699 - width(w) then " width=\""+w+"\"",  
3700 - percentage_width(n) then " width=\""+percent(n)+"%\"",  
3701 - height(h2) then " height=\""+h2+"\"",  
3702 - columns(n) then " colspan=\""+n+"\"",  
3703 - rows(n) then " rowspan=\""+n+"\"",  
3704 - nowrap then " nowrap",  
3705 - class(class_name) then " class=\""+class_name+"\""  
3706 - }  
3707 - + format(t)  
3708 - }.  
3709 -  
3710 -  
3711 - Normalizing a list of cell options (horizontal position must be specified; the default  
3712 - is 'left').  
3713 -  
3714 - Formating cells in a row.  
3715 -  
3716 -define Printable_tree  
3717 - format  
3718 - (  
3719 - List(HTML_Cell($T)) cells,  
3720 - $T -> Printable_tree format_element  
3721 - ) =  
3722 - if cells is  
3723 - {  
3724 - [ ] then [ ],  
3725 - [h . t] then if h is cell(options,element) then  
3726 - ["<td",format(reverse(options)),">",  
3727 - format_element(element),  
3728 - "</td>"  
3729 - . format(t,format_element)]  
3730 - }.  
3731 -  
3732 -define Printable_tree  
3733 - format  
3734 - (  
3735 - List(HTML_Header_Cell($T)) cells,  
3736 - $T -> Printable_tree format_element  
3737 - ) =  
3738 - if cells is  
3739 - {  
3740 - [ ] then [ ],  
3741 - [h . t] then if h is header_cell(options,element) then  
3742 - ["<th ",format(reverse(options)),">",  
3743 - format_element(element),  
3744 - "</th>"  
3745 - . format(t,format_element)]  
3746 - }.  
3747 -  
3748 - Formating the rows in a table.  
3749 -  
3750 -define Printable_tree  
3751 - format  
3752 - (  
3753 - List(HTML_Row($T)) rows,  
3754 - $T -> Printable_tree format_element,  
3755 - ) =  
3756 - if rows is  
3757 - {  
3758 - [ ] then [ ],  
3759 - [h . t] then if h is row(options,cells) then  
3760 - ["<tr",format(reverse(options)),">",  
3761 - format(cells,format_element),  
3762 - "</tr>\n"  
3763 - . format(t,format_element)]  
3764 - }.  
3765 -  
3766 -define Printable_tree  
3767 - format  
3768 - (  
3769 - HTML_Header_Row($T) row,  
3770 - $T -> Printable_tree format_element  
3771 - ) =  
3772 - if row is  
3773 - {  
3774 - empty then [ ],  
3775 - header_row(options,cells) then  
3776 - ["<thead> <tr",format(reverse(options)),">",  
3777 - format(cells,format_element),  
3778 - "</tr> </thead>\n"  
3779 - ]  
3780 - }.  
3781 -  
3782 -define Printable_tree  
3783 - format  
3784 - (  
3785 - HTML_Footer_Row($T) row,  
3786 - $T -> Printable_tree format_element  
3787 - ) =  
3788 - if row is  
3789 - {  
3790 - empty then [ ],  
3791 - footer_row(options,cells) then  
3792 - ["<tfoot> <tr",format(reverse(options)),">",  
3793 - format(cells,format_element),  
3794 - "</tr> </tfoot>\n"  
3795 - ]  
3796 - }.  
3797 -  
3798 -define Printable_tree  
3799 - format1  
3800 - (  
3801 - List(TextAreaOption) l  
3802 - ) =  
3803 - if l is  
3804 - {  
3805 - [] then [],  
3806 - [h . t] then if h is  
3807 - {  
3808 - input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)],  
3809 - disabled then [" disabled=\"disabled\" " . format1(t)]  
3810 - read_only then [" readonly=\"readonly\" " . format1(t)]  
3811 - wrap_lines then [" wrap=\"wrap\" " . format1(t)]  
3812 - }  
3813 - }.  
3814 -  
3815 -define Printable_tree  
3816 - format  
3817 - (  
3818 - List(TextAreaOption) l  
3819 - ) =  
3820 - if member(l,wrap_lines)  
3821 - then format1(l)  
3822 - else [" wrap=\"off\" " . format1(l)].  
3823 -  
3824 -  
3825 - *** [5.7] Formating elements which may be put anywhere.  
3826 -  
3827 - The function below involves the parameter $T which is later instantiated as  
3828 - 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions  
3829 - for these two types, and because formating of tables requires recursive calls of such  
3830 - functions, it is necessary to provide the 'format' function to be called recursively as  
3831 - an argument. Putting naively a call to 'format' will not work, because the compiler  
3832 - will look for a function able to format data of type $T (which is at that time distinct  
3833 - from any other type, including our two types). Such a function does not exist. Hence  
3834 - the function to be called for formating elements must be passed as a functional  
3835 - argument (called 'format_element' below). Actually, what we pass is a function taking  
3836 - a unique argument of type $T. Other informations (like the name of the state) are  
3837 - already in the function by way of full functionality.  
3838 -  
3839 -  
3840 - Formating text options. They are formated in CSS syntax, to be used within a  
3841 - 'style=...'.  
3842 -  
3843 -define String  
3844 - format  
3845 - (  
3846 - List(Text_Option) l  
3847 - ) =  
3848 - if l is  
3849 - {  
3850 - [ ] then "",  
3851 - [h . t] then if h is  
3852 - {  
3853 - size(n) then "font-size:"+n+"pt",  
3854 - font(fn) then "font-family:"+fn,  
3855 - color(c) then if c is rgb(r,g,b) then  
3856 - "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")",  
3857 - italic then "font-style:italic",  
3858 - oblique then "font-style:oblique",  
3859 - small_capitals then "font-variant:small-caps",  
3860 - bold then "font-weight:bold",  
3861 - underlined then "text-decoration:underline",  
3862 - left_justified then "text-align:left",  
3863 - right_justified then "text-align:right",  
3864 - justified then "text-align:justify",  
3865 - line_through then "text-decoration:line-through",  
3866 - nowrap then "white-space:nowrap",  
3867 - class(class_name)then " class=\"" + class_name +"\"",  
3868 - id(id_name) then " id=\"" + id_name +"\"",  
3869 - style(style_string) then " style=\"" + style_string + "\"",  
3870 - title(s) then " title=\"" + s +"\""  
3871 - attr(n,v) then " " + n + "=\"" + v +"\""  
3872 - } + if t is [ ] then "" else ("; "+format(t))  
3873 - }.  
3874 -  
3875 -  
3876 -  
3877 - Formating table options.  
3878 -  
3879 -define String  
3880 - format  
3881 - (  
3882 - List(Table_Option) l,  
3883 - Bool border_seen  
3884 - ) =  
3885 - if l is  
3886 - {  
3887 - [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"",  
3888 - [h . t] then if h is  
3889 - {  
3890 - background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen),  
3891 - background_image(url) then " background="+url+format(t,border_seen),  
3892 - border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+  
3893 - //" bordercolor="+format(c)+  
3894 - format(t,true),  
3895 - width(w) then " width=\""+w+"\""+format(t,border_seen),  
3896 - percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen),  
3897 - attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen),  
3898 - class(name) then " class=\""+name+"\""  
3899 - }  
3900 - }.  
3901 -  
3902 -  
3903 -  
3904 -  
3905 -  
3906 -define Printable_tree  
3907 - format_scroller  
3908 - (  
3909 - String sn,  
3910 - Int width,  
3911 - Int height,  
3912 - Int content_width,  
3913 - Int content_height,  
3914 - Int idnum, // identifying the scroller  
3915 - $T content,  
3916 - $T -> Printable_tree format_element  
3917 - ) =  
3918 - [  
3919 - "<script type = \"text/javascript\" language=\"JavaScript\">",  
3920 - "function doscroll_",idnum,"(dx,dy) {\n",  
3921 - " if (document.layers) { var c_",idnum," = eval(document.cs_",idnum,"); } else\n",  
3922 - " if (document.getElementById) {var c_",idnum," = eval(\"document.getElementById('cs_",  
3923 - idnum,"').style\"); } else\n",  
3924 - " if (document.all) { var c_",idnum," = eval(document.all.cs_",idnum,".style); };\n",  
3925 - " var x_",idnum," = parseInt(c_",idnum,".left);\n",  
3926 - " var y_",idnum," = parseInt(c_",idnum,".top);\n",  
3927 - " if ((x_",idnum,"+dx <= 0) && (x_",idnum,"+dx > ",width-content_width,"))\n",  
3928 - " { x_",idnum," += dx; }\n",  
3929 - " if ((y_",idnum,"+dy <= 0) && (y_",idnum,"+dy > ",height-content_height,"))\n",  
3930 - " { y_",idnum," += dy; }\n",  
3931 - " c_",idnum,".left = x_",idnum,";\n",  
3932 - " c_",idnum,".top = y_",idnum,";\n",  
3933 - " }\n",  
3934 - "</script>\n",  
3935 - "<table>",  
3936 - "<tbody>",  
3937 - "<tr>",  
3938 - "<td align=left valign=top",  
3939 - " width=",width,  
3940 - " height=",height,  
3941 - ">",  
3942 - "<div id=\"ws_",idnum,"\" style=\"position:absolute; width:",width,"px; height:",height,"px;",  
3943 - " clip:rect(0px ",width,"px ",height,"px 0px)\">",  
3944 - "<div id=\"cs_",idnum,"\" style=\"position:absolute; left:0px; top:0px\">",  
3945 - format_element(content),  
3946 - "</div>",  
3947 - "</div>",  
3948 - "</td>",  
3949 - "<td valign=bottom>",  
3950 - "<table>",  
3951 - "<tbody>",  
3952 - "<tr><td><img alt=\"sroll up\" src=\"scrollup.gif\" onmousedown=\"doscroll_", idnum,"(0,20);\"></td></tr>",  
3953 - "<tr><td><img alt=\"scroll down\" src=\"scrolldown.gif\" onmousedown=\"doscroll_", idnum,"(0,-20);\"></td></tr>",  
3954 - "</tbody>",  
3955 - "</table>",  
3956 - "</td>",  
3957 - "</tr>",  
3958 - (if content_width > width then  
3959 - [  
3960 - "<tr>",  
3961 - "<td align=right>",  
3962 - "<table>",  
3963 - "<tbody>",  
3964 - "<tr>",  
3965 - "<td><img alt=\"scroll left\" src=\"scrollleft.gif\" onmousedown=\"doscroll_", idnum,"(20,0);\"></td>",  
3966 - "<td><img alt=\"scroll right\" src=\"scrollright.gif\" onmousedown=\"doscroll_", idnum,"(-20,0);\"></td>",  
3967 - "</tr>",  
3968 - "</tbody>",  
3969 - "</table>",  
3970 - "</td>",  
3971 - "</tr>",  
3972 - ] else [ ]),  
3973 - "</tbody>",  
3974 - "</table>"  
3975 - ].  
3976 -  
3977 -  
3978 -  
3979 -define Printable_tree  
3980 - format  
3981 - (  
3982 - Body_Option o  
3983 - ) =  
3984 - if o is  
3985 - {  
3986 - core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)],  
3987 - background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""],  
3988 - background_image(n) then [" background=", n],  
3989 - background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""]  
3990 -  
3991 - }.  
3992 -  
3993 -  
3994 -  
3995 -define Printable_tree  
3996 - format  
3997 - (  
3998 - List(Body_Option) l  
3999 - ) =  
4000 - if l is  
4001 - {  
4002 - [ ] then [ ],  
4003 - [h . t] then [format(h) . format(t)]  
4004 - }.  
4005 -  
4006 -define Printable_tree  
4007 - add_css_files  
4008 - (  
4009 - List(CSS_File) l  
4010 - ) =  
4011 - if l is  
4012 - {  
4013 - [ ] then [ ],  
4014 - [h . t] then  
4015 - [ ["<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file_name(h) + "\" />\n" ]  
4016 - . add_css_files(t)]  
4017 - }.  
4018 -  
4019 -define Printable_tree  
4020 - add_js_files_attributes  
4021 - (  
4022 - List(JS_Attribute) l  
4023 - ) =  
4024 - if l is  
4025 - {  
4026 - [ ] then [ ],  
4027 - [h . t] then  
4028 - if h is attr(name, value) then  
4029 - [ " " + name + "=\"" + value + "\""  
4030 - . add_js_files_attributes(t)]  
4031 - }.  
4032 -  
4033 -  
4034 -define Printable_tree  
4035 - add_js_files  
4036 - (  
4037 - List(JS_File) l  
4038 - ) =  
4039 - if l is  
4040 - {  
4041 - [ ] then [ ],  
4042 - [h . t] then  
4043 - [ ["<script src=\""+ file_name(h) +"\" type=\"text/javascript\""  
4044 - . add_js_files_attributes(attributes(h)) ]  
4045 - . ["></script>\n"  
4046 - . add_js_files(t)] ]  
4047 - }.  
4048 -  
4049 -define Printable_tree  
4050 - add_script  
4051 - (  
4052 - List(Script) l  
4053 - ) =  
4054 - if l is  
4055 - {  
4056 - [ ] then [ ],  
4057 - [h . t] then [ "<script type=\""+ script_type(h) +"\">\n"+ content(h) + "\n</script>\n" . add_script(t) ]  
4058 - }.  
4059 -  
4060 -define Printable_tree  
4061 - add_css_styles  
4062 - (  
4063 - List(CSS_Style) css_styles  
4064 - ) =  
4065 -  
4066 - if css_styles is  
4067 - {  
4068 - [] then [],  
4069 - [_ . _] then [ "<style type=\"text/css\"><!--\n",  
4070 - format_css_styles(css_styles),  
4071 - " --></style>\n"  
4072 - ]  
4073 - }.  
4074 -  
4075 -  
4076 - // The function below formats a datum of type 'HTML_Any($T)'.  
4077 -  
4078 -define Printable_tree  
4079 - format  
4080 - (  
4081 - CommonInfo cinfo,  
4082 - String sn, // state_name  
4083 - Var(Int) ic_v,  
4084 - HTML_Any($T) element,  
4085 - $T -> Printable_tree format_element, // able to format a datum of type $T  
4086 - Bool is_https,  
4087 - Var(Int) action_count  
4088 - ) =  
4089 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4090 - if element is  
4091 - {  
4092 - any_text(opts , t) then  
4093 - if opts is  
4094 - {  
4095 - [] then [t],  
4096 - [_ . _] then ["<span", format_text_options(opts), ">",t,"</span>"]  
4097 - },  
4098 - any_preformated(opts,s) then  
4099 - ["<span", format_text_options(opts), "><pre>",s,"</pre></span>"],  
4100 - //["<pre>",s,"</pre>"],  
4101 - any_paragraph(opts,e) then  
4102 - ["<p", format_text_options(opts), ">",format_element(e),"</p>\n"],  
4103 - any_image(opts, url, alt) then  
4104 - ["<img alt=\"",alt,"\" src=\"",url,"\" ", format_attrs(opts)," />"],  
4105 - any_image(opts, url, alt, w, h) then  
4106 - ["<img alt=\"",alt,"\" src=\"",url,"\" width=\"",w,"\" height=\"",h,"\" ", format_attrs(opts)," />"],  
4107 - any_table(opts,h_row, rows, f_row) then  
4108 - ["<table",format(reverse(opts),false),">",  
4109 - format(h_row, format_element),  
4110 - "<tbody>",format(rows,format_element),"</tbody>",  
4111 - format(f_row, format_element),  
4112 - "</table>\n"],  
4113 - any_center(e) then  
4114 - ["<center>",format_element(e),"</center>"],  
4115 - any_mail_to(email,elem) then  
4116 - ["<a href=\"mailto:",email,"\">",format_element(elem),"</a>"],  
4117 - any_scroller(w,h,cw,ch,c) then  
4118 - format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element),  
4119 - any_fixed_size(w,h,c) then  
4120 - with url = create_secondary_document(site_directory,secret,sn,format_element,c,w),  
4121 - ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",  
4122 - "secondary document",  
4123 - "</object>"],  
4124 - any_fixed_size_2(w,h,fn) then  
4125 - with url = fn+"?zauth="+make_authorization(site_directory,secret,  
4126 - fn),  
4127 - ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",  
4128 - "secondary document",  
4129 - "</object>"],  
4130 - any_actioner(c,t,a,an,eo,ja,fn) then  
4131 - format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https, action_count),  
4132 -  
4133 - any_foreign_link_new(target, aspect, url) then  
4134 - format_foreign_link(target, aspect, url, is_https),  
4135 -  
4136 - any_foreign_link(options,url) then  
4137 - ["<a href=\"",url,"\" ", format_text_options(options), "></a>"], // IE7 doesn't support the form <a href="..." />  
4138 - any_foreign_link(options,url,name) then  
4139 - ["<a href=\"",url,"\"><span ", format_text_options(options), ">",name,"</span></a>"],  
4140 - any_private_download(url,name,extra_ext,action) then  
4141 - format_private_download(cinfo,sn,url,name,extra_ext,action),  
4142 - any_div(options, e) then  
4143 - [format_div_option(options), format_element(e),"</div>\n"],  
4144 - any_div_empty(options) then  
4145 - [format_div_option(options), "</div>\n"],  
4146 - any_coreattrs(attributs) then  
4147 - [format_attrs(attributs)]  
4148 - }.  
4149 -  
4150 -  
4151 -  
4152 -  
4153 - // *** [5.8] Formating 'in form' elements.  
4154 -  
4155 -  
4156 -define Printable_tree  
4157 - maybe_label  
4158 - (  
4159 - String label_text,  
4160 - HtmlId id  
4161 - ) =  
4162 - if length(label_text) > 0 then ["<label for=\"",id,"\">",label_text,"</label>"]  
4163 - else [].  
4164 -  
4165 -  
4166 -define Printable_tree  
4167 - format  
4168 - (  
4169 - CommonInfo cinfo,  
4170 - String fn, // form_name  
4171 - String sn, // state_name  
4172 - Var(Int) ic_v, // idnum counter variable  
4173 - HTML_In_Form element,  
4174 - Bool is_https,  
4175 - Var(Int) action_count  
4176 - ) =  
4177 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4178 - with format_element = (HTML_In_Form e) |-> format(cinfo, fn, sn, ic_v, e, is_https, action_count),  
4179 - if element is  
4180 - {  
4181 - literal_pt(t) then t,  
4182 - literal(t) then [t],  
4183 - sequence(l) then flat(map(format_element,l))  
4184 - text(opts,t) then  
4185 - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https, action_count),  
4186 - preformated(o,s) then  
4187 - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https, action_count),  
4188 - paragraph(opts,t) then  
4189 - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https, action_count),  
4190 - image(opts, url, alt) then  
4191 - format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https, action_count),  
4192 - image(opts, url, alt, w, h) then  
4193 - format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https, action_count),  
4194 - table(opts,header_row,rows,footer_row) then  
4195 - format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https, action_count),  
4196 - center(e) then  
4197 - format(cinfo,sn,ic_v,any_center(e),format_element,is_https, action_count),  
4198 - mail_to(a,e) then  
4199 - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https, action_count),  
4200 - scroller(w,h,cw,ch,c) then  
4201 - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https, action_count),  
4202 - actioner(c,t,a,an,eo,ja) then  
4203 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https, action_count),  
4204 -  
4205 - foreign_link_new(target, aspect, url) then  
4206 - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https, action_count),  
4207 -  
4208 - foreign_link(options,url) then  
4209 - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https, action_count),  
4210 - foreign_link(options,url,name) then  
4211 - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https, action_count),  
4212 - private_download(url,name,extra,action) then  
4213 - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https, action_count),  
4214 - text_input(options, label_text, id, name, i, w) then  
4215 - [ maybe_label(label_text, id),  
4216 - "<input type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4217 - text_input_ro(options, label_text, id, name,i,w) then  
4218 - [ maybe_label(label_text, id),  
4219 - "<input readonly=\"readonly\" type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4220 - password_input(options, label_text, id, name,i,w) then  
4221 - [ maybe_label(label_text, id),  
4222 - "<input type=\"password\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4223 - text_area(opts,label_text, id, n,i,w,h) then  
4224 - [ maybe_label(label_text, id), "<textarea ",format(opts)," id=\"",id,"\" name=\"",n,"\" cols=\"",w,"\" rows=\"",h,"\">",i,"</textarea>"],  
4225 - file_upload(options, label, id, n, w) then  
4226 - [ maybe_label(label, id),  
4227 - "<input type=\"file\" id=\"",id,"\" size=\"",w,"\" name=\"",n,"\"",format_attrs(options)," />"],  
4228 - selector(opts, label, id, n,s,cs) then  
4229 - [ maybe_label(label, id),  
4230 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],  
4231 - selector(opts, label, id, n,s,cs,sd) then  
4232 - [ maybe_label(label, id),  
4233 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],  
4234 - selector_c(opts, label, id, n,s,cs) then  
4235 - [ maybe_label(label, id),  
4236 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],  
4237 - selector_c(opts, label, id, n,s,cs,sd) then  
4238 - [ maybe_label(label, id),  
4239 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],  
4240 -  
4241 - radio_button(options, label_text, id, n, v, c) then  
4242 - [ maybe_label(label_text, id),  
4243 - "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />"],  
4244 - radio_button_r(options, label_text, id, n, v, c) then  
4245 - [ "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />",  
4246 - maybe_label(label_text, id)],  
4247 - check_box(options, label_text, id, n, v, c) then  
4248 - [ maybe_label(label_text, id),  
4249 - "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />"]  
4250 - check_box_r(options, label_text, id, n, v, c) then  
4251 - [ "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />",  
4252 - maybe_label(label_text, id)]  
4253 - div(options, e) then  
4254 - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https, action_count),  
4255 - div_empty(options) then  
4256 - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https, action_count),  
4257 - hidden(id, name, value) then  
4258 - ["<input type=\"hidden\" id=\"",id,"\" name=\"",name,"\" value=\"",value,"\" />"],  
4259 -  
4260 - }.  
4261 -  
4262 -  
4263 -  
4264 -  
4265 -  
4266 -  
4267 - *** [5.9] Formating 'off form' elements.  
4268 -  
4269 - The encryption type 'multipart/form-data' is required for a form containing an upload.  
4270 -  
4271 -  
4272 -define Bool  
4273 - contains_an_upload  
4274 - (  
4275 - HTML_In_Form form_content  
4276 - ).  
4277 -  
4278 -define Bool  
4279 - contains_an_upload  
4280 - (  
4281 - HTML_Row(HTML_In_Form) row  
4282 - ) =  
4283 - mapor(contains_an_upload,  
4284 - map(content,cells(row))).  
4285 -  
4286 -define Bool  
4287 - contains_an_upload  
4288 - (  
4289 - HTML_Footer_Row(HTML_In_Form) row  
4290 - ) =  
4291 - if row is  
4292 - {  
4293 - empty then false,  
4294 - footer_row(_, cells) then  
4295 - mapor(contains_an_upload,  
4296 - map(content,cells))  
4297 - }.  
4298 -  
4299 -define Bool  
4300 - contains_an_upload  
4301 - (  
4302 - HTML_In_Form form_content  
4303 - ) =  
4304 - if form_content is  
4305 - {  
4306 - literal_pt(t) then false,  
4307 - literal(t) then false,  
4308 - sequence(l) then mapor(contains_an_upload,l)  
4309 - text(o,t) then false,  
4310 - preformated(o,s) then false,  
4311 - paragraph(o,t) then false,  
4312 - image(o,u,a) then false,  
4313 - image(o,u,a,w,h) then false,  
4314 - table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true  
4315 - else contains_an_upload(f_row),  
4316 - center(e) then contains_an_upload(e),  
4317 - mail_to(m,e) then false, // 'e' may but should not contain an upload  
4318 - scroller(w,h,cw,ch,e) then contains_an_upload(e),  
4319 - actioner(c,t,a,an,eo,ja) then false,  
4320 - foreign_link_new(_,_,_) then false,  
4321 - foreign_link(o,u) then false,  
4322 - foreign_link(o,u,n) then false,  
4323 - private_download(p,n,e,a) then false,  
4324 - text_input(o,lt,l,n,i,w) then false,  
4325 - text_input_ro(o,lt,l,n,i,w) then false,  
4326 - password_input(o,lt,l,n,i,w) then false,  
4327 - text_area(o,lt,id,n,i,w,h) then false,  
4328 - file_upload(o,l,i,n,w) then true,  
4329 - selector(o,l,i,n,s,c) then false,  
4330 - selector(o,l,i,n,s,c,p) then false,  
4331 - selector_c(o,l,i,n,s,c) then false,  
4332 - selector_c(o,l,i,n,s,c,p) then false,  
4333 - radio_button(o,_,_,n,v,c) then false,  
4334 - radio_button_r(o,_,_,n,v,c) then false,  
4335 - check_box(o,_,_,n,v,c) then false,  
4336 - check_box_r(o,_,_,n,v,c) then false,  
4337 - div(o,c) then contains_an_upload(c),  
4338 - div_empty(o) then false,  
4339 - hidden(_,_,_) then false  
4340 - }.  
4341 -  
4342 -define String  
4343 - enctype  
4344 - (  
4345 - HTML_In_Form form_content  
4346 - ) =  
4347 - if contains_an_upload(form_content)  
4348 - then " enctype=\"multipart/form-data\""  
4349 - else "".  
4350 -  
4351 -  
4352 -  
4353 -define Printable_tree  
4354 - format  
4355 - (  
4356 - CommonInfo cinfo,  
4357 - String sn, // state_name  
4358 - Var(Int) ic_v, // 'idnum' counter variable  
4359 - HTML_Off_Form element,  
4360 - Bool is_https,  
4361 - Var(Int) action_count  
4362 - ) =  
4363 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4364 - with format_element = (HTML_Off_Form e) |-> format(cinfo, sn, ic_v, e, is_https, action_count),  
4365 - if element is  
4366 - {  
4367 - literal_pt(t) then t,  
4368 - literal(t) then [t],  
4369 - sequence(l) then flat(map(format_element,l)),  
4370 - text(opts,t) then  
4371 - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https, action_count),  
4372 - preformated(o,s) then  
4373 - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https, action_count),  
4374 - paragraph(opts,t) then  
4375 - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https, action_count),  
4376 - image(opts,url,alt) then  
4377 - format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https, action_count),  
4378 - image(opts,url,alt,w,h) then  
4379 - format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https, action_count),  
4380 - table(opts,header_row, rows, footer_row) then  
4381 - format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https, action_count),  
4382 - center(e) then  
4383 - format(cinfo,sn,ic_v,any_center(e),format_element,is_https, action_count),  
4384 - mail_to(a,e) then  
4385 - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https, action_count),  
4386 - scroller(w,h,cw,ch,c) then  
4387 - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https, action_count),  
4388 - fixed_size(w,h,c) then  
4389 - format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https, action_count),  
4390 - fixed_size_2(w,h,fn) then  
4391 - format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https, action_count),  
4392 - actioner(c,t,a,an,eo,ja) then  
4393 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https, action_count),  
4394 - actioner(c,t,a,an,eo,ja,fn) then  
4395 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https, action_count),  
4396 - foreign_link_new(target, aspect, url) then  
4397 - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https, action_count),  
4398 - foreign_link(options,url) then  
4399 - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https, action_count),  
4400 - foreign_link(options,url,name) then  
4401 - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https, action_count),  
4402 - private_download(url,name,extra,action) then  
4403 - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https, action_count),  
4404 - label(n) then ["<a name=\"",n,"\">"],  
4405 - form(fn,attributs, c) then  
4406 - [  
4407 - "<form id=\"",fn,"\"",  
4408 - format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https, action_count),  
4409 - " method=\"post\"",  
4410 - enctype(c),  
4411 - " action=\"http",  
4412 - if is_https then "s" else "",  
4413 - "://",common_name,":",to_decimal(http_port),"/\">",  
4414 - // action is set dynamically by  
4415 - // the actioner using JavaScript  
4416 - if fn is htmlId(id) then  
4417 - format(cinfo,id,sn,ic_v,c,is_https, action_count),  
4418 - "</form>"  
4419 - ]  
4420 - form(fn,attributs, action_name, extra_ops, c) then  
4421 - with url = make_actioner_url(cinfo, same, same,  
4422 - sn, action_name, extra_ops, is_https),  
4423 - [  
4424 - "<form id=\"",fn,"\"",  
4425 - format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https, action_count),  
4426 - " method=\"post\"",  
4427 - enctype(c),  
4428 - " action=\"" + url + "\">",  
4429 -// " action=\"http",  
4430 -// if is_https then "s" else "",  
4431 -// "://",common_name,":",http_port,"/\">",  
4432 - // action is set dynamically by  
4433 - // the actioner using JavaScript  
4434 - if fn is htmlId(id) then  
4435 - format(cinfo,id,sn,ic_v,c,is_https, action_count),  
4436 - "</form>"  
4437 - ]  
4438 - div(options, e) then  
4439 - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https, action_count),  
4440 - div_empty(options) then  
4441 - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https, action_count),  
4442 - iframe(options, css_styles, css_files, js_files, body) then  
4443 - if body is body(body_options,element) then  
4444 - [ "<iframe", format_attrs(options), ">\n",  
4445 - "<html style=\"margin: 0pt; padding: 0pt;\">\n",  
4446 - "<head>\n",  
4447 - add_css_styles(css_styles),  
4448 - add_css_files(css_files),  
4449 - add_js_files(js_files),  
4450 - "</head>\n",  
4451 - "<body ", format(body_options), ">\n", // format body options  
4452 - format(cinfo,sn,ic_v,element,is_https, action_count),  
4453 - "</body>\n",  
4454 - "</html>\n",  
4455 - "</iframe>\n",  
4456 - ],  
4457 -  
4458 - }.  
4459 -  
4460 -  
4461 -  
4462 -  
4463 - *** [5.10] Formating meta-tags.  
4464 -  
4465 -define Printable_tree  
4466 - format_keywords  
4467 - (  
4468 - List(String) l  
4469 - ) =  
4470 - if l is  
4471 - {  
4472 - [] then [ ],  
4473 - [h . t] then if t is []  
4474 - then [h]  
4475 - else [h , ", " . format_keywords(t)]  
4476 - }.  
4477 -  
4478 -  
4479 -define Printable_tree  
4480 - format  
4481 - (  
4482 - CommonInfo cinfo,  
4483 - String state_name,  
4484 - HTML_Meta m,  
4485 - Bool is_https  
4486 - ) =  
4487 - if m is  
4488 - {  
4489 - keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],  
4490 - refresh(co,ta,an,delay) then  
4491 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",  
4492 - make_actioner_url(cinfo,co,ta,state_name,an,[],is_https),"\" />\n"],  
4493 - refresh(url,delay) then  
4494 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],  
4495 - meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],  
4496 - http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],  
4497 - generic_meta(l) then ["<meta ",  
4498 - flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],  
4499 - l)),  
4500 - " />\n"],  
4501 - literal(s) then [s]  
4502 - }.  
4503 -  
4504 -define Printable_tree // c'est le nรดtre et c'est meilleur  
4505 - format  
4506 - (  
4507 - HTML_Meta m,  
4508 - ) =  
4509 - if m is  
4510 - {  
4511 - keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],  
4512 - refresh(co,ta,an,delay) then  
4513 - ["<!-- TODO refresh(co,ta,an,delay) --> "], // TODO  
4514 - refresh(url,delay) then  
4515 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],  
4516 - meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],  
4517 - http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],  
4518 - generic_meta(l) then ["<meta ",  
4519 - flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],  
4520 - l)),  
4521 - " />\n"],  
4522 - literal(s) then [s]  
4523 - }.  
4524 -  
4525 -  
4526 -define Printable_tree  
4527 - format  
4528 - (  
4529 - CommonInfo cinfo,  
4530 - String state_name,  
4531 - List(HTML_Meta) metas,  
4532 - Bool is_https,  
4533 - String charset  
4534 - ) =  
4535 - if metas is  
4536 - {  
4537 - [] then [format(cinfo,state_name,http_equiv("content-type",  
4538 - "text/html; charset="+charset),is_https)],  
4539 - [h . t] then [format(cinfo,state_name,h,is_https)  
4540 - . format(cinfo,state_name,t,is_https,charset)]  
4541 - }.  
4542 -  
4543 -define Printable_tree  
4544 - _format_html_head  
4545 - (  
4546 - List(HTML_Head_Tag) lwf,  
4547 - Printable_tree so_far  
4548 - )  
4549 - =  
4550 - if lwf is  
4551 - {  
4552 - [] then reverse(so_far),  
4553 - [ h . t] then  
4554 - if h is  
4555 - {  
4556 - meta(meta) then  
4557 - [format(meta) . _format_html_head(t, so_far)],  
4558 - title(title) then  
4559 - ["<title>"+title+"</title>\n" . _format_html_head(t, so_far)],  
4560 - js(jsf) then  
4561 - [add_js_files([jsf]) . _format_html_head(t, so_far)],  
4562 - js_inline(jsi) then  
4563 - ["<script>"+content(jsi)+"</script>\n" . _format_html_head(t, so_far)],  
4564 - css(cssf) then  
4565 - ["<link rel=\"stylesheet\" type=\"text/css\" href=\""+file_name(cssf)+"\" />\n" . _format_html_head(t, so_far)],  
4566 - css_inline(cssi) then  
4567 - ["<style>"+cssi+"</style>\n" . _format_html_head(t, so_far)]  
4568 - }  
4569 - }  
4570 - .  
4571 -  
4572 -public define Printable_tree  
4573 - format_html_head  
4574 - (  
4575 - List(HTML_Head_Tag) lwf,  
4576 - String charset  
4577 - )  
4578 - =  
4579 - with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf],  
4580 - if lwf is  
4581 - {  
4582 - [] then  
4583 - [],  
4584 - [ h . t] then  
4585 - _format_html_head(lwf, [])  
4586 - }  
4587 - .  
4588 -  
4589 -define Printable_tree  
4590 - format  
4591 - (  
4592 - CommonInfo cinfo,  
4593 - String state_name,  
4594 - List(HTTP_header) additional_headers,  
4595 - HTTP_Answer page,  
4596 - Bool is_https,  
4597 - String charset  
4598 - ) =  
4599 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4600 - with ic_v = var((Int)0),  
4601 - if page is  
4602 - {  
4603 - html_page(status, head_tags, body) then  
4604 - if body is body(options,element) then  
4605 - if format(status) is (status_string, status_headers) then  
4606 - with answer_body =  
4607 - [doctype_w3c_header,  
4608 - html_header,  
4609 -  
4610 - "<head>\n", format_html_head(head_tags, charset),"</head>\n",  
4611 -  
4612 - "<body ", format(options), ">", // format body options  
4613 - format(cinfo,state_name,ic_v,element,is_https, var(0)),  
4614 - "</body>\n",  
4615 -  
4616 - "</html>"],  
4617 - [ "HTTP/1.1 " + status_string, crlf,  
4618 - format_headers(standard_headers),  
4619 - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),  
4620 - format_headers(status_headers),  
4621 - format_headers(additional_headers),  
4622 - crlf  
4623 - . answer_body  
4624 - ]  
4625 -  
4626 - html_page(status, title, metas, css_styles, css_files, js_files, script, body) then  
4627 - if body is body(options,element) then  
4628 - if format(status) is (status_string, status_headers) then  
4629 - with answer_body =  
4630 - [ doctype_w3c_header,  
4631 - html_header,  
4632 - "<head>\n",  
4633 - add_css_styles(css_styles),  
4634 - add_css_files(css_files),  
4635 - add_js_files(js_files),  
4636 - add_script(script),  
4637 - "<link rel=\"shortcut icon\" href=\"favicon.ico\" />\n",  
4638 - "<script type = \"text/javascript\" language=\"JavaScript\">",  
4639 - " function show_local_popup(divname,stvname) {",  
4640 - " if (document.layers) { var d = eval(document.divname); } else\n",  
4641 - " if (document.getElementById) { var d = eval(\"document.getElementById(divname)\"); } else\n",  
4642 - " if (document.all) { var d = eval(document.all.divname.style)};\n",  
4643 - // " alert(typeof(eval(stvname))); ",  
4644 - " var s = eval(stvname); ",  
4645 - " if (s[0]==0) ",  
4646 - " { s[0]=1; d.style.visibility = 'visible'; d.zIndex = 100; } else\n",  
4647 - " { s[0]=0; d.style.visibility = 'hidden'; }; }",  
4648 - "</script>\n",  
4649 - "<title>",title,"</title>\n", // put title  
4650 - format(cinfo,state_name,metas,is_https,charset), // format the metas  
4651 - "</head>\n",  
4652 - "<body ", format(options), ">", // format body options  
4653 - //"<center>",  
4654 - format(cinfo,state_name,ic_v,element,is_https, var(0)),  
4655 - //"</center>",  
4656 - "</body>\n",  
4657 - "</html>"  
4658 - ],  
4659 - [ "HTTP/1.1 " + status_string, crlf,  
4660 - format_headers(standard_headers),  
4661 - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),  
4662 - format_headers(status_headers),  
4663 - format_headers(additional_headers),  
4664 - crlf  
4665 - . answer_body  
4666 - ],  
4667 -  
4668 - plain_text (HTTP_Status status, String text) then  
4669 - if format(status) is (status_string, status_headers) then  
4670 - [ "HTTP/1.1 " + status_string, crlf,  
4671 - format_headers(standard_headers),  
4672 - format_headers(standard_headers_for("text/plain", length(text), success(charset))),  
4673 - format_headers(status_headers),  
4674 - format_headers(additional_headers),  
4675 - crlf,  
4676 - text . (Printable_tree)[]  
4677 - ],  
4678 -  
4679 - custom_text(HTTP_Status status, String mime_type, String content) then  
4680 - if format(status) is (status_string, status_headers) then  
4681 - [ "HTTP/1.1 " + status_string, crlf,  
4682 - format_headers(standard_headers),  
4683 - format_headers(standard_headers_for(mime_type, length(content), success(charset))),  
4684 - format_headers(status_headers),  
4685 - format_headers(additional_headers),  
4686 - crlf,  
4687 - content . (Printable_tree)[]  
4688 - ],  
4689 - custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then  
4690 - if format(status) is (status_string, status_headers) then  
4691 - [ "HTTP/1.1 " + status_string, crlf,  
4692 - format_headers(status_headers),  
4693 - format_headers(standard_headers_for(mime_type, length(content), failure)),  
4694 - format_headers(status_headers),  
4695 - format_headers(other_headers),  
4696 - format_headers(additional_headers),  
4697 - crlf,  
4698 - content . (Printable_tree)[]  
4699 - ],  
4700 -  
4701 - custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then  
4702 - if format(status) is (status_string, status_headers) then  
4703 - [ "HTTP/1.1 " + status_string, crlf,  
4704 - format_headers(standard_headers),  
4705 - format_headers(standard_headers_for(mime_type, length(content), success(charset))),  
4706 - format_headers(status_headers),  
4707 - format_headers(additional_headers),  
4708 - crlf .  
4709 - content  
4710 - ],  
4711 -  
4712 - http_raw(Printable_tree content) then content,  
4713 -  
4714 - html_content(HTTP_Status status, HTML_Off_Form content_HTML) then  
4715 - if format(status) is (status_string, status_headers) then  
4716 - with content = format(cinfo, state_name, ic_v, content_HTML, is_https, var(0)),  
4717 - [ "HTTP/1.1 " + status_string, crlf,  
4718 - format_headers(standard_headers),  
4719 - format_headers(standard_headers_for("text/html", length(content), success(charset))),  
4720 - format_headers(status_headers),  
4721 - format_headers(additional_headers),  
4722 - crlf .  
4723 - content  
4724 - ],  
4725 - }.  
4726 - 1 +๏ปฟ
  2 +
  3 + *Project* Anubis
  4 +
  5 + *Title* Making interactive Web sites.
  6 +
  7 + *Copyright* Copyright (c) Alain Proutรฉ 2004-2005.
  8 + Copyright (c) Calexium 2007.
  9 +
  10 +
  11 + *Authors* Alain Proutรฉ
  12 + David Renรฉ
  13 +
  14 + *Revised* May 2007
  15 +
  16 +
  17 + *Overview*
  18 +
  19 + In this file we propose simple tools for making well structured interactive and secured
  20 + web sites.
  21 +
  22 +
  23 + ----------------------------------- Table of Contents ---------------------------------
  24 +
  25 + * (1) Structure of a web site.
  26 + ** (1.1) Three sorts of data.
  27 + ** (1.2) How requests are handled.
  28 + ** (1.3) What web pages are made of.
  29 + ** (1.4) Actions.
  30 + ** (1.5) States.
  31 +
  32 + * (2) Carrying on.
  33 + ** (2.1) Describing your web sites.
  34 + ** (2.2) Directories on the server's disk.
  35 + ** (2.3) Starting your web sites.
  36 +
  37 + * (3) The HTML interface.
  38 + ** (3.1) Types used by the HTML interface.
  39 + ** (3.2) ``in form'' versus ``off form''.
  40 + ** (3.3) Defining your own style.
  41 + ** (3.4) Actioners and forms.
  42 + ** (3.5) Local popup.
  43 +
  44 + ---------------------------------------------------------------------------------------
  45 +
  46 +
  47 +read tools/basis.anubis
  48 +read tools/printable_tree.anubis
  49 +read tools/base64.anubis
  50 +read system/string.anubis
  51 +read system/logger.anubis
  52 +read CXM_common.anubis
  53 +read CXM_multihost_http_server.anubis
  54 +read web/mime.anubis
  55 +read CXM_cookies.anubis
  56 +
  57 +
  58 + * (1) Structure of a web site.
  59 +
  60 + First of all we need to explain what a web site should be made of. Ideally, the
  61 + visitor (also called the 'client') should see the web site working as any other
  62 + interactive computer software. So, it should be clear that a 'session' (i.e. a visit
  63 + to the web site, including the consultation of several pages) is some kind of
  64 + conversation between the visitor and the web site, and that the web site should
  65 + maintain a 'current state' of this conversation. At each new request (click) from the
  66 + visitor, this state must be updated. This whole conversation is called a 'session' and
  67 + should not be confused with a single request.
  68 +
  69 +
  70 +
  71 + ** (1.1) Three sorts of data.
  72 +
  73 + All the data needed for putting a web site at work may be dispatched into three
  74 + categories:
  75 +
  76 + 1. Constant data (data that never change). These data may be hard coded into the
  77 + Anubis source files of the web site.
  78 +
  79 + 2. Permanent data (data which always exist independantly of the users connected to
  80 + the web site). These data are normally recorded into data bases.
  81 +
  82 + 3. Session data (data which depend on a particular visitor and which exist only
  83 + during the time he visits the web site). These data are stored into so-called
  84 + 'states'.
  85 +
  86 +
  87 + It is important to determine which data belongs to which category. This is part of your
  88 + design decisions.
  89 +
  90 +
  91 +
  92 + ** (1.2) How requests are handled.
  93 +
  94 + We want to separate the following two functionalities (which are used at each request
  95 + (click) during a single session):
  96 +
  97 + - computing the new state from the previous state and from the client request, and
  98 + updating the data base,
  99 +
  100 + - computing the page to be sent to the client from the new current state and from
  101 + the informations in the data base.
  102 +
  103 +
  104 + The next picture shows the structure we have in mind:
  105 +
  106 +
  107 + request +---------+ HTML page (with a hidden state name)
  108 + .-------------------| client |<--------------.
  109 + | .-----------------| | |
  110 + | | previous state +---------+ |
  111 + | | name (if any) |
  112 + | | | client side
  113 + ............................................................................
  114 + | | | server side
  115 + | | |
  116 + | | .-------------------. |
  117 + | | | previous state | |
  118 + V V V | |
  119 + +---------------+ +---------------+ +--------------+
  120 + | compute state | | server's disk | | compute page |
  121 + +---------------+ +---------------+ +--------------+
  122 + ^ | | ^ ^ ^ ^ ^
  123 + | | | | | | | |
  124 + | | `--------------------+--------------------' | |
  125 + | | new state | | |
  126 + read | `------------------------+--------------------' |
  127 + write | new state name |
  128 + update V |
  129 + +-----------+ |
  130 + | data base |--------------------------------------------'
  131 + +-----------+ read only
  132 +
  133 +
  134 + When the client begins a session, there is no previous state. In this case, a default
  135 + 'initial state' is used instead.
  136 +
  137 + The data base may be updated by 'compute state' box, but should not be update by the
  138 + 'compute page' box. The 'compute page' box should be allowed only to read the data
  139 + base.
  140 +
  141 + In this file, all the above stuff is defined, except the 'compute state' and 'compute
  142 + page' boxes. You just have to provide the function for computing a new state (compute
  143 + state) and the function for computing the page (compute page) from the new state. You
  144 + don't have to worry about state names, saving and retrieving states and the like.
  145 +
  146 +
  147 +
  148 +
  149 +
  150 + ** (1.3) What web pages are made of.
  151 +
  152 + What the client can see in his browser's window may be called a 'page'. Within a page,
  153 + we have several sorts of components:
  154 +
  155 + - 'local' components, i.e. all components which do not open a connection, like
  156 + texts, images, etc... possibly using JavaScript programmation,
  157 +
  158 + - 'actioners', which, when clicked upon, open a connection with our web site; they
  159 + may appear as links or buttons, etc...
  160 +
  161 + - 'foreign links', which when clicked upon, open a connection with another web site
  162 + (or ours eventually).
  163 +
  164 + Of course, what an actioner does is just ask our web site to perform an action. To that
  165 + end, the actioner essentially sends the name of the action to be performed. However, it
  166 + may be necessary to provide additional informations which may be seen as 'operands' of
  167 + the action. In order to attach operands to an action, HTML provides the notion of
  168 + 'form'. Indeed, a form contains essentially a set of input fields into which the client
  169 + may put values for the required operands of the action, and a submit button, which is
  170 + the actioner itself. Notice that a single form may contain several submit buttons,
  171 + which simply means that there are several distincts actions taking the same set of
  172 + operands.
  173 +
  174 + Restrictions must be put on the use of all theses gadgets. Indeed, for example,
  175 + putting a form within another form is officially meaningless in HTML, and the client's
  176 + browser may be seriously disturbed by this. In this file, we propose an interface to
  177 + the HTML language, which forbids such meaningless things, simply by imposing a strict
  178 + typing of HTML concepts.
  179 +
  180 + Each web site may be accessible through two communication channels:
  181 +
  182 + - a non secured channel (HTTP),
  183 + - a secured channel (HTTPS).
  184 +
  185 + Nevertheless, the whole thing should be considered as a single web site. For example,
  186 + you may have a secured page, obtained through HTTPS, containing public images obtained
  187 + through HTTP. An actioner in a non secured page may open a secured connection, and
  188 + conversely.
  189 +
  190 + Summarizing, a web page is made of local elements, foreign links and actioners.
  191 + Actioners receive operands from forms, and they also choose to communicate through the
  192 + non secured or through the secured channel.
  193 +
  194 +
  195 +
  196 + +-------------------+
  197 + | page |
  198 + | | +---------------+
  199 + | +--------------+ | | next page |
  200 + | | form | | | (non secured) |
  201 + | | +----------+ | | HTTP | |
  202 + | | | actioner |---------------------------->| |
  203 + | | +----------+ | | +---------------+
  204 + | | | |
  205 + | | +----------+ | | +---------------+
  206 + | | | actioner |---------------------------->| next page |
  207 + | | +----------+ | | HTTPS | (secured) |
  208 + | | | | | |
  209 + | +--------------+ | | |
  210 + | | +---------------+
  211 + | |
  212 + +-------------------+
  213 +
  214 +
  215 + Notice that actioners need no be necessarily put into forms. In that case, they work as
  216 + ordinary links, but they still may receive operands as we shall see.
  217 +
  218 +
  219 +
  220 +
  221 + ** (1.4) Actions.
  222 +
  223 + The client opens a new connection with our web site whenever he clicks on an
  224 + actioner. The result is that a request is sent, essentially made of a list of 'web
  225 + arguments'. Each web argument is a pair (name,value). One of these web arguments, the
  226 + 'action' web argument (whose name is "a"), determines the action to be performed. The
  227 + other web arguments (not including "s", used to identify the state) are the operands
  228 + for this action.
  229 +
  230 + Hence, the 'compute state' box in the picture above, splits naturally into as many
  231 + sub-boxes as there are actions. For this reason, we define the following type for
  232 + representing actions (where '$State' is the type representing session informations):
  233 +
  234 +public type Web_Action($State):
  235 + http_action (String name, // name of action
  236 + ($State) -> Bool allow, // true if action allowed
  237 + (HTTP_Info http_info,
  238 + List(Web_arg) web_args, // actually only 'operands' web arguments
  239 + $State state) -> $State do_it),
  240 + https_action (String name, // name of action
  241 + ($State) -> Bool allow, // true if action allowed
  242 + (HTTP_Info http_info,
  243 + List(Web_arg) web_args, // actually only 'operands' web arguments
  244 + $State state) -> $State do_it),
  245 + http_https_action (String name,
  246 + ($State) -> Bool allow,
  247 + (HTTP_Info http_info,
  248 + List(Web_arg) web_args,
  249 + $State state) -> $State do_it).
  250 +
  251 + 'http_action's are executed only under HTTP, and 'https_action's are executed only
  252 + under HTTPS. 'http_https_action's may be executed under both types of connections.
  253 +
  254 + Each action has a name, which is used to identify the action. Each action also has a
  255 + function 'allow' whose job is to verify that the action is allowed in the current
  256 + state, and a function 'do_it' for performing the action. The function 'do_it' receives
  257 + a lot of informations:
  258 +
  259 + - 'HTTP informations':
  260 + - the IP address of the client,
  261 + - the URI requested by the client (after redirection),
  262 + - the list of HTTP headers generated by the client's browser,
  263 + - the list of web arguments sent by the client (except "s" and "a"),
  264 + - the previous state (or the 'initial' or 'ticket expired' state if no previous
  265 + state can be found).
  266 +
  267 + In most cases, HTTP informations are not used. This is the reason why they are gathered
  268 + for simplicity into a unique datum of type 'HTTP_Info'.
  269 +
  270 +// For your convenience, we introduce the following simpler variants:
  271 +//
  272 +//public define Web_Action($State)
  273 +// http_action
  274 +// (
  275 +// String name,
  276 +// $State -> Bool allow,
  277 +// (List(Web_arg),$State) -> $State do_it
  278 +// ) =
  279 +// http_action(name,
  280 +// (Maybe($State) ms) |-> if ms is
  281 +// {
  282 +// failure then true,
  283 +// success(s) then allow(s)
  284 +// },
  285 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  286 +// {
  287 +// failure then (failure, []),
  288 +// success(s2) then (success(do_it(l,s2)), [])
  289 +// }).
  290 +//
  291 +//public define Web_Action($State)
  292 +// https_action
  293 +// (
  294 +// String name,
  295 +// $State -> Bool allow,
  296 +// (List(Web_arg),$State) -> $State do_it
  297 +// ) =
  298 +// https_action(name,
  299 +// (Maybe($State) ms) |-> if ms is
  300 +// {
  301 +// failure then true,
  302 +// success(s) then allow(s)
  303 +// },
  304 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  305 +// {
  306 +// failure then (failure, []),
  307 +// success(s2) then (success(do_it(l,s2)), [])
  308 +// }).
  309 +//
  310 +//public define Web_Action($State)
  311 +// http_https_action
  312 +// (
  313 +// String name,
  314 +// $State -> Bool allow,
  315 +// (List(Web_arg),$State) -> $State do_it
  316 +// ) =
  317 +// http_https_action(name,
  318 +// (Maybe($State) ms) |-> if ms is
  319 +// {
  320 +// failure then true,
  321 +// success(s) then allow(s)
  322 +// },
  323 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  324 +// {
  325 +// failure then (failure, []),
  326 +// success(s2) then (success(do_it(l,s2)), [])
  327 +// }).
  328 +
  329 +
  330 +
  331 + When you define your web site, you must provide the list of all the actions of the
  332 + site. When a new state has been computed, a graphical representation of this state
  333 + must be sent to the client. To that end, you must provide a function (named below
  334 + 'compute_page') of type:
  335 +
  336 + $State -> HTTP_Answer
  337 +
  338 + where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML
  339 + pages.
  340 +
  341 +public type HTTP_Answer:...
  342 +
  343 + It should be clear that states and pages are deeply linked together. Indeed, we really
  344 + understand the page shown to the client as a representation of the current state of the
  345 + conversation between the client and the web site, but also containing informations
  346 + taken from the data bases.
  347 +
  348 +
  349 +
  350 +
  351 +
  352 + ** (1.5) States.
  353 +
  354 + Now, we explain how you can define the type (say 'State') to be used as an instance of
  355 + the type parameter '$State'. The following is just a suggestion.
  356 +
  357 + Each state determines a page (since 'compute_page' computes a page from a
  358 + state). However, some components of the state may be independant of the page. It may be
  359 + the case for example for the indication of the natural language used by the
  360 + client. Hence, a state should be made of (at least) two parts:
  361 +
  362 + - informations which are the same for all pages,
  363 + - informations which are particular to each page.
  364 +
  365 + For example, you could define:
  366 +
  367 + type Page: // one alternative per page, with particular informations
  368 + login(...), // in the components
  369 + main_page(...),
  370 + ...etc...
  371 +
  372 + Now, the type 'State' could be defined as follows:
  373 +
  374 + type State:
  375 + state(Language, // informations valid for all pages
  376 + ...,
  377 + Page). // informations particular to a page
  378 +
  379 + However, if you are making a secured web site within which clients should be identified
  380 + (by id and password), it may be a good idea to have two sorts of states, one for non
  381 + identified clients and one for identified clients. In this case, define the type
  382 + 'State' as follows (this is just a suggestion):
  383 +
  384 + type State:
  385 + non_identified(Language),
  386 + identified(String id,
  387 + Language,
  388 + Page).
  389 +
  390 + When a request arrives, check if the previous state is 'identified(...)' or
  391 + 'non_identified(...)', and don't provide access to certain pages to non identified
  392 + clients. This is required for security.
  393 +
  394 + Some more words on security. If your site needs to identify clients, define the
  395 + initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and
  396 + password of the client. If the id and password are correct, then change the state of
  397 + the client to 'identified(...)'. No other action should be able to do that. Now, be
  398 + confident that clients cannot forge states. The only information they have is the name
  399 + of a state, not the state itself which is never sent over the network, but only stored
  400 + on the server's disk. The name of the state is constructed using strong cryptographical
  401 + methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even
  402 + state names cannot be seen by a third party. So, if the system retrieves a previous
  403 + state of the form 'identified(...)', you can be confident that your client is well
  404 + identified, and you can send him confidential informations.
  405 +
  406 + States have a limited life time. It may happen that a client clicks on a button at a
  407 + time its state is out of date. In this case, this system considers that the new state
  408 + is a special state named 'ticket expired'. You must provide a function producing this
  409 + state when you describe your web site. The page corresponding to this state must just
  410 + inform the client that he/she waited a too long time before clicking on a button, and
  411 + has to restart (a new conversation) from the begining.
  412 +
  413 +
  414 +
  415 + * (2) Carrying on.
  416 +
  417 + ** (2.1) Describing your web sites.
  418 +
  419 + Before you may start your web site, you must describe it, i.e. produce a datum of the
  420 + opaque type 'Web_Site'.
  421 +
  422 +public type Web_Site:...
  423 +
  424 + Producing such a datum may be performed by:
  425 +
  426 +public define Web_Site
  427 + make_web_site_description
  428 + (
  429 + List(String) common_names, // for example: ["www.our-business.com",
  430 + // "192.168.0.1"]
  431 + // the second one is just for testing
  432 + String site_directory, // where 'public' and other directories are
  433 + // located (should NOT end with '/')
  434 + String state_directory,
  435 + One -> One init,
  436 + (HTTP_Info,
  437 + List(Web_arg),
  438 + Bool is_https) -> $State initial_state,
  439 + ($State expired,
  440 + Maybe(String),
  441 + HTTP_Info,
  442 + List(Web_arg),
  443 + Bool is_https) -> $State ticket_expired_state,
  444 + (Maybe(String),
  445 + HTTP_Info,
  446 + List(Web_arg),
  447 + Bool is_https) -> $State ticket_lost_state,
  448 + List(Web_Action($State)) actions,
  449 + $State -> HTTP_Answer compute_page,
  450 + $State -> List(HTTP_header) additional_headers,
  451 + Int timeout, // seconds (todo: minutes)
  452 + Redirections redirections,
  453 + String charset,
  454 + List(String) journal_extensions,
  455 + List(String) journal_headers,
  456 + String authorization_secret,
  457 + List(MIME) known_mime_types,
  458 + (String action_name,
  459 + List(Web_arg) args)-> One before_send_file
  460 + ).
  461 +
  462 +
  463 + Explanations:
  464 +
  465 + 'common_names' is the list of names of the site (the name the browser must send as the
  466 + value of the 'Host' HTTP header in order to access the site must be in that list). Such
  467 + a name generally looks like this:
  468 +
  469 + www.somewhere.com
  470 +
  471 + If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of
  472 + the site must be exactly the same as the name on the certificate (which is precisely
  473 + called the 'common name' in the X.509 jargon). If the two names do not match, the site
  474 + will still work, but the transaction will not be transparent to the client. His browser
  475 + will complain that the name of the certificate does not match the name of the site, and
  476 + he will have to accept the certificate manually.
  477 +
  478 + 'site_directory' is the absolute path to the directory where the files needed by the
  479 + site are located. Usually this directory looks like:
  480 +
  481 + my_anubis/web_sites/www.somewhere.com
  482 +
  483 + However, this information is not computed from 'common_name', so that you can change
  484 + the common name (for example temporarily, for networking reasons) without loosing
  485 + access to the files.
  486 +
  487 + 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state
  488 + whose graphical representation is a page explaining to the user that its 'ticket' (or
  489 + 'session information') has expired, and that he/she must close all popup windows and
  490 + start a new session. The arguments of the function contain the previous (expired)
  491 + state and all current informations concerning the user. This arguments may be useful
  492 + for example for producing the expiration message in the language chosen by the user.
  493 + You can also (and this may be much smarter) send a 'ticket prolongation page'
  494 + (including a new login for example), and resume the same conversation, since you have
  495 + all the pertinent informations at hand. In the case the ticket is definitely lost, the
  496 + second fonction 'ticket_lost_state' is used.
  497 +
  498 + Notice that despite the fact that the parameter $State is involved in the arguments of
  499 + the above function, the type 'Web_Site' does not depend on this parameter. This allows
  500 + to produce lists of web site descriptions, where each description may be constructed
  501 + with a different instance of $State. This is required because distinct sites must have
  502 + distinct types of session informations. This is made possible by the fact that the
  503 + type is obscure, and the constructor replaced by a function which assembles
  504 + 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single
  505 + entity not depending on $State. You should have a look to the private part of this file
  506 + if you want more precisions about this programming technique.
  507 +
  508 + 'charset' is a string which will determine the character encoding to be used by the
  509 + browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",
  510 + etc...
  511 +
  512 + 'before_send_file' is a function which is executed just before the HTTP server sends a
  513 + file. It gets an action name and the web arguments received with the request for that
  514 + file. Notice that this action name and these web arguments may be put into a
  515 + 'private_download' element, and will come back to the server at the time of the
  516 + download.
  517 +
  518 +
  519 +
  520 + ** (2.2) Directories on the server's disk.
  521 +
  522 + The description of your site contains the name of the directory within which the
  523 + required files are located. This may be for example:
  524 +
  525 + my_anubis/web_sites/www.our-business.com/
  526 +
  527 + This is called the 'site directory' (for the given site). Within the site directory,
  528 + the following directories are created by this program:
  529 +
  530 + states
  531 + public
  532 + journal
  533 + private_download
  534 + upload_temporary
  535 +
  536 + The directory 'states' is used for storing states (session informations). Out of date
  537 + states are automatically removed after some time.
  538 +
  539 + The tree rooted at 'public' contains files that the server is allowed to send to the
  540 + clients. For security reasons, the server never sends a file which is not within the
  541 + tree whose root is this 'public' directory (except for the 'private download' mecanism;
  542 + see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis')
  543 + must have been recognized before the file may be sent.
  544 +
  545 + The directory 'journal' contains the jounal files. The roles of the remaining
  546 + directories 'private_download' and 'upload_temporary' is explained in
  547 + 'multihost_http_server.anubis', where you will also find further informations on
  548 + 'public' and 'journal'.
  549 +
  550 +
  551 +
  552 +
  553 + ** (2.3) Web servers parameters.
  554 +
  555 + The web servers have several parameters useful for administration. They are described
  556 + as follows:
  557 +
  558 + public type WebServersParameters:
  559 + wsparms(Var(Bool) shutdown_required,
  560 +
  561 +
  562 +
  563 +
  564 + ** (2.4) Starting your web sites.
  565 +
  566 + When you have described all your web sites (you may want to have several web sites, and
  567 + they are distinguished by their 'common name'), you may start them all together using
  568 + 'start_web_sites' below. This function returns a result of the following type:
  569 +
  570 +public type Start_Web_Sites_Result:
  571 + cannot_bind_to_port(Word32),
  572 + cannot_bind_to_port(Word32,Word32),
  573 + ok(Server http_server,
  574 + Server https_server).
  575 +
  576 + Indeed, it may happen that the system cannot bind (begin to listen) to one of the two
  577 + ports (or to both). The main reason is that another server is already listening on that
  578 + port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that
  579 + the 's' bit has not been set for 'user' and 'group' (there is not such problem under
  580 + Windows). Also notice that the Linux kernel may need a rather long time (up to several
  581 + minutes) before liberating a listening port. Now, if the system can bind to the two
  582 + ports, the pair of the two servers is returned. Two tools are useful for manipulating
  583 + servers:
  584 +
  585 + shutdown of type Server -> One
  586 + is_down of type Server -> Bool
  587 +
  588 + They are defined in 'predefined.anubis' (together with the type 'Server').
  589 +
  590 +
  591 +public define Start_Web_Sites_Result
  592 + start_web_sites
  593 + (
  594 + Word32 ip_address, // the IP address shared by the web sites
  595 + Word32 http_port, // usually: 80
  596 + Word32 https_port, // usually: 443
  597 + String ssl_certificate_common_name,
  598 + List(Web_Site) web_sites, // web sites to be started
  599 + (One) -> Bool shutdown_required
  600 + ).
  601 +
  602 + 'ip_address' is the IP address on which the two servers listen. If you put 0, the
  603 + servers listen on all the IP addresses of the machine. This may be useful if the
  604 + machine has several network interfaces.
  605 +
  606 + 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec'
  607 + loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server
  608 + certificate. This is due to a problem of conception of SSL itself. See the book 'SSL
  609 + and TLS' by Eric Rescorla (at Addison Wesley) for more explanations.
  610 +
  611 + Notice that the number of servers is always 2, regardless of the number of web sites
  612 + you are starting.
  613 +
  614 + The dynamic variable 'shutdown_required' may be used to control the shutdown of the two
  615 + servers from within the web site (typically the administration part). The servers will
  616 + shutdown as soon as this variable contains 'true'. So you must provide a variable
  617 + containing 'false' otherwise your servers will not run. You may also use the primitive
  618 + 'must_restart' (see 'predefined.anubis') to control the restarting of your servers.
  619 +
  620 +
  621 +
  622 +
  623 +
  624 +
  625 + * (3) The HTML interface.
  626 +
  627 + We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination
  628 + of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more
  629 + reactive and attractive on the client side.
  630 +
  631 +
  632 + ** (3.1) Types used by the HTML interface.
  633 +
  634 + For easy reference, we gather below the definitions of all the types used by the HTML
  635 + interface, and we comment them immediately.
  636 +
  637 +
  638 +public type HTML_Size:
  639 + absolute(Int), // in pixels
  640 + percentage(Int).
  641 +
  642 +
  643 +public type Text_Option:
  644 + size(Int), // size of character font to use
  645 + font(String), // name of character font to use (such as "helvetica",...)
  646 + color(RGB), // color to be used for characters
  647 + italic,
  648 + oblique,
  649 + small_capitals,
  650 + bold,
  651 + underlined,
  652 + left_justified,
  653 + right_justified,
  654 + justified, // justified on both sides
  655 + line_through,
  656 + nowrap,
  657 + class(String), //CSS class
  658 + id(String),
  659 + style(String),
  660 + title(String),
  661 + attr(String, String).
  662 +
  663 +public define Text_Option
  664 + tooltip(String s) = title(s).
  665 +
  666 + A list of 'Text_Option' must be given with each text you want to put in your page.
  667 +
  668 + This indicate the way of reading text.
  669 +public type Reading_Way:
  670 + ltr, //the text is readable from "Left To Right" like english
  671 + rtl. //the text is readable from "Right To Left" like arabic
  672 +
  673 +
  674 +// Following types are define to prohib any arguments order error
  675 +
  676 +/**
  677 + * String value for 'id' attribut
  678 + */
  679 +public type HtmlId:
  680 + htmlId(String id).
  681 +
  682 +/**
  683 + * String value for 'class' attribut
  684 + */
  685 +public type HtmlClass:
  686 + htmlClass(String class).
  687 +
  688 +/**
  689 + * Name used in arguments list when form is submitted.
  690 + */
  691 +public type WebArgName:
  692 + wan(String name).
  693 +
  694 +/**
  695 + * Value passed to arguments list when form is submitted (for RadioButton and CheckBox).
  696 + */
  697 +public type WebArgValue:
  698 + wav(String value).
  699 +
  700 +/**
  701 + * Initial value of an input field.
  702 + */
  703 +public type InitialValue:
  704 + init(String value).
  705 +
  706 +public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y).
  707 +public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y).
  708 +public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y).
  709 +public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y).
  710 +public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y).
  711 +
  712 +
  713 +public type HtmlEvents:
  714 + // Form element events
  715 + onchange,
  716 + onsubmit,
  717 + onreset,
  718 + onselect,
  719 + onblur,
  720 + onfocus,
  721 + // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
  722 + onkeydown,
  723 + onkeypress,
  724 + onkeyup,
  725 + // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
  726 + onclick,
  727 + ondblclick,
  728 + onmousedown,
  729 + onmousemove,
  730 + onmouseout,
  731 + onmouseover,
  732 + onmouseup.
  733 +
  734 +public type CoreAttrs:
  735 + id (String),
  736 + class (String),
  737 + style (String),
  738 + title (String),
  739 + lang (String),
  740 + dir (Reading_Way),
  741 + accesskey (Word8),
  742 + tabindex (Int),
  743 + attr (String, String),
  744 + event (HtmlEvents, String).
  745 +
  746 +public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
  747 +
  748 +public type InputAttrs:
  749 + class (String),
  750 + style (String),
  751 + title (String),
  752 + lang (String),
  753 + dir (Reading_Way),
  754 + accesskey (Word8),
  755 + tabindex (Int),
  756 + attr (String, String),
  757 + event (HtmlEvents, String).
  758 +
  759 +public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
  760 +
  761 +public define CoreAttrs
  762 + tooltip(String s) = title(s).
  763 +public define InputAttrs
  764 + tooltip(String s) = title(s).
  765 +
  766 +public type I18n:
  767 + lang (String),
  768 + dir (Reading_Way).
  769 +
  770 +//public type DIV_Option:
  771 +// id (String),
  772 +// class (String),
  773 +// style (String),
  774 +// tooltip (String),
  775 +// lang (String),
  776 +// dir (Reading_Way),
  777 +// attr (String, String),
  778 +// event (HtmlEvents, String).
  779 +//
  780 +
  781 + A list of 'DIV_Option' must be given with each DIV you want to put in your page.
  782 +
  783 +define String event_name
  784 + (
  785 + HtmlEvents e
  786 + ) =
  787 + if e is
  788 + {
  789 + // Form element events
  790 + onchange then "onchange",
  791 + onsubmit then "onsubmit",
  792 + onreset then "onreset",
  793 + onselect then "onselect",
  794 + onblur then "onblur",
  795 + onfocus then "onfocus",
  796 + // Keyboard events
  797 + onkeydown then "onkeydown",
  798 + onkeypress then "onkeypress",
  799 + onkeyup then "onkeyup",
  800 + // Mouse events
  801 + onclick then "onclick",
  802 + ondblclick then "ondblclick",
  803 + onmousedown then "onmousedown",
  804 + onmousemove then "onmousemove",
  805 + onmouseout then "onmouseout",
  806 + onmouseover then "onmouseover",
  807 + onmouseup then "onmouseup"
  808 + }.
  809 +
  810 +public type Table_Option:
  811 + background_color(RGB), // applied to all cells in the table
  812 + background_image(String url),
  813 + border(Int width_of_outer_edge, // if not present, all values are 0
  814 + Int width_of_top_of_relief,
  815 + Int width_of_inner_edge,
  816 + RGB border_color),
  817 + width(Int), // sets a minimal width for the table
  818 + percentage_width(Int),
  819 + attr(String name, String value),
  820 + class(String class_name).
  821 +
  822 +
  823 +public define Table_Option nude = border(0,0,0,rgb(0,0,0)).
  824 +
  825 +
  826 + A list of 'Table_Option' must be given with each table.
  827 +
  828 +
  829 +public type BackgroundOption:
  830 + repeat, // repeat the background in both directions
  831 + repeat_horizontal, // repeat the background only horizontally
  832 + repeat_vertical, // repeat the background only verticall
  833 + no_repeat, // don't repeat the background
  834 + center.
  835 +
  836 +
  837 +public type Cell_Option:
  838 + core_attrs(List(CoreAttrs)),
  839 + left, // put the content of the cell on the left
  840 + h_center, // center the content of the cell horizontally
  841 + right, // put the content of the cell on the right
  842 + top, // put the content of the cell upwards
  843 + v_center, // center the content of tye cell vertically,
  844 + bottom, // put the content of the cell downwards
  845 + base_line, // align the content vertically according to base lines
  846 + background_color(RGB),
  847 + background_image(String url, BackgroundOption),
  848 + width(Int), // sets a minimal width for the cell
  849 + percentage_width(Int),
  850 + height(Int), // sets a minimal height for the cell
  851 + columns(Int), // lets the cell span over several columns
  852 + rows(Int), // lets the cell span over several rows
  853 + nowrap, // do not allow text wrapping within the cell
  854 + class(String class_name).
  855 +
  856 + A list of 'Cell_Option' must be given with each cell and each row in a table. Options
  857 + given with a row apply to all the cells in the row, but are superseded by options given
  858 + with cells, which apply only to the cell they are given with.
  859 +
  860 +
  861 +public type HTML_Cell($T):
  862 + cell(List(Cell_Option) options, $T content).
  863 +
  864 +public type HTML_Header_Cell($T):
  865 + header_cell(List(Cell_Option) options, $T content).
  866 +
  867 + The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form',
  868 + depending on where you put your table (within a form or not within a form). For your
  869 + convenience, we define the following particular case:
  870 +
  871 +public define HTML_Cell($T)
  872 + cell
  873 + (
  874 + $T content
  875 + ) =
  876 + cell([],content).
  877 +
  878 +public define HTML_Header_Cell($T)
  879 + header_cell
  880 + (
  881 + $T content
  882 + ) =
  883 + header_cell([],content).
  884 +
  885 +
  886 +public type HTML_Row($T):
  887 + row(List(Cell_Option) options, List(HTML_Cell($T)) cells).
  888 +
  889 +public type HTML_Header_Row($T):
  890 + empty,
  891 + header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells).
  892 +
  893 +public type HTML_Footer_Row($T):
  894 + empty,
  895 + footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells).
  896 +
  897 + Same remark as for 'HTML_Cell($T)'. We define several convenience functions:
  898 +
  899 +public define HTML_Row($T)
  900 + row
  901 + (
  902 + List(HTML_Cell($T)) cells
  903 + ) =
  904 + row([],cells).
  905 +
  906 +public define HTML_Row($T)
  907 + row
  908 + (
  909 + HTML_Cell($T) cell
  910 + ) =
  911 + row([],[cell]).
  912 +
  913 +public define HTML_Header_Row($T)
  914 + header_row
  915 + (
  916 + List(HTML_Header_Cell($T)) cells
  917 + ) =
  918 + header_row([],cells).
  919 +
  920 +public define HTML_Header_Row($T)
  921 + header_row
  922 + (
  923 + HTML_Header_Cell($T) cell
  924 + ) =
  925 + header_row([],[cell]).
  926 +
  927 +public type Actioner_Connection:
  928 + same, // use same type of connection as current page
  929 + http, // use non secured connection
  930 + https. // use secured connection
  931 +
  932 +public type Other_Window_Option:
  933 + resizable, // the new window may be resized by the client
  934 + scrollbars, // the new window has scrollbars
  935 + width(Int), // the new window has the specified width
  936 + height(Int). // the new window has the specified height
  937 +
  938 +public type Actioner_Target:
  939 + same,
  940 + same (String label),
  941 + other(String window_name, List(Other_Window_Option)).
  942 +
  943 +public type Actioner_Aspect:
  944 + link (List(Text_Option), String text, Maybe(String) name),// hypertext link
  945 + img_link (String img_url, String alt_text),
  946 + push_button (List(CoreAttrs),String text),
  947 + button (String url_off, String url_on), // rollover button
  948 + button (String url_off, String url_on, Int w, Int h), // idem with size
  949 + submit (List(CoreAttrs),String text),
  950 + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((List(CoreAttrs),WebArgValue,String)) choices),
  951 + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((List(CoreAttrs),WebArgValue,String)) choices, InitialValue selected).
  952 +
  953 +
  954 +
  955 +public type Actioner_Local_Action:
  956 + close_window.
  957 +
  958 +
  959 +public define Actioner_Aspect
  960 + link
  961 + (
  962 + List(Text_Option) options,
  963 + String text
  964 + ) =
  965 + link(options, text, failure).
  966 +
  967 +public define Actioner_Aspect
  968 + link
  969 + (
  970 + String text
  971 + ) =
  972 + link([], text, failure).
  973 +
  974 +
  975 +public define Actioner_Aspect
  976 + link
  977 + (
  978 + List(Text_Option) options,
  979 + Int i
  980 + ) =
  981 + link(options,to_decimal(i), failure).
  982 +
  983 +public define Actioner_Aspect
  984 + link
  985 + (
  986 + Int i
  987 + ) =
  988 + link([], i).
  989 +
  990 +public define Actioner_Aspect
  991 + button
  992 + (
  993 + String url_img
  994 + ) =
  995 + button(url_img,url_img).
  996 +
  997 + Actioners are explained in details below.
  998 +
  999 +
  1000 +public type TextAreaOption:
  1001 + input_attrs(List(InputAttrs)),
  1002 + disabled,
  1003 + read_only,
  1004 + wrap_lines.
  1005 +
  1006 +public type CSS_Style:
  1007 + text_options(List(Text_Option)).
  1008 +
  1009 +public type CSS_File:
  1010 + css_file(String file_name).
  1011 +
  1012 +public type JS_Attribute:
  1013 + attr (String, String).
  1014 +
  1015 +public type JS_File:
  1016 + js_file(String file_name,
  1017 + List(JS_Attribute) attributes).
  1018 +
  1019 +public type Script:
  1020 + script( String script_type,
  1021 + String content).
  1022 +
  1023 +public define JS_File
  1024 + js_file
  1025 + (
  1026 + String file_name
  1027 + ) =
  1028 + js_file(file_name, []).
  1029 +
  1030 +public type HTML_Meta:...
  1031 +
  1032 +public type HTML_Off_Form:...
  1033 +
  1034 +public type HTML_Head_Tag:
  1035 + meta(HTML_Meta),
  1036 + title(String),
  1037 + js(JS_File),
  1038 + js_inline(Script),
  1039 + css(CSS_File),
  1040 + css_inline(String css_styles) /* Note: <style> and </style> tags are not necessaries */
  1041 + .
  1042 +
  1043 + /* It contains
  1044 + * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ...
  1045 + * - a HTML_Off_Form representing the HTML code for the part of the page we want to display
  1046 + */
  1047 +public type HTML_Partial_Content:
  1048 + partial_content
  1049 + (
  1050 + List(HTML_Head_Tag),
  1051 + HTML_Off_Form
  1052 + )
  1053 + .
  1054 +
  1055 +
  1056 +public define List(HTML_Head_Tag)
  1057 + to_HTML_Head_Tag
  1058 + (
  1059 + List(CSS_File) css_file_list
  1060 + )=
  1061 + map((CSS_File css_f) |-> css(css_f), css_file_list).
  1062 +
  1063 +public define List(HTML_Head_Tag)
  1064 + to_HTML_Head_Tag
  1065 + (
  1066 + List(JS_File) js_file_list
  1067 + )=
  1068 + map((JS_File js_f) |-> js(js_f), js_file_list).
  1069 +
  1070 +public type HTML_In_Form:
  1071 + literal_pt (Printable_tree),
  1072 + literal (String),
  1073 + sequence (List(HTML_In_Form) items),
  1074 + text (List(Text_Option), String the_text),
  1075 + preformated (List(Text_Option), String),
  1076 + paragraph (List(Text_Option), HTML_In_Form content),
  1077 + image (List(CoreAttrs), String url, String alternate),
  1078 + image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  1079 + table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)),
  1080 + center (HTML_In_Form),
  1081 + mail_to (String email, HTML_In_Form element),
  1082 + scroller (Int width, Int height,
  1083 + Int content_width, Int content_height,
  1084 + HTML_In_Form content),
  1085 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1086 + String action_name, List((String,String)) extra_ops,
  1087 + List(Actioner_Local_Action)),
  1088 + foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  1089 + foreign_link (List(Text_Option), String url),
  1090 + foreign_link (List(Text_Option), String url, String name),
  1091 + private_download (String abs_path, String name, String extra_ext,
  1092 + Maybe((String,List((String,String)))) action),
  1093 + text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1094 + text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1095 + password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1096 + text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height),
  1097 + file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width),
  1098 + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices),
  1099 + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected),
  1100 + // List((String,String)) = List((code,name)) where :
  1101 + // code is the web-arg value
  1102 + // name appears in selector
  1103 + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((List(CoreAttrs),WebArgValue,String)) choices),
  1104 + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((List(CoreAttrs),WebArgValue,String)) choices, InitialValue selected),
  1105 + radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1106 + radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1107 + check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1108 + check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1109 + div (List(CoreAttrs), HTML_In_Form content),
  1110 + div_empty (List(CoreAttrs)),
  1111 + hidden (HtmlId id, WebArgName name, InitialValue init).
  1112 +
  1113 +
  1114 + 'HTML_In_Form' defines all the elements you may put within a form. We define a
  1115 + convenience function:
  1116 +
  1117 +public define HTML_In_Form literal(Printable_tree t) = literal_pt(t).
  1118 +
  1119 +public define HTML_In_Form image(String url) = image([], url, url).
  1120 +
  1121 +public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height).
  1122 +
  1123 +public define HTML_In_Form
  1124 + foreign_link
  1125 + (
  1126 + Int tsize,
  1127 + String url,
  1128 + String name
  1129 + ) =
  1130 + foreign_link([size(tsize)],url,name).
  1131 +
  1132 +public define HTML_In_Form
  1133 + actioner
  1134 + (
  1135 + Actioner_Connection conn,
  1136 + Actioner_Target targ,
  1137 + Actioner_Aspect asp,
  1138 + String action_name,
  1139 + List((String,String)) extra_ops
  1140 + ) =
  1141 + actioner(conn,targ,asp,action_name,extra_ops,[]).
  1142 +
  1143 +public define HTML_In_Form
  1144 + actioner
  1145 + (
  1146 + Actioner_Connection conn,
  1147 + Actioner_Target targ,
  1148 + Actioner_Aspect asp,
  1149 + ) =
  1150 + actioner(conn, targ, asp, "", [], []).
  1151 +
  1152 +
  1153 +public define HTML_In_Form
  1154 + text_area
  1155 + (
  1156 + WebArgName name,
  1157 + InitialValue init,
  1158 + Int width,
  1159 + Int height
  1160 + ) =
  1161 + text_area([], "", htmlId(""), name,init,width,height).
  1162 +
  1163 +public define HTML_In_Form
  1164 + text_area
  1165 + (
  1166 + List(TextAreaOption) options,
  1167 + WebArgName name,
  1168 + InitialValue init,
  1169 + Int width,
  1170 + Int height
  1171 + ) =
  1172 + text_area(options, "", htmlId(""), name,init,width,height).
  1173 +
  1174 +public define HTML_In_Form
  1175 + table
  1176 + (
  1177 + List(HTML_Row(HTML_In_Form)) rows
  1178 + ) =
  1179 + table([],empty,rows,empty).
  1180 +
  1181 +public define HTML_In_Form
  1182 + table
  1183 + (
  1184 + List(Table_Option) options,
  1185 + List(HTML_Row(HTML_In_Form)) rows
  1186 + ) =
  1187 + table(options,empty,rows,empty).
  1188 +
  1189 +public define HTML_In_Form
  1190 + table
  1191 + (
  1192 + HTML_Header_Row(HTML_In_Form) h_row,
  1193 + List(HTML_Row(HTML_In_Form)) rows
  1194 + ) =
  1195 + table([],h_row,rows,empty).
  1196 +
  1197 +public define HTML_In_Form
  1198 + table
  1199 + (
  1200 + List(Table_Option) options,
  1201 + HTML_Header_Row(HTML_In_Form) h_row,
  1202 + List(HTML_Row(HTML_In_Form)) rows
  1203 + ) =
  1204 + table(options,h_row,rows,empty).
  1205 +
  1206 +public define HTML_In_Form
  1207 + private_download
  1208 + (
  1209 + String abs_path,
  1210 + String name,
  1211 + String extra_ext
  1212 + ) =
  1213 + private_download(abs_path,name,extra_ext,failure).
  1214 +
  1215 +public define HTML_In_Form
  1216 + private_download
  1217 + (
  1218 + String abs_path,
  1219 + String name,
  1220 + String extra_ext,
  1221 + String action_name,
  1222 + List((String,String)) args
  1223 + ) =
  1224 + private_download(abs_path,name,extra_ext,success((action_name,args))).
  1225 +
  1226 +public define HTML_In_Form
  1227 + text
  1228 + (
  1229 + String s
  1230 + ) =
  1231 + text([],s).
  1232 +
  1233 +public define HTML_In_Form
  1234 + radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1235 + = radio_button (options, label_text, htmlId(n.name), n, value, checked).
  1236 +
  1237 +public define HTML_In_Form
  1238 + radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1239 + = radio_button_r (options, label_text, htmlId(n.name), n, value, checked).
  1240 +
  1241 +public define HTML_In_Form
  1242 + check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1243 + = check_box (options, label_text, htmlId(n.name), n, value, checked).
  1244 +
  1245 +public define HTML_In_Form
  1246 + check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1247 + = check_box_r (options, label_text, htmlId(n.name), n, value, checked).
  1248 +
  1249 +public define HTML_In_Form
  1250 + file_upload (WebArgName name, Int width)
  1251 + = file_upload([], "", htmlId(""), name, width).
  1252 +
  1253 +public define HTML_In_Form
  1254 + hidden (WebArgName name, InitialValue init)
  1255 + = if name is wan(web_name) then
  1256 + hidden(htmlId(web_name), name, init).
  1257 +
  1258 +public type HTML_Body:...
  1259 +
  1260 +public type HTML_Off_Form:
  1261 + literal_pt (Printable_tree),
  1262 + literal (String),
  1263 + sequence (List(HTML_Off_Form) items),
  1264 + text (List(Text_Option), String the_text),
  1265 + preformated (List(Text_Option), String),
  1266 + paragraph (List(Text_Option), HTML_Off_Form content),
  1267 + image (List(CoreAttrs), String url, String alternate),
  1268 + image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  1269 + table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)),
  1270 + center (HTML_Off_Form),
  1271 + mail_to (String email, HTML_Off_Form element),
  1272 + scroller (Int width, Int height,
  1273 + Int content_width, Int content_height,
  1274 + HTML_Off_Form content),
  1275 + fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content),
  1276 + fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),
  1277 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1278 + String action_name, List((String,String)) extra_ops,
  1279 + List(Actioner_Local_Action)),
  1280 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1281 + String action_name, List((String,String)) extra_ops,
  1282 + List(Actioner_Local_Action), String form_name),
  1283 + foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  1284 + foreign_link (List(Text_Option), String url),
  1285 + foreign_link (List(Text_Option), String url, String name),
  1286 + private_download (String abs_path, String name, String extra_ext,
  1287 + Maybe((String,List((String,String)))) action),
  1288 + label (String name),
  1289 + form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content),
  1290 + form (HtmlId form_id, List(CoreAttrs),
  1291 + String action_name, List((String,String)) extra_ops,
  1292 + HTML_In_Form content),
  1293 + div (List(CoreAttrs), HTML_Off_Form content),
  1294 + div_empty (List(CoreAttrs)),
  1295 + iframe (List(CoreAttrs),
  1296 + List(CSS_Style) /*styles*/,
  1297 + List(CSS_File) /*css_files*/,
  1298 + List(JS_File) /*js_files*/,
  1299 + HTML_Body /*body*/).
  1300 +
  1301 + 'HTML_Off_Form' defines all the elements you may put outside any form.
  1302 +
  1303 +
  1304 +public define HTML_Off_Form image(String url) = image([], url, url).
  1305 +
  1306 +public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height).
  1307 +
  1308 +public define HTML_Off_Form
  1309 + form
  1310 + (
  1311 + String form_name,
  1312 + List(CoreAttrs) options,
  1313 + HTML_In_Form content
  1314 + ) =
  1315 + form(htmlId(form_name), options, content).
  1316 +
  1317 +public define HTML_Off_Form
  1318 + form
  1319 + (
  1320 + String form_name,
  1321 + List(CoreAttrs) options,
  1322 + String action_name,
  1323 + List((String,String)) extra_ops,
  1324 + HTML_In_Form content
  1325 + ) =
  1326 + form(htmlId(form_name), options, action_name, extra_ops, content).
  1327 +
  1328 +
  1329 +public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t).
  1330 +public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file)
  1331 + = fixed_size_2(width,height,name_of_HTML_file).
  1332 +
  1333 +
  1334 +public define HTML_Off_Form
  1335 + foreign_link
  1336 + (
  1337 + Int tsize,
  1338 + String url,
  1339 + String name
  1340 + ) =
  1341 + foreign_link([size(tsize)],url,name).
  1342 +
  1343 +
  1344 +public define HTML_Off_Form
  1345 + actioner
  1346 + (
  1347 + Actioner_Connection conn,
  1348 + Actioner_Target targ,
  1349 + Actioner_Aspect asp,
  1350 + String action_name,
  1351 + List((String,String)) extra_ops
  1352 + ) =
  1353 + actioner(conn,targ,asp,action_name,extra_ops,[]).
  1354 +
  1355 +public define HTML_Off_Form
  1356 + table
  1357 + (
  1358 + List(HTML_Row(HTML_Off_Form)) rows
  1359 + ) =
  1360 + table([],empty,rows,empty).
  1361 +
  1362 +public define HTML_Off_Form
  1363 + table
  1364 + (
  1365 + List(Table_Option) options,
  1366 + List(HTML_Row(HTML_Off_Form)) rows
  1367 + ) =
  1368 + table(options,empty,rows,empty).
  1369 +
  1370 +public define HTML_Off_Form
  1371 + table
  1372 + (
  1373 + HTML_Header_Row(HTML_Off_Form) h_row,
  1374 + List(HTML_Row(HTML_Off_Form)) rows
  1375 + ) =
  1376 + table([],h_row,rows,empty).
  1377 +
  1378 +public define HTML_Off_Form
  1379 + table
  1380 + (
  1381 + List(Table_Option) options,
  1382 + HTML_Header_Row(HTML_Off_Form) h_row,
  1383 + List(HTML_Row(HTML_Off_Form)) rows
  1384 + ) =
  1385 + table(options,h_row,rows,empty).
  1386 +
  1387 + We add two convenience functions for 'row'. The reason why we add two functions, one
  1388 + for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an
  1389 + arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so,
  1390 + the arguments of the function do not refer to any of the types defined here.
  1391 +
  1392 +public define HTML_Row(HTML_In_Form)
  1393 + row
  1394 + (
  1395 + HTML_In_Form content
  1396 + ) =
  1397 + row([],[cell([],content)]).
  1398 +
  1399 +public define HTML_Row(HTML_Off_Form)
  1400 + row
  1401 + (
  1402 + HTML_Off_Form content
  1403 + ) =
  1404 + row([],[cell([],content)]).
  1405 +
  1406 +
  1407 +public define HTML_Off_Form
  1408 + private_download
  1409 + (
  1410 + String abs_path,
  1411 + String name,
  1412 + String extra_ext
  1413 + ) =
  1414 + private_download(abs_path,name,extra_ext,failure).
  1415 +
  1416 +
  1417 +public define HTML_Off_Form
  1418 + private_download
  1419 + (
  1420 + String abs_path,
  1421 + String name,
  1422 + String extra_ext,
  1423 + String action_name,
  1424 + List((String,String)) args
  1425 + ) =
  1426 + private_download(abs_path,name,extra_ext,success((action_name,args))).
  1427 +
  1428 +public define HTML_Off_Form
  1429 + text
  1430 + (
  1431 + List(Text_Option) lto,
  1432 + Int i
  1433 + ) =
  1434 + text(lto,to_decimal(i)).
  1435 +
  1436 +
  1437 +public define HTML_Off_Form
  1438 + text
  1439 + (
  1440 + Int i
  1441 + ) =
  1442 + text([],i).
  1443 +
  1444 +public define HTML_Off_Form
  1445 + text
  1446 + (
  1447 + String s
  1448 + ) =
  1449 + text([],s).
  1450 +
  1451 + - Cell a gap between two other cells :
  1452 +
  1453 +public define HTML_Cell(HTML_Off_Form)
  1454 + width_gap
  1455 + (
  1456 + Int w
  1457 + ) =
  1458 + cell([width(w)],text([],"")).
  1459 +
  1460 +public define HTML_Cell(HTML_In_Form)
  1461 + width_gap
  1462 + (
  1463 + Int w
  1464 + ) =
  1465 + cell([width(w)],text([],"")).
  1466 +
  1467 +
  1468 + - Row a gap between two other rows :
  1469 +
  1470 +public define HTML_Row(HTML_Off_Form)
  1471 + height_gap
  1472 + (
  1473 + Int h
  1474 + ) =
  1475 + row([],[cell([height(h)],text([],""))]).
  1476 +
  1477 +public define HTML_Row(HTML_In_Form)
  1478 + height_gap
  1479 + (
  1480 + Int h
  1481 + ) =
  1482 + row([],[cell([height(h)],text([],""))]).
  1483 +
  1484 +
  1485 + Notice that the two types have alternatives in common (same name, same arguments types,
  1486 + up to the value of the parameter $T), which correspond to elements which may be put
  1487 + anywhere in the page.
  1488 +
  1489 +
  1490 +public define HTML_Partial_Content
  1491 + partial_content
  1492 + (
  1493 + HTML_Off_Form content
  1494 + )=
  1495 + partial_content([], content).
  1496 +
  1497 +public define HTML_Partial_Content
  1498 + partial_content
  1499 + (
  1500 + List(HTML_Head_Tag) tags,
  1501 + HTML_Partial_Content p_content
  1502 + )=
  1503 + if p_content is partial_content(ptags, html) then
  1504 + partial_content(tags + ptags, html).
  1505 +
  1506 +define HTML_Partial_Content
  1507 + list_to_pcontent
  1508 + (
  1509 + List(HTML_Partial_Content) l_p_content,
  1510 + List(HTML_Head_Tag) so_far_tags,
  1511 + List(HTML_Off_Form) so_far_html
  1512 + )=
  1513 + if l_p_content is
  1514 + {
  1515 + [] then partial_content(so_far_tags, sequence(reverse(so_far_html))),
  1516 + [h . t] then
  1517 + //extract resurgent type and symbols of h
  1518 + if h is partial_content(tags, html) then
  1519 + list_to_pcontent(t, so_far_tags + tags, [html . so_far_html])
  1520 + }.
  1521 +
  1522 +public define HTML_Partial_Content
  1523 + partial_content
  1524 + (
  1525 + List(HTML_Partial_Content) l_p_content
  1526 + )=
  1527 + list_to_pcontent(l_p_content, [], []).
  1528 +
  1529 +
  1530 +
  1531 +define String
  1532 + format
  1533 + (
  1534 + List(Text_Option) l
  1535 + ).
  1536 +
  1537 +
  1538 +
  1539 +
  1540 +define Printable_tree
  1541 + format_css_styles
  1542 + (
  1543 + List(CSS_Style) l
  1544 + ) =
  1545 + if l is
  1546 + {
  1547 + [ ] then [ ],
  1548 + [h . t] then
  1549 + [ if h is
  1550 + {
  1551 + text_options(tos) then
  1552 + [" body, span, p { ", format(tos), " }\n" ]
  1553 + }
  1554 + . format_css_styles(t)]
  1555 + }.
  1556 +
  1557 +
  1558 +
  1559 +public type HTML_Meta:
  1560 + keywords (List(String)),
  1561 + refresh (Actioner_Connection connection,
  1562 + Actioner_Target target,
  1563 + String action_name,
  1564 + Int delay), // in seconds
  1565 + refresh (String url, Int delay), // in seconds
  1566 + meta (String name, String content),
  1567 + http_equiv (String name, String content),
  1568 + generic_meta (List((String,String))),
  1569 + literal (String).
  1570 +
  1571 + Meta tags are put in the 'head' of the HTML page.
  1572 +
  1573 +
  1574 +public type Body_Option:
  1575 + core_attrs(List(CoreAttrs)),
  1576 + background_color (RGB),
  1577 + background_image (String url),
  1578 + background_image (String url, List(BackgroundOption)).
  1579 +
  1580 +public type HTML_Body:
  1581 + body(List(Body_Option) options, HTML_Off_Form content).
  1582 +
  1583 +
  1584 +public type HTTP_Answer:
  1585 + html_page (HTTP_Status /*http_status*/,
  1586 + List(HTML_Head_Tag) /*html <head> tags*/,
  1587 + HTML_Body /*body*/),
  1588 + html_page (HTTP_Status /*http_status*/,
  1589 + String /*title*/,
  1590 + List(HTML_Meta) /*meta_tags*/,
  1591 + List(CSS_Style) /*styles*/,
  1592 + List(CSS_File) /*css_files*/,
  1593 + List(JS_File) /*js_files*/,
  1594 + List(Script) /*script*/,
  1595 + HTML_Body /*body*/),
  1596 + plain_text (HTTP_Status /*http_status*/,
  1597 + String /*text*/),
  1598 + custom_text (HTTP_Status /*http_status*/,
  1599 + String /*mime_type*/,
  1600 + String /*content*/),
  1601 + custom_binary(HTTP_Status /*http_status*/,
  1602 + String /*mime_type*/,
  1603 + ByteArray /*content*/,
  1604 + List(HTTP_header)/*other headers*/),
  1605 + custom_tree (HTTP_Status /*http_status*/,
  1606 + String /*mime_type*/,
  1607 + Printable_tree /*content*/),
  1608 + http_raw (Printable_tree),
  1609 + html_content (HTTP_Status /*http_status*/,
  1610 + HTML_Off_Form).
  1611 +
  1612 +
  1613 +public define HTTP_Answer
  1614 + html_page
  1615 + (
  1616 + String title,
  1617 + List(HTML_Meta) metas,
  1618 + HTML_Body body
  1619 + ) =
  1620 + html_page(http_ok, title,metas,[],[],[],[],body).
  1621 +
  1622 +public define HTTP_Answer
  1623 + html_page
  1624 + (
  1625 + String title,
  1626 + List(HTML_Meta) metas,
  1627 + List(CSS_Style) styles,
  1628 + HTML_Body body
  1629 + ) =
  1630 + html_page(http_ok, title, metas, styles, [], [], [], body).
  1631 +
  1632 + 'HTTP_Answer' represents the final product of the construction of a web page.
  1633 +
  1634 +
  1635 +
  1636 +
  1637 + *** (3.2) ``in form'' versus ``off form''.
  1638 +
  1639 + There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some
  1640 + of them may have a content, which is yet another HTML element (or several). Hence, it
  1641 + is meaningful to say that an element is 'within' another one. Now, putting any element
  1642 + within any other one may be meaningless. For example, an input element must be put
  1643 + within a form (otherwise, it is useless), and a from within another form has no precise
  1644 + meaning (and is forbidden by the HTML specification).
  1645 +
  1646 + Actually, the main criterium is ``within a form or not within a form''. So, HTML
  1647 + elements in a given page are separated into two categories: those who are within a
  1648 + form, and the others. Nevertheless, there are elements which may belong to both
  1649 + categories, like images and texts. We want to make use of the strong typing mecanism of
  1650 + Anubis in order to forbid non meaningful placement of elements.
  1651 +
  1652 + The type 'HTML_In_Form' defines elements to be put within forms. Similarly,
  1653 + 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive,
  1654 + and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course),
  1655 + but the two types are not cross recursive. This is the reason why it is impossible to
  1656 + put a form within a form. In order to construct a web page, you essentially have to
  1657 + produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form').
  1658 +
  1659 + In practice, you don't have to worry so much about these two types, because elements
  1660 + which may be put anywhere are constructed for both types by functions with the same
  1661 + name and the same arguments. Hence, for both types, you just write the same thing. You
  1662 + are warned by the compiler only when you try to put an element at a place it is not
  1663 + allowed.
  1664 +
  1665 +
  1666 +
  1667 + *** (3.3) Defining your own style.
  1668 +
  1669 + We provide generic tools for constructing HTML elements. However, your web site needs
  1670 + to have a ``style''.
  1671 +
  1672 + To that end, you need to write down a set of ``styling functions'', using the tools
  1673 + defined here. These styling functions allow the introduction of your colors and other
  1674 + visual characteristics into the constructed elements once and for all. For example, you
  1675 + may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using
  1676 + some 'text_color'. You may write something like this:
  1677 +
  1678 + define RGB text_color = rgb(10,40,40).
  1679 +
  1680 + define HTML_Off_Form
  1681 + text
  1682 + (
  1683 + String the_text
  1684 + ) =
  1685 + text([font("helvetica"),size(14),color(text_color)],
  1686 + the_text).
  1687 +
  1688 + (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a
  1689 + page, you just write:
  1690 +
  1691 + text("... some text ...")
  1692 +
  1693 + and you don't have to provide the font, size and color for each text. If you want to
  1694 + have several styles of text presentation, you just write several sets of such
  1695 + convenience functions. This also suggests a trick. You may want for example different
  1696 + colors for 'in form' texts and 'off form' texts. This may be achieved automatically by
  1697 + defining two functions as above, with the same name and same argument type, but
  1698 + returning either a 'HTML_In_Form' or a 'HTML_Off_Form'.
  1699 +
  1700 + If this preliminary work is well done, you will not waste your time later when you
  1701 + concentrate on the actual informational content of your pages.
  1702 +
  1703 + This general principle should be applied to all sorts of elements. This is the best
  1704 + thing to do in order to separate the functions defining the visual style from the
  1705 + functions defining the informational content itself, so that changing the style without
  1706 + changing the content becomes easy. This is also the best way for having a clean and
  1707 + easily readable source for your web site.
  1708 +
  1709 +
  1710 +
  1711 +
  1712 +
  1713 + *** (3.4) Actioners and forms.
  1714 +
  1715 + We have gathered several notions from HTML into that of an 'actioner'. An actioner is
  1716 + an HTML element which opens a connection to our server when clicked upon. Actioners may
  1717 + have different visual aspects. They may look like hypertext links or like buttons
  1718 + (rollovers), or even like selectors (with immediate action). In any case, their
  1719 + behavior is the same: they open a connection to our server, and send a set of 'web
  1720 + arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes
  1721 + the action to be performed, and the others should be considered as operands for this
  1722 + action. Actually, the precise behavior of the actioner has several variants.
  1723 +
  1724 + The connection with the server may be secured (HTTPS) or non secured (HTTP). See the
  1725 + type 'Actioner_Connection' above.
  1726 +
  1727 + You must also choose where the answer must be rendered. This may be in the same window
  1728 + or in another window (or frame). If it is in another window, the name of that window
  1729 + must be given. If the window does not exist, the browser will create it. Optionally,
  1730 + you may give the dimensions of the new window and other characteristics. See the type
  1731 + 'Actioner_Target' above.
  1732 +
  1733 + The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the
  1734 + case of a rollover button, you provide the URLs of two images (of the same size)
  1735 + representing the button:
  1736 +
  1737 + url_off: to be used when the mouse is not over the button,
  1738 + url_on: to be used when the mouse is over the button.
  1739 +
  1740 + You can also create rollover buttons without creating images. Just use the second
  1741 + alternative named 'button'. The server creates the images automatically.
  1742 +
  1743 + The purpose of forms is just to give operands to actioners. If the actioner is placed
  1744 + within a form, all the input elements which are within this form provide operands to
  1745 + the actioner (except sometimes when they are not set by the client). If it is not put
  1746 + within a form, the actioner gets no operand, except if the name of a form is explicitly
  1747 + given, in which case the actioner gets all the inputs from that form as
  1748 + operands. Furthermore, you may want to give extra operands to the actioner. This may be
  1749 + useful for separating families of actioners with the same action name. Extra operands
  1750 + 'name=value' must be given in the form of pairs '(name,value)'.
  1751 +
  1752 + Notice that the name of a form may be used by an actioner which is off the form, so as
  1753 + to get the operands provided by this form. Also notice that several actioners may refer
  1754 + to the same form, being either in the form, or referring to the form from the
  1755 + outside. These actioners simply get the same set of operands, even if they correspond
  1756 + to distinct actions.
  1757 +
  1758 + Input elements may be put only within a form.
  1759 +
  1760 +
  1761 +
  1762 + *** (3.5) Local popup.
  1763 +
  1764 + This element looks like a link or a rollover button. When this button is clicked upon,
  1765 + a 'popup window' appears. Actually, this popup window is just a layer in the same HTML
  1766 + page, which becomes suddenly visible. It is realized with a '<div>' HTML tag. In
  1767 + particular, clicking on the button does not open any connection. This is why it is
  1768 + called 'local'. The arguments have the following roles:
  1769 +
  1770 + Actioner_Aspect aspect of the button (same semantics as for actioners)
  1771 + content content of the popup window
  1772 + x, y, position of the popup window on the HTML page (not relative
  1773 + to the button but to the page itself)
  1774 + title title of the popup window
  1775 + color color of the title bar and close button in the popup window.
  1776 + A lightened version of this color is used for the background
  1777 + of the popup window.
  1778 + width width of the title bar
  1779 +
  1780 +
  1781 +
  1782 +
  1783 +
  1784 + --- That's all for the public part ! --------------------------------------------------
  1785 +
  1786 +
  1787 +
  1788 +
  1789 +
  1790 + ----------------------------------- Table of Contents ---------------------------------
  1791 +
  1792 + *** [1] States.
  1793 + *** [1.1] Saving and retrieving states.
  1794 + *** [1.2] Deleting out of date states.
  1795 +
  1796 + *** [2] Tools.
  1797 + *** [2.1] Directories.
  1798 + *** [2.2] Secondary documents.
  1799 +
  1800 + *** [3] Managing web arguments.
  1801 + *** [3.1] Prefixing web arguments names.
  1802 + *** [3.2] Separating web arguments.
  1803 + *** [3.3] Applying an action.
  1804 +
  1805 + *** [4] Web site descriptions and the 'awp handlers'.
  1806 + *** [4.1] The type 'Web_Site'.
  1807 + *** [4.2] Making a web site description.
  1808 + *** [4.3] Starting the servers.
  1809 +
  1810 + *** [5] HTML Formating.
  1811 + *** [5.1] The type 'HTML_Any($T)'.
  1812 + *** [5.2] Formating a color.
  1813 + *** [5.3] Creating buttons.
  1814 + *** [5.4] Formating an actioner.
  1815 + *** [5.5] Formating a private download link.
  1816 + *** [5.6] Formating rows and cells in a table.
  1817 + *** [5.7] Formating elements which may be put anywhere.
  1818 + *** [5.8] Formating 'in form' elements.
  1819 + *** [5.9] Formating 'off form' elements.
  1820 + *** [5.10] Formating meta-tags.
  1821 +
  1822 + ---------------------------------------------------------------------------------------
  1823 +
  1824 +
  1825 +
  1826 +
  1827 +public define String
  1828 + doctype_w3c_header
  1829 + =
  1830 + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "+
  1831 + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".
  1832 +
  1833 +public define String
  1834 + html_header
  1835 + =
  1836 + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n".
  1837 +
  1838 +
  1839 + *** [1] States.
  1840 +
  1841 + We have to define functions for saving a state, retrieving a state, deleting out of
  1842 + date states. We need one such function per web site. The types of the first two
  1843 + functions depend on the parameter $State. This is not the case of the third one. The
  1844 + fact that the instance of $State is variable from one web sites to the other implies
  1845 + rather subtle manipulations using full functionality.
  1846 +
  1847 +
  1848 + *** [1.1] Saving and retrieving states.
  1849 +
  1850 + Each state is saved into a file on the server's disk (in the directory represented by
  1851 + the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The
  1852 + state is saved together with a time stamp whose value is obtained by adding the current
  1853 + time to the given timeout for states. The state receives a name obtained by hashing
  1854 + (using sha1) the content of the file itself, and then encoding the hash with
  1855 + 'web_arg_encode'. The name of the file into which the state is saved is the
  1856 + concatenation of "s" and the name of the state.
  1857 +
  1858 +read CXM_web_arg_encode.anubis
  1859 +
  1860 + The tool below constructs the function which is able to save a state on the server's
  1861 + disk.
  1862 +
  1863 +define ($State s) -> String // the function constructed returns the name of the state
  1864 + make_save_state_function
  1865 + (
  1866 + Int timeout,
  1867 + String state_directory
  1868 + ) =
  1869 + ($State s) |->
  1870 + with time_stamp = now+timeout,
  1871 + to_be_saved = (time_stamp,s),
  1872 + state_name = web_arg_encode(sha1(s)),
  1873 + if save(to_be_saved,state_directory+"/s"+state_name) is ok
  1874 + then state_name
  1875 + else (print("Cannot create state file in '"+state_directory+"'.\n"); "").
  1876 +
  1877 +
  1878 + When a request arrives, we need to retrieve the previous state from the server's
  1879 + disk. We receive the name of that state. If the state is out of date, the state file is
  1880 + kept 3 days, and then deleted.
  1881 +
  1882 +type PreviousState($State):
  1883 + not_found, // cannot retrieve the previous state
  1884 + out_of_date($State), // the previous state is out of date
  1885 + still_valid($State). // the previous state is still valid
  1886 +
  1887 +define (String state_name) -> PreviousState($State)
  1888 + make_retrieve_state_function
  1889 + (
  1890 + String state_directory
  1891 + ) =
  1892 + (String state_name) |->
  1893 + with file_path = state_directory+"/s"+state_name,
  1894 + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)
  1895 + then (
  1896 + if d is (time_stamp,s) then
  1897 + if time_stamp < now
  1898 + then (
  1899 + forget(remove(file_path));
  1900 + out_of_date(s)
  1901 + )
  1902 + else still_valid(s) // state has been successfully retrieved
  1903 + )
  1904 + else not_found.
  1905 +
  1906 +
  1907 +
  1908 + *** [1.2] Deleting out of date states.
  1909 +
  1910 + We also need to delete states which are out of date and which will never be deleted by
  1911 + the above method. This may be performed by a machine doing this periodically (say once
  1912 + per states life time period).
  1913 +
  1914 +define (List(String) file_names) -> One
  1915 + make_delete_out_of_date_states_function
  1916 + (
  1917 + Maybe($State) dummy,
  1918 + String state_directory
  1919 + ) =
  1920 + (List(String) file_names) |-df->
  1921 + if file_names is
  1922 + {
  1923 + [ ] then unique,
  1924 + [h . t] then
  1925 + with file_path = state_directory+"/"+h,
  1926 + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)
  1927 + then (
  1928 + if d is (time_stamp,data) then
  1929 + if time_stamp < now
  1930 + then (forget(remove(file_path)); df(t))
  1931 + else df(t)
  1932 + )
  1933 + else (forget(remove(file_path)); df(t))
  1934 + }.
  1935 +
  1936 +
  1937 + The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'.
  1938 +
  1939 + Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the
  1940 + function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler
  1941 + does not accept a parameter in the body of a function (here the parameter is required
  1942 + by the use of 'retrieve') if this parameter does not appear in the type of the
  1943 + function. This is because this would create ambiguities that no explicit typing may
  1944 + ever resolve. If you put a double slash in front of the declaration of 'dummy' above,
  1945 + and if you compile this file, you will get a message like this one:
  1946 +
  1947 + Error in 'making_a_web_site.anubis', line 1300, column 7:
  1948 + A definition may not contain parameters which are not present
  1949 + in the declaration part (hidden parameters):
  1950 + $State
  1951 +
  1952 + The type of the function constructed by 'make_delete_out_of_date_states_function' is
  1953 + independant of the parameter $State. This is important because this allows to create
  1954 + the list of such functions for all web sites. From this list, it is possible to call
  1955 + the functions one after the other, so deleting out of date states for all web
  1956 + sites. Actually, the next function receives a list of pairs (state_directory,function),
  1957 + one for each web site.
  1958 +
  1959 +define One
  1960 + delete_out_of_date_states // for all web sites
  1961 + (
  1962 + List((String, List(String) -> One)) directories_and_functions
  1963 + ) =
  1964 + if directories_and_functions is
  1965 + {
  1966 + [ ] then unique,
  1967 + [h . t] then if h is (state_directory,function) then
  1968 + function(directory_list(state_directory,"s*"));
  1969 + delete_out_of_date_states(t)
  1970 + }.
  1971 +
  1972 +
  1973 + The above function must be called periodically in a separate virtual machine. The
  1974 + period we have choosen is (rather logically) the life time of states itself. This may
  1975 + be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not
  1976 + be really infinite, because the servers may be shutdown. Hence, our loop must test
  1977 + (rather frequently; say every second) if the servers are down. If they are, the loop
  1978 + must be exited.
  1979 +
  1980 +define One
  1981 + delete_states_loop
  1982 + (
  1983 + List((String,List(String) -> One)) directories_and_functions,
  1984 + Int timeout,
  1985 + Int next_time,
  1986 + Server http_server,
  1987 + Server https_server,
  1988 + (One) -> Bool shutdown_required
  1989 + ) =
  1990 + if shutdown_required(unique)
  1991 + then (shutdown(http_server); shutdown(https_server))
  1992 + else unique;
  1993 + if (is_down(http_server) & is_down(https_server))
  1994 + then unique
  1995 + else if now > next_time
  1996 + then
  1997 + (
  1998 + delete_out_of_date_states(directories_and_functions);
  1999 + delete_states_loop(directories_and_functions,
  2000 + timeout,
  2001 + now+timeout,
  2002 + http_server,
  2003 + https_server,
  2004 + shutdown_required)
  2005 + )
  2006 + else
  2007 + (
  2008 + sleep(1000); // sleep just one second and try again
  2009 + delete_states_loop(directories_and_functions,
  2010 + timeout,
  2011 + next_time,
  2012 + http_server,
  2013 + https_server,
  2014 + shutdown_required)
  2015 + ).
  2016 +
  2017 + The above loop must be run in a separate virtual machine. This will be done just after
  2018 + the two servers are started.
  2019 +
  2020 +
  2021 +
  2022 +
  2023 +
  2024 + *** [2] Tools.
  2025 +
  2026 + *** [2.1] Directories.
  2027 +
  2028 + We need a tool for creating directories (if needed).
  2029 +
  2030 + (This tool has been moved to 'tools/basis.anubis').
  2031 +
  2032 +
  2033 +
  2034 +
  2035 + *** [2.2] Secondary documents.
  2036 +
  2037 + Some HTML elements (like '<object>', '<frame>') cannot receive their content directly
  2038 + from the current document, but only through an URL. For this reason, we implement a
  2039 + mecanism for creating secondary documents on the fly. To that end we use the 'private
  2040 + download' mecanism.
  2041 +
  2042 + A secondary document is formated by the same functions as the main document itself. The
  2043 + next function takes an 'off form' element, creates the file containing the secondary
  2044 + document in HTML format, and returns the URL at which the document will be available.
  2045 +
  2046 +define String
  2047 + create_secondary_document
  2048 + (
  2049 + String sd, // site directory
  2050 + String as, // authorization_secret
  2051 + String sn, // state name
  2052 + $T -> Printable_tree format_element,
  2053 + $T content,
  2054 + HTML_Size width
  2055 + ) =
  2056 + with private_download_directory = sd+"/private_download",
  2057 + hash = web_arg_encode(sha1(content)),
  2058 + file_content = (Printable_tree)
  2059 + [doctype_w3c_header,
  2060 + "<html><body><table ",
  2061 + if width is
  2062 + {
  2063 + absolute(w) then ["width=\"",w-25],
  2064 + percentage(w) then ["width=\"95%\""]
  2065 + },"\"><tbody><tr><td align=right>",
  2066 + format_element(content),
  2067 + "</td></tr></tbody></table></body></html>"
  2068 + ],
  2069 + file_name = "sd"+hash+".html",
  2070 + file_path = private_download_directory+"/"+file_name,
  2071 + if write_to_file(file_path,file_content) is
  2072 + {
  2073 + cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "",
  2074 + write_error(n) then print("Error writing file '"+file_path+"'.\n"); "",
  2075 + ok then file_name+"?zauth="+
  2076 + make_authorization(sd,as,private_download_directory+"/"+file_name)
  2077 + }.
  2078 +
  2079 +
  2080 +
  2081 +
  2082 + *** [2.3] Generating unique ids.
  2083 +
  2084 + In order to uniquely name object for JavaScript we generate unique ids from a counter.
  2085 +
  2086 +define Int
  2087 + new_idnum
  2088 + (
  2089 + Var(Int) ic_v // 'idnum' counter variable
  2090 + ) =
  2091 + protect
  2092 + with result = *ic_v+1,
  2093 + ic_v <- result;
  2094 + result.
  2095 +
  2096 +
  2097 +
  2098 +
  2099 +
  2100 +
  2101 + *** [3] Managing web arguments.
  2102 +
  2103 + Web arguments are those pairs 'name=value' which are transmitted through the HTTP
  2104 + protocol. We need precise naming conventions for these web arguments.
  2105 +
  2106 +
  2107 +
  2108 + *** [3.1] Prefixing web arguments names.
  2109 +
  2110 + CR 2008-07-08 Prefixing Removed
  2111 +
  2112 +
  2113 +
  2114 + *** [3.2] Separating web arguments.
  2115 +
  2116 + When a new request arrives, we need to separate the web arguments, that is to say:
  2117 +
  2118 + - find the value of "s", and recover the corresponding state,
  2119 + - find the value of "a", which is the name of the action to be performed,
  2120 + - get the list of all the remaining web arguments (operands of the action).
  2121 +
  2122 + We must also determine if the previous state may be recovered. If it is not the case
  2123 + (either because the previous state name is invalid, or the previous state is out of
  2124 + date), we must check if there is an action name. Indeed, the presence of an action name
  2125 + indicates that the user has clicked on one of our buttons or links. If on the contrary
  2126 + there is no action name the user has just entered our address in his browser. In this
  2127 + last case, we must send the first page of our site (maybe a 'login' page), but if there
  2128 + is an action, we must send a page just saying that the session ticket has expired. If
  2129 + the previous state is recovered and there is no action, the new state is the same as
  2130 + the previous state.
  2131 +
  2132 + The result of the separation of the web arguments is of type:
  2133 +
  2134 +type Separated_Web_Args($State):
  2135 + swa(PreviousState($State) previous_state,
  2136 + Maybe(String) action_name,
  2137 + List(Web_arg) operands).
  2138 +
  2139 +
  2140 +
  2141 + The next function constructs the function which separates the web arguments.
  2142 +
  2143 +define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State)
  2144 + make_separate_web_args_function
  2145 + (
  2146 + String state_directory,
  2147 + String -> PreviousState($State) retrieve_state,
  2148 + String website_name
  2149 + ) =
  2150 + (List(Web_arg) lwa, HTTP_Info info) |-swaf->
  2151 + if lwa is
  2152 + {
  2153 + [ ] then
  2154 + //
  2155 + // no web arg found => no previous state and no action
  2156 + //
  2157 + if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is
  2158 + {
  2159 + failure then swa(not_found,failure,[]),
  2160 + success(cookie) then swa(retrieve_state(value(cookie)),failure,[])
  2161 + },
  2162 +
  2163 + //swa(failure,failure,[]),
  2164 +
  2165 + [wa_1 . wa_others] then
  2166 + //
  2167 + // at least one web arg =>
  2168 + // separate other web args, and insert the first one as needed
  2169 + //
  2170 + if (Separated_Web_Args($State))swaf(wa_others, info) is
  2171 + {
  2172 + swa(ps1, // possible previous state
  2173 + an1, // maybe an action name
  2174 + op1) // operands so far
  2175 + then
  2176 + if wa_1 is
  2177 + {
  2178 + web_arg(n, value) then
  2179 + with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n,
  2180 + if name = "a" then
  2181 + swa(ps1,success(value),op1)
  2182 + else if name = "t" then
  2183 + swa(ps1,an1,[web_arg("target",value) . op1])
  2184 + else
  2185 + swa(ps1,an1,[web_arg(name,value) . op1]),
  2186 +
  2187 + upload(n,v,t) then
  2188 + swa(ps1,an1,[wa_1 . op1])
  2189 + }
  2190 + }
  2191 + }.
  2192 +
  2193 +
  2194 +
  2195 +
  2196 +
  2197 +
  2198 + *** [3.3] Applying an action.
  2199 +
  2200 + When the web arguments are separated (and their names cleaned up from prefixes), we may
  2201 + apply the action to the operands and the current state. We search for the action to be
  2202 + applied in the list of actions. If no action is found, the new state is the same as
  2203 + the previous state. Also, we deny the application of an HTTP action if the request
  2204 + arrives through the HTTPS channel and conversely.
  2205 +
  2206 +
  2207 +define ($State previous,
  2208 + String action_name,
  2209 + HTTP_Info http_info,
  2210 + List(Web_arg) lwa,
  2211 + Bool is_https) -> $State
  2212 + make_apply_action_function
  2213 + (
  2214 + List(Web_Action($State)) actions_list
  2215 + ) =
  2216 + with f =
  2217 + ($State previous,
  2218 + String action_name,
  2219 + HTTP_Info http_info,
  2220 + List(Web_arg) lwa,
  2221 + Bool is_https,
  2222 + List(Web_Action($State)) actions) |-f->
  2223 + //println("Looking for action ["+action_name+"]");
  2224 + if actions is
  2225 + {
  2226 + [ ] then print("action '"+action_name+
  2227 + "' not found.\n"); previous,
  2228 + [ac1 . others] then if ac1 is
  2229 + {
  2230 + http_action(an,allow,do_it) then
  2231 + if an = action_name
  2232 + then if is_https
  2233 + then (print("HTTP action '"+an+
  2234 + "' called through HTTPS (denied).\n");
  2235 + previous)
  2236 + else if allow(previous)
  2237 + then do_it(http_info,lwa,previous)
  2238 + else previous
  2239 + else f(previous,action_name,http_info,lwa,is_https,others),
  2240 +
  2241 + https_action(an,allow,do_it) then
  2242 + if an = action_name
  2243 + then if is_https
  2244 + then if allow(previous)
  2245 + then do_it(http_info,lwa,previous)
  2246 + else previous
  2247 + else (print("HTTPS action '"+an+
  2248 + "' called through HTTP (denied).\n");
  2249 + previous)
  2250 + else f(previous,action_name,http_info,lwa,is_https,others),
  2251 +
  2252 + http_https_action(an,allow,do_it) then
  2253 + if an = action_name
  2254 + then
  2255 + //println("Action ["+action_name+"] found");
  2256 + if allow(previous)
  2257 + then do_it(http_info,lwa,previous)
  2258 + else previous
  2259 + else f(previous,action_name,http_info,lwa,is_https,others),
  2260 +
  2261 + }
  2262 + },
  2263 + ($State previous,
  2264 + String action_name,
  2265 + HTTP_Info http_info,
  2266 + List(Web_arg) lwa,
  2267 + Bool is_https) |->
  2268 + f(previous, action_name, http_info, lwa, is_https, actions_list).
  2269 +
  2270 +
  2271 +
  2272 +
  2273 +
  2274 +
  2275 +
  2276 +
  2277 + *** [4] Web site descriptions and the 'awp handlers'.
  2278 +
  2279 + *** [4.1] The type 'Web_Site'.
  2280 +
  2281 + The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We
  2282 + need another one, because, we have some extra informations to record for each site.
  2283 +
  2284 +public type Web_Site:
  2285 + web_site((Word32,Word32) -> Web_Site_Description description,
  2286 + List(String) -> One delete_out_of_date).
  2287 +
  2288 +
  2289 +
  2290 +
  2291 + *** [4.2] Making a web site description.
  2292 +
  2293 + Below is the function which creates a web site description. It first creates (if
  2294 + needed) the directories for the site, then constructs the tool functions for the site,
  2295 + and the site handler. Finally, it constructs the web site description.
  2296 +
  2297 + We gather common (constant) informations in the following type:
  2298 +
  2299 +public type CommonInfo:
  2300 + info(String common_name,
  2301 + Word32 http_port,
  2302 + Word32 https_port,
  2303 + String site_directory,
  2304 + String authorization_secret
  2305 + ).
  2306 +
  2307 + We need a forward declaration.
  2308 +
  2309 +public define Printable_tree
  2310 + format
  2311 + (
  2312 + CommonInfo cinfo,
  2313 + String state_name,
  2314 + List(HTTP_header) headers,
  2315 + HTTP_Answer page,
  2316 + Bool is_https,
  2317 + String charset
  2318 + ).
  2319 +
  2320 +
  2321 +define Printable_tree
  2322 + format
  2323 + (
  2324 + HTML_Size s
  2325 + ) =
  2326 + if s is
  2327 + {
  2328 + absolute(x) then ["\"",x,"\""],
  2329 + percentage(x) then ["\"",x,"%\""]
  2330 + }.
  2331 +
  2332 +define List(HTTP_header)
  2333 + make_state_cookie_headers
  2334 + (
  2335 + String website_name,
  2336 + String state_name
  2337 + )
  2338 + =
  2339 + [
  2340 + http_header("Set-Cookie", "state_"+website_name+"="+state_name)
  2341 + ]
  2342 + .
  2343 +
  2344 + public define Web_Site
  2345 + make_web_site_description
  2346 + (
  2347 + List(String) common_names, // for example: ["www.our-business.com",
  2348 + // "192.168.0.1"]
  2349 + // the second one is just for testing
  2350 + String site_directory, // where 'public' and other directories are
  2351 + // located (should NOT end with '/')
  2352 + One -> One init,
  2353 + (HTTP_Info,
  2354 + List(Web_arg),
  2355 + Bool is_https) -> $State initial_state,
  2356 + ($State expired,
  2357 + HTTP_Info,
  2358 + List(Web_arg),
  2359 + Bool is_https) -> $State ticket_expired_state,
  2360 + (HTTP_Info,
  2361 + List(Web_arg),
  2362 + Bool is_https) -> $State ticket_lost_state,
  2363 + List(Web_Action($State)) actions,
  2364 + $State -> HTTP_Answer compute_page,
  2365 + $State -> List(HTTP_header) additional_headers,
  2366 + Int timeout, // seconds (todo: minutes)
  2367 + Redirections redirections,
  2368 + String charset,
  2369 + List(String) journal_extensions,
  2370 + List(String) journal_headers,
  2371 + String authorization_secret,
  2372 + List(MIME) known_mime_types,
  2373 + (String action_name,
  2374 + List(Web_arg) args)-> One before_send_file
  2375 + ).
  2376 +
  2377 +
  2378 +public define Web_Site
  2379 + make_web_site_description
  2380 + (
  2381 + String website_name,
  2382 + List(String) common_names, // for example: ["www.our-business.com"]
  2383 + String site_directory,
  2384 + String state_directory,
  2385 + One -> One init,
  2386 + (HTTP_Info,
  2387 + List(Web_arg),
  2388 + Bool is_https) -> $State initial_state,
  2389 + ($State expired,
  2390 + Maybe(String),
  2391 + HTTP_Info,
  2392 + List(Web_arg),
  2393 + Bool is_https) -> $State ticket_expired_state,
  2394 + (Maybe(String),
  2395 + HTTP_Info,
  2396 + List(Web_arg),
  2397 + Bool is_https) -> $State ticket_lost_state,
  2398 + List(Web_Action($State)) actions,
  2399 + $State -> HTTP_Answer compute_page,
  2400 + $State -> List(HTTP_header) additional_headers,
  2401 + Int timeout,
  2402 + Redirections redirections,
  2403 + String charset,
  2404 + List(String) journal_extensions,
  2405 + List(String) journal_headers,
  2406 + String secret,
  2407 + List(MIME) known_mime_types,
  2408 + (String action_name,
  2409 + List(Web_arg) args) -> One before_send_file
  2410 + //Bool using_state_cookies
  2411 + ) =
  2412 + init(unique);
  2413 +
  2414 +
  2415 + //
  2416 + // make required directories (if needed)
  2417 + //
  2418 + with //web_sites_directory = (String) make_directory(my_anubis_directory+"/web_sites"),
  2419 + base_directory = (String) make_directory(site_directory),
  2420 + // state_directory = make_directory(site_directory+"/states"),
  2421 + forget((String)make_directory(site_directory+"/public"));
  2422 + //
  2423 + // construct tool functions
  2424 + // TODO 'make_separate_web_args_function' must retrieve state_cookies before parsing web_args if using_state_cookies is true
  2425 + with save_state = make_save_state_function(timeout, state_directory),
  2426 + retrieve_state = make_retrieve_state_function(state_directory),
  2427 + separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name),
  2428 + apply_action = make_apply_action_function(actions),
  2429 + //
  2430 + // construct the site handler
  2431 + //
  2432 + site_handler = (Word32 http_port, Word32 https_port) |->
  2433 + ((String host_name,
  2434 + HTTP_Info http_info,
  2435 + List(Web_arg) lwa,
  2436 + Bool is_https) |->
  2437 + //(Printable_tree)
  2438 + if separate_web_args(lwa, http_info) is
  2439 + {
  2440 + swa(mb_previous_state, mb_action_name, operands) then
  2441 + with new_state = if mb_previous_state is
  2442 + {
  2443 + not_found then
  2444 + //println("previous state not found");
  2445 + if mb_action_name is
  2446 + {
  2447 + failure then initial_state(http_info, operands, is_https),
  2448 + success(_) then
  2449 + ticket_lost_state(mb_action_name, http_info,operands,is_https)
  2450 + },
  2451 +
  2452 + out_of_date(state) then
  2453 + ticket_expired_state(state, mb_action_name, http_info,operands,is_https),
  2454 +
  2455 + still_valid(state) then
  2456 + if mb_action_name is
  2457 + {
  2458 + failure then state,
  2459 + success(action_name) then
  2460 + apply_action(state,action_name,http_info,operands,is_https)
  2461 + }
  2462 + },
  2463 + //if state_and_headers is (session_ticket, mb_new_state, headers) then
  2464 + with state_name = save_state(new_state),
  2465 + //println("Cookie new STATE NAME "+state_name);
  2466 + with cookie_headers = if mb_action_name is
  2467 + {
  2468 + failure then [],
  2469 + success(action_name) then
  2470 + if substr(action_name, 0, 5)="ajax_" then
  2471 + []
  2472 + else
  2473 + make_state_cookie_headers(website_name, state_name)
  2474 + },
  2475 +
  2476 + format(info(host_name, http_port, https_port, site_directory, secret),
  2477 + state_name,
  2478 + additional_headers(new_state) + cookie_headers,
  2479 + compute_page(new_state),
  2480 + is_https,
  2481 + charset)
  2482 + }),
  2483 + //
  2484 + // make the delete_out_of_date function
  2485 + //
  2486 + delete_out_of_date =
  2487 + make_delete_out_of_date_states_function((Maybe($State))failure,
  2488 + site_directory+"/states"),
  2489 + //
  2490 + // construct the web site description
  2491 + //
  2492 + web_site((Word32 http_port, Word32 https_port) |->
  2493 + web_site_description(common_names,
  2494 + site_directory,
  2495 + redirections,
  2496 + charset,
  2497 + journal_extensions,
  2498 + journal_headers,
  2499 + secret,
  2500 + known_mime_types,
  2501 + site_handler(http_port,https_port),
  2502 + (HTTP_Info http_info, List(Web_arg) lwa) |-> if separate_web_args(lwa, http_info ) is
  2503 + swa(mb_previous_state,mb_action_name,operands) then
  2504 + if mb_action_name is
  2505 + {
  2506 + failure then unique
  2507 + success(an) then before_send_file(an,operands)
  2508 + }
  2509 + //using_state_cookies
  2510 + ),
  2511 + delete_out_of_date).
  2512 +
  2513 +define String
  2514 + _random_string
  2515 + (
  2516 + Int size,
  2517 + String current
  2518 + )=
  2519 + if size = 0 then
  2520 + current
  2521 + else
  2522 + _random_string( size - 1, current + random(9))
  2523 + .
  2524 +
  2525 +public define String
  2526 + generate_random_string
  2527 + (
  2528 + Int size
  2529 + ) =
  2530 + to_string(extract(base64_encode(to_byte_array(_random_string(size, ""))), 0, size)).
  2531 +
  2532 +
  2533 +define String
  2534 + get_site_uid
  2535 + (
  2536 + String site_path
  2537 + )=
  2538 + with file_name = site_path+"/site_UID",
  2539 + if read_from_file(file_name) is
  2540 + {
  2541 + cannot_find_file then
  2542 + println("site UID doesn't exists. Generating it now");
  2543 + with uid = generate_random_string(9),
  2544 + if write_to_file(file_name, to_byte_array(uid)) is
  2545 + {
  2546 + cannot_open_file then println("Can't create site UID here "+file_name);"",
  2547 + write_error(_) then println("Can't write site UID here "+file_name);"",
  2548 + ok then uid
  2549 + }
  2550 + read_error(_) then
  2551 + println("cannot read site UID from "+file_name);""
  2552 + ok(ba) then to_string(ba)
  2553 + }
  2554 + .
  2555 +
  2556 +// Compatibility function for older websites
  2557 +public define Web_Site
  2558 + make_web_site_description
  2559 + (
  2560 + List(String) common_names, // for example: ["www.our-business.com"]
  2561 + String site_directory,
  2562 + String state_directory,
  2563 + One -> One init,
  2564 + (HTTP_Info,
  2565 + List(Web_arg),
  2566 + Bool is_https) -> $State initial_state,
  2567 + ($State expired,
  2568 + Maybe(String),
  2569 + HTTP_Info,
  2570 + List(Web_arg),
  2571 + Bool is_https) -> $State ticket_expired_state,
  2572 + (Maybe(String),
  2573 + HTTP_Info,
  2574 + List(Web_arg),
  2575 + Bool is_https) -> $State ticket_lost_state,
  2576 + List(Web_Action($State)) actions,
  2577 + $State -> HTTP_Answer compute_page,
  2578 + $State -> List(HTTP_header) additional_headers,
  2579 + Int timeout,
  2580 + Redirections redirections,
  2581 + String charset,
  2582 + List(String) journal_extensions,
  2583 + List(String) journal_headers,
  2584 + String secret,
  2585 + List(MIME) known_mime_types,
  2586 + (String action_name,
  2587 + List(Web_arg) args) -> One before_send_file
  2588 + //Bool using_state_cookies
  2589 + )
  2590 + =
  2591 + //generate an unique ID if doesn't exist in root of site_directory
  2592 + with site_UID = get_site_uid(site_directory),
  2593 + println("site_UID : "+site_UID);
  2594 + make_web_site_description(site_UID, common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file)
  2595 + .
  2596 +
  2597 +
  2598 +
  2599 + *** [4.3] Starting the servers.
  2600 +
  2601 +public define Start_Web_Sites_Result
  2602 + start_web_sites
  2603 + (
  2604 + Word32 ip_address, // the IP address shared by the web sites
  2605 + Word32 http_port, // usually: 80
  2606 + Word32 https_port, // usually: 443
  2607 + String ssl_certificate_common_name,
  2608 + List(Web_Site) web_sites, // web sites to be started
  2609 + (One) -> Bool shutdown_required
  2610 + ) =
  2611 + with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port),
  2612 + with http_server_r =
  2613 + start_http_server(ip_address,http_port,
  2614 + map(get_description,web_sites),
  2615 + load_denial_of_service_info),
  2616 + with https_server_r =
  2617 + start_https_server(ip_address,https_port,
  2618 + ssl_certificate_common_name,
  2619 + map(get_description,web_sites),
  2620 + load_denial_of_service_info),
  2621 + if http_server_r is ok(http_server)
  2622 + then
  2623 + (
  2624 + if https_server_r is ok(https_server)
  2625 + then
  2626 + (
  2627 + start_http_servers_tasks(map(get_description,web_sites),
  2628 + [http_server,https_server],
  2629 + 600); // period of 10 minutes
  2630 + delegate
  2631 + delete_states_loop(
  2632 + map((Web_Site ws) |->
  2633 + (site_directory(description(ws)(http_port,https_port))+
  2634 + "/states",delete_out_of_date(ws)),
  2635 + web_sites),
  2636 + 3600*24*3, // keep out of date states 3 days
  2637 + now,
  2638 + http_server,
  2639 + https_server,
  2640 + shutdown_required),
  2641 + ok(http_server,https_server)
  2642 + )
  2643 + else cannot_bind_to_port(https_port)
  2644 + )
  2645 + else
  2646 + (
  2647 + if https_server_r is ok(https_server)
  2648 + then cannot_bind_to_port(http_port)
  2649 + else cannot_bind_to_port(http_port,https_port)
  2650 + ).
  2651 +
  2652 +
  2653 +public define One
  2654 + start_web_sites
  2655 + (
  2656 + Word32 ip_address, // the IP address shared by the web sites
  2657 + Word32 http_port, // usually: 80
  2658 + Word32 https_port, // usually: 443
  2659 + String ssl_certificate_common_name,
  2660 + List(Web_Site) web_sites, // web sites to be started
  2661 + (One) -> Bool shutdown_required,
  2662 + Logger log
  2663 + ) =
  2664 + if (Start_Web_Sites_Result)start_web_sites(ip_address,
  2665 + http_port,
  2666 + https_port,
  2667 + ssl_certificate_common_name,
  2668 + web_sites,
  2669 + shutdown_required) is
  2670 + {
  2671 + cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n),
  2672 + cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m),
  2673 + ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).")
  2674 + }.
  2675 +
  2676 +
  2677 +
  2678 +
  2679 +
  2680 + *** [5] HTML Formating.
  2681 +
  2682 + We need to translate HTML elements as defined above into actual HTML text.
  2683 +
  2684 + Actioners require special informations, which must be transmitted when needed by the
  2685 + 'format' functions:
  2686 +
  2687 + - the 'common name', which is used for URLs,
  2688 + - the HTTP/HTTPS port number,
  2689 + - the 'state name', which must be transmitted when the actioner is clicked upon,
  2690 + - the 'form name' (if any) to which the actioner refers.
  2691 +
  2692 + If the actioner is off form, and if it refers to a form, the name of that form is
  2693 + already known by the actioner. On the contrary, if the actioner is 'in form', it refers
  2694 + implicitly to the form containing it. The name of that form is transmitted to the
  2695 + 'format' functions called from within the formating of that form.
  2696 +
  2697 +
  2698 +
  2699 +
  2700 + *** [5.1] The type 'HTML_Any($T)'.
  2701 +
  2702 + The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The
  2703 + parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'.
  2704 +
  2705 +type HTML_Any($T):
  2706 + any_text (List(Text_Option), String the_text),
  2707 + any_preformated (List(Text_Option), String),
  2708 + any_paragraph (List(Text_Option), $T content),
  2709 + any_image (List(CoreAttrs), String url, String alternate),
  2710 + any_image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  2711 + any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)),
  2712 + any_center ($T),
  2713 + any_mail_to (String email, $T element),
  2714 + any_scroller (Int width, Int height,
  2715 + Int content_width, Int content_height,
  2716 + $T content),
  2717 + any_fixed_size (HTML_Size width, HTML_Size height, $T content),
  2718 + any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),
  2719 + any_actioner (Actioner_Connection,
  2720 + Actioner_Target,
  2721 + Actioner_Aspect,
  2722 + String action_name,
  2723 + List((String,String)) extra_ops,
  2724 + List(Actioner_Local_Action),
  2725 + Maybe(String) form_name),
  2726 + any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  2727 + any_foreign_link (List(Text_Option), String url),
  2728 + any_foreign_link (List(Text_Option), String url, String name),
  2729 + any_private_download (String abs_path, String name, String extra_ext,
  2730 + Maybe((String,List((String,String))))),
  2731 + any_div (List(CoreAttrs), $T element),
  2732 + any_div_empty (List(CoreAttrs)),
  2733 + any_coreattrs (List(CoreAttrs)).
  2734 +
  2735 +
  2736 +
  2737 + *** [5.2] Formating a color.
  2738 +
  2739 + RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters
  2740 + hexadecimal values.
  2741 +
  2742 +define String
  2743 + html_format
  2744 + (
  2745 + RGB color
  2746 + ) =
  2747 + if color is rgb(r,g,b) then
  2748 + "#" + to_hexa(r)
  2749 + + to_hexa(g)
  2750 + + to_hexa(b).
  2751 +
  2752 +
  2753 + The following is a very arbitrary definition of the opposite color. The thing which is
  2754 + important is that it is far from the original, so that characters in 'opposite' color
  2755 + are clearly visible over the original.
  2756 +
  2757 +define RGB
  2758 + opposite
  2759 + (
  2760 + RGB color
  2761 + ) =
  2762 + if color is rgb(r,g,b) then
  2763 + rgb(255-r,
  2764 + 255-g,
  2765 + 255-b).
  2766 +
  2767 +
  2768 +
  2769 +
  2770 + *** [5.3] Creating buttons.
  2771 +
  2772 + We want to be able to create buttons in the form of a pair of images (rollovers)
  2773 + automatically. We use the JPEG interface, because for the time being Anubis cannot
  2774 + handle other kinds of images.
  2775 +
  2776 +
  2777 + Computing printed text length.
  2778 +
  2779 + define Int
  2780 + printed_text_width
  2781 + (
  2782 + Word8 -> Int char_size,
  2783 + List(Word8) l
  2784 + ) =
  2785 + if l is
  2786 + {
  2787 + [] then (Int) 0,
  2788 + [h . t] then char_size(h) + 1+ printed_text_width(char_size,t)
  2789 + }.
  2790 +
  2791 + define Int
  2792 + printed_text_width
  2793 + (
  2794 + SystemFont font,
  2795 + String s
  2796 + ) =
  2797 + printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))),
  2798 + explode(s)).
  2799 +
  2800 +
  2801 +
  2802 + Converting RGB to RGBA.
  2803 +
  2804 +define RGBA
  2805 + to_rgba
  2806 + (
  2807 + RGB color
  2808 + ) =
  2809 + if color is rgb(r,g,b) then rgba(r,g,b,255).
  2810 +
  2811 +
  2812 + Drawing a 'relief'.
  2813 +
  2814 + define One
  2815 + draw_relief
  2816 + (
  2817 + RGBAImage dest,
  2818 + RGBA color,
  2819 + Int contrast,
  2820 + Int x,
  2821 + Int y,
  2822 + Int width,
  2823 + Int height
  2824 + ) =
  2825 + with l = lighten(color,contrast),
  2826 + d = darken(color,contrast),
  2827 + draw_rectangle(dest,rect(x,y,x+width,y+1),l);
  2828 + draw_rectangle(dest,rect(x,y+1,x+1,y+height),l);
  2829 + draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d);
  2830 + draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d).
  2831 +
  2832 +
  2833 + Creating a button background.
  2834 +
  2835 + define RGBAImage
  2836 + create_button_background
  2837 + (
  2838 + RGBA color,
  2839 + Int width,
  2840 + Int height
  2841 + ) =
  2842 + with result = create_rgba_image(width,height,color),
  2843 + draw_relief(result,color,100,0,0,width,height);
  2844 + draw_relief(result,color,70,1,1,width-2,height-2);
  2845 + draw_relief(result,color,55,2,2,width-4,height-4);
  2846 + draw_relief(result,color,35,3,3,width-6,height-6);
  2847 + draw_relief(result,color,20,4,4,width-8,height-8);
  2848 + draw_relief(result,color,10,5,5,width-10,height-10);
  2849 + draw_relief(result,color,5,6,6,width-12,height-12);
  2850 + result.
  2851 +
  2852 +
  2853 + Drawing the text over the background.
  2854 +
  2855 + define One
  2856 + draw_button_text
  2857 + (
  2858 + RGBAImage image,
  2859 + String text,
  2860 + Int text_index,
  2861 + Int pixel_x,
  2862 + Int y,
  2863 + Rectangle clip,
  2864 + RGBA color,
  2865 + SystemFont font,
  2866 + ) =
  2867 + if nth(text_index,text) is
  2868 + {
  2869 + failure then unique,
  2870 + success(c) then
  2871 + with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color),
  2872 + draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font)
  2873 + }.
  2874 +
  2875 + define One
  2876 + draw_button_text
  2877 + (
  2878 + RGBAImage image,
  2879 + String text,
  2880 + Int text_width,
  2881 + RGBA light_color,
  2882 + RGBA dark_color,
  2883 + SystemFont font
  2884 + ) =
  2885 + with image_width = width(image),
  2886 + image_height = height(image),
  2887 + x_pos = (image_width-text_width)>>1,
  2888 + clip = rect(0,0,image_width,image_height),
  2889 + new_light_color = lighten(light_color,150),
  2890 + new_dark_color = darken(dark_color,40),
  2891 + draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font);
  2892 + draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font).
  2893 +
  2894 +
  2895 + The next function creates the two images for a button. The information given is the
  2896 + main color of the button, the text of the button and the minimal width (in pixels) of
  2897 + the button. The function does not create the button if the images already exist. The
  2898 + two images are stored in the directory 'site_directory/buttons'. The names of the files
  2899 + are of the form:
  2900 +
  2901 + bxxxx_off.jpg
  2902 + bxxxx_on.jpg
  2903 +
  2904 + where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like
  2905 + 'rm'), and where 'xxxx' is created from the given informations by the formula:
  2906 +
  2907 + xxxx = web_arg_encode(sha1((color,text,width)))
  2908 +
  2909 + Hence, distinct informations give distinct file names.
  2910 +
  2911 +
  2912 + define String // returns xxxx
  2913 + create_button_images
  2914 + (
  2915 + String site_directory,
  2916 + RGBA color,
  2917 + String text,
  2918 + Int width,
  2919 + SystemFont font
  2920 + ) =
  2921 + with xxxx = web_arg_encode(sha1((color,text,width))),
  2922 + buttons_dir = site_directory+"/public/buttons",
  2923 + off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg",
  2924 + on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg",
  2925 + if file_exists(on_filepath)
  2926 + then xxxx
  2927 + else with
  2928 + text_width = printed_text_width(font,text),
  2929 + button_width = max(width,text_width+12),
  2930 + button_height = (Int)20,
  2931 + light_color = lighten(color,60),
  2932 + very_light_color = lighten(light_color,30),
  2933 + dark_color = darken(color,40),
  2934 + background_off =
  2935 + create_button_background(color,button_width,button_height),
  2936 + background_on =
  2937 + create_button_background(light_color,button_width,button_height),
  2938 +
  2939 + draw_button_text(background_off,text,text_width,very_light_color,dark_color,font);
  2940 + draw_button_text(background_on, text,text_width,very_light_color,dark_color,font);
  2941 + forget(write_image_to_JPEG_file(to_JPEG(background_off),
  2942 + off_filepath,
  2943 + 100));
  2944 + forget(write_image_to_JPEG_file(to_JPEG(background_on),
  2945 + on_filepath,
  2946 + 100));
  2947 + xxxx.
  2948 +
  2949 +
  2950 +
  2951 +
  2952 +
  2953 + *** [5.4] Formating an actioner.
  2954 +
  2955 + An actioner works as follows. Assume first that it refers to a form. When it is clicked
  2956 + upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the
  2957 + form, and submits the form, using the JavaScript command 'form_name.submit()'. If the
  2958 + actioner does not refer to a form, it fires the URL directly via 'href', because in
  2959 + that case, the actioner is always an <a> tag.
  2960 +
  2961 + The URL itself is composed using the connection sort (same, http or https), the common
  2962 + name and port number (if needed), the state name, the action name, and the extra
  2963 + operands, which are put into a query string. It may look like this:
  2964 +
  2965 + http://common_name:port/?s=state_name&a=action_name&oname=value...
  2966 +
  2967 + Each extra operand is a pair of strings: (name,value). It is formated as:
  2968 +
  2969 + &oname=value
  2970 +
  2971 +public define String
  2972 + format_attrs
  2973 + (
  2974 + List(CoreAttrs) attributs
  2975 + ).
  2976 +
  2977 +
  2978 +public define String
  2979 + format_extra_operands
  2980 + (
  2981 + List((String,String)) l
  2982 + ) =
  2983 + if l is
  2984 + {
  2985 + [ ] then "",
  2986 + [h . t] then if h is (n,v) then
  2987 + "&amp;"+n+"="+v+format_extra_operands(t)
  2988 + }.
  2989 +
  2990 +
  2991 + It seams that the standard requires "&amp;" instead of "&" !
  2992 +
  2993 + In case the target is another window, we need to format the options for this window.
  2994 +
  2995 +define String
  2996 + format
  2997 + (
  2998 + List(Other_Window_Option) l
  2999 + ) =
  3000 + if l is
  3001 + {
  3002 + [ ] then "",
  3003 + [h . t] then if h is
  3004 + {
  3005 + resizable then "resizable",
  3006 + scrollbars then "scrollbars",
  3007 + width(w) then "width="+w,
  3008 + height(h2) then "height="+h2
  3009 + } + if t is [ ] then "" else (","+format(t))
  3010 + }.
  3011 +
  3012 +
  3013 +
  3014 + Formating choices for a <select> tag.
  3015 +
  3016 +public define Printable_tree
  3017 + format_choices
  3018 + (
  3019 + List(String) l
  3020 + ) =
  3021 + if l is
  3022 + {
  3023 + [ ] then [ ],
  3024 + [h . t] then ["<option>", h, "</option>\n" . format_choices(t)]
  3025 + }.
  3026 +
  3027 +
  3028 +public define Printable_tree
  3029 + format_choices
  3030 + (
  3031 + List(String) l,
  3032 + InitialValue selected
  3033 + ) =
  3034 + if l is
  3035 + {
  3036 + [ ] then [ ],
  3037 + [h . t] then if h = selected.value
  3038 + then ["<option selected=\"selected\">", h, "</option>\n" . format_choices(t)]
  3039 + else ["<option>", h, "</option>\n" . format_choices(t,selected)]
  3040 + }.
  3041 +
  3042 +
  3043 +public define Printable_tree
  3044 + format_choices
  3045 + (
  3046 + List((List(CoreAttrs),WebArgValue,String)) l
  3047 + ) =
  3048 + if l is
  3049 + {
  3050 + [ ] then [ ],
  3051 + [h . t] then
  3052 + if h is (attrs,val,item)
  3053 + then ["<option value=\""+val.value+"\" "+format_attrs(attrs)+">", item, "</option>\n" . format_choices(t)]
  3054 + }.
  3055 +
  3056 +public define Printable_tree
  3057 + format_choices
  3058 + (
  3059 + List((List(CoreAttrs),WebArgValue,String)) l,
  3060 + InitialValue selected
  3061 + ) =
  3062 + if l is
  3063 + {
  3064 + [ ] then [ ],
  3065 + [h . t] then
  3066 + if h is (attrs,val,item) then
  3067 + if val.value = selected.value
  3068 + then ["<option value=\""+val.value+"\" "+format_attrs(attrs)+" selected=\"selected\">", item, "</option>\n" . format_choices(t)]
  3069 + else ["<option value=\""+val.value+"\" "+format_attrs(attrs)+" >", item, "</option>\n" . format_choices(t,selected)]
  3070 + }.
  3071 +
  3072 +
  3073 +
  3074 + Note: this counter is private to the virtual machine, hence there is one counter by
  3075 + client and by page : it seems that a new VM (simply a delegate) is started for each request.
  3076 +
  3077 +define Int
  3078 + new_count
  3079 + (
  3080 + Var(Int) count
  3081 + )
  3082 + =
  3083 + count <- *count+1;
  3084 + *count.
  3085 +
  3086 +
  3087 + The next function composes the URL. It is a JavaScript URL when the target is another
  3088 + window.
  3089 +
  3090 +define String
  3091 + make_actioner_url
  3092 + (
  3093 + CommonInfo cinfo,
  3094 + Actioner_Connection connection,
  3095 + Actioner_Target target,
  3096 + String state_name,
  3097 + String action_name,
  3098 + List((String,String)) extra_ops,
  3099 + Bool is_https
  3100 + ) =
  3101 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  3102 + with strict_url =
  3103 + if connection is
  3104 + {
  3105 + same then "/",
  3106 + http then "http://"+common_name+":"+http_port+"/",
  3107 + https then "https://"+common_name+":"+https_port+"/",
  3108 + } +
  3109 + "?a=" + action_name +
  3110 + format_extra_operands(extra_ops),
  3111 + if target is
  3112 + {
  3113 + same then strict_url,
  3114 + same(label) then strict_url+"#"+label,
  3115 + other(wn,ops) then
  3116 +
  3117 + "javascript:void window.open('"+strict_url+"&amp;t="+wn+"','"+
  3118 + "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"
  3119 + }.
  3120 +
  3121 +define String
  3122 + make_foreign_link_url
  3123 + (
  3124 + Actioner_Target target,
  3125 + String url
  3126 + ) =
  3127 + if target is
  3128 + {
  3129 + same then "/",
  3130 + same(label) then "/#"+label,
  3131 + other(wn,ops) then
  3132 +
  3133 + "javascript:void window.open('"+url+"','"+
  3134 + "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"
  3135 + }.
  3136 +
  3137 +
  3138 + Depending on the fact that the actioner refers to a form or not, the URL is used in two
  3139 + different ways. If the actioner does not refer to a form, it is realized by a '<a>'
  3140 + tag, with a 'href' attribute. If it refers to a form, it is still realized by a '<a>'
  3141 + tag, but with no href attribute. In this case, we use the 'onMouseDown' or 'onChange'
  3142 + event handler. The handler calls a JavaScript function which puts the URL as the value
  3143 + of the 'action' attribute of the form, and submits the form.
  3144 +
  3145 +type URL_or_JavaScript:
  3146 + url (String),
  3147 + javascript (Printable_tree script, Printable_tree handler).
  3148 +
  3149 +
  3150 + It was as shown below, in order to allow submission of a form from outside the form,
  3151 + but this makes problems:
  3152 +
  3153 +define URL_or_JavaScript
  3154 + format_action
  3155 + (
  3156 + String the_url,
  3157 + Actioner_Aspect aspect,
  3158 + Maybe(String) mb_id,
  3159 + Maybe(String) mb_form_name,
  3160 + Var(Int) action_count
  3161 + ) =
  3162 + if mb_form_name is
  3163 + {
  3164 + failure then
  3165 + url(the_url),
  3166 + success(form_name) then
  3167 + with n = new_count(action_count),
  3168 + fn_name = "pfu_" + if mb_id is
  3169 + {
  3170 + failure then form_name + "_" + n,
  3171 + success(id) then id,
  3172 + },
  3173 + javascript(
  3174 + [
  3175 + "<script type=\"text/javascript\" language =\"JavaScript\">\n",
  3176 + "function ", fn_name, "() {\n",
  3177 + " var fa = document.forms.",form_name,";\n",
  3178 + " var u = \"",the_url,"\";\n",
  3179 + " fa.action = u;",
  3180 + if aspect is submit(_, _) then " }\n"
  3181 + else "\n fa.submit(); }\n",
  3182 + "</script>\n"
  3183 + ],
  3184 + [fn_name,"();"]
  3185 + )
  3186 + }.
  3187 +
  3188 +
  3189 +
  3190 + Now, we format the actioner according to its aspect.
  3191 +
  3192 +define List(Text_Option)
  3193 + get_text_options
  3194 + (
  3195 + List(Text_Option) l
  3196 + )
  3197 + =
  3198 + if l is
  3199 + {
  3200 + [] then [],
  3201 + [h . t ] then
  3202 + if h is class(_) then
  3203 + get_text_options(t)
  3204 + else if h is id(_) then
  3205 + get_text_options(t)
  3206 + else if h is style(_) then
  3207 + get_text_options(t)
  3208 + else if h is title(_) then
  3209 + get_text_options(t)
  3210 + else
  3211 + [ h . get_text_options(t) ]
  3212 +
  3213 + }.
  3214 +
  3215 + /**
  3216 + * Extract the CSS class list from the list of Text_Option
  3217 + */
  3218 +define List(CoreAttrs)
  3219 + get_css_class
  3220 + (
  3221 + List(Text_Option) l
  3222 + )
  3223 + =
  3224 + if l is
  3225 + {
  3226 + [] then [],
  3227 + [h . t ] then
  3228 +
  3229 +
  3230 + if h is class(name) then
  3231 + [ class(name) . get_css_class(t) ]
  3232 + else if h is id(name) then
  3233 + [ id(name) . get_css_class(t) ]
  3234 + else if h is style(the_style) then
  3235 + [ style(the_style) . get_css_class(t) ]
  3236 + else if h is title(name) then
  3237 + [ tooltip(name) . get_css_class(t) ]
  3238 + else if h is attr(name, value) then
  3239 + [ attr(name, value) . get_css_class(t) ]
  3240 + else
  3241 + get_css_class(t)
  3242 + }
  3243 + .
  3244 +
  3245 +define Printable_tree
  3246 + format
  3247 + (
  3248 + List(Actioner_Local_Action) l
  3249 + ) =
  3250 + if l is
  3251 + {
  3252 + [ ] then [ ],
  3253 + [h . t] then [if h is
  3254 + {
  3255 + close_window then [" window.close(); "]
  3256 + }
  3257 + . format(t)]
  3258 + }.
  3259 +
  3260 +public define String
  3261 + format_attrs
  3262 + (
  3263 + List(CoreAttrs) attributs
  3264 + )=
  3265 + if attributs is
  3266 + {
  3267 + [] then "",
  3268 + [h . t] then
  3269 + with current = if h is
  3270 + {
  3271 + id(id_name) then
  3272 + " id=\"" + id_name + "\"",
  3273 + class(class_name) then
  3274 + " class=\"" + class_name + "\"",
  3275 + style(style_string) then
  3276 + " style=\"" + style_string + "\"",
  3277 +
  3278 + title(title_string) then
  3279 + " title=\"" + title_string + "\"",
  3280 +
  3281 + lang(lang) then
  3282 + " xml:lang=" + lang,
  3283 + dir(reading_Way) then
  3284 + if reading_Way is
  3285 + {
  3286 + ltr then " dir=ltr",
  3287 + rtl then " dir=rtl"
  3288 + },
  3289 +
  3290 + accesskey(key) then
  3291 + " accesskey=\"" + key + "\"",
  3292 + tabindex(index) then
  3293 + " tabindex=\"" + index + "\"",
  3294 +
  3295 + attr(name, value) then
  3296 + " " + name + "=\"" + value + "\"",
  3297 +
  3298 + event(e, value) then
  3299 + " " + event_name(e) + "=\"" + value + "\"",
  3300 + },
  3301 + current + format_attrs(t)
  3302 + }.
  3303 +
  3304 +define String
  3305 + format_attrs
  3306 + (
  3307 + List(InputAttrs) attributs
  3308 + )=
  3309 + if attributs is
  3310 + {
  3311 + [] then "",
  3312 + [h . t] then
  3313 + with current = if h is
  3314 + {
  3315 + class(class_name) then
  3316 + " class=\"" + class_name + "\"",
  3317 + style(style_string) then
  3318 + " style=\"" + style_string + "\"",
  3319 +
  3320 + title(title_string) then
  3321 + " title=\"" + title_string + "\"",
  3322 +
  3323 + lang(lang) then
  3324 + " xml:lang=" + lang,
  3325 + dir(reading_Way) then
  3326 + if reading_Way is
  3327 + {
  3328 + ltr then " dir=ltr",
  3329 + rtl then " dir=rtl"
  3330 + },
  3331 +
  3332 + accesskey(key) then
  3333 + " accesskey=\"" + key + "\"",
  3334 + tabindex(index) then
  3335 + " tabindex=\"" + index + "\"",
  3336 +
  3337 + attr(name, value) then
  3338 + " " + name + "=\"" + value + "\"",
  3339 +
  3340 + event(e, value) then
  3341 + " " + event_name(e) + "=\"" + value + "\"",
  3342 + },
  3343 + current + format_attrs(t)
  3344 + }.
  3345 +
  3346 +define String
  3347 + format_text_options
  3348 + (
  3349 + List(Text_Option) l
  3350 + )
  3351 + =
  3352 + with text_options = get_text_options(l),
  3353 + css_classes = get_css_class(l),
  3354 + if text_options is
  3355 + {
  3356 + [] then "",
  3357 + [_ . _] then " style=\"" + format(text_options) + "\" "
  3358 + }
  3359 + +
  3360 + if css_classes is
  3361 + {
  3362 + [] then "",
  3363 + [_ . _] then format_attrs(css_classes)
  3364 + }.
  3365 +
  3366 +//define String
  3367 +// _format
  3368 +// (
  3369 +// List(CoreAttrs) opt
  3370 +// )=
  3371 +// if opt is
  3372 +// {
  3373 +// [] then "",
  3374 +// [h .t] then
  3375 +// with current = if h is
  3376 +// {
  3377 +// id(id_name) then
  3378 +// " id=\"" + id_name + "\"",
  3379 +// class(class_name) then
  3380 +// " class=\"" + class_name + "\"",
  3381 +// style(style_string) then
  3382 +// " style=\"" + style_string + "\"",
  3383 +//
  3384 +// title(title_string) then
  3385 +// " title=\"" + title_string + "\"",
  3386 +// lang(lang) then
  3387 +// " xml:lang=" + lang,
  3388 +// dir(reading_Way) then
  3389 +// if reading_Way is
  3390 +// {
  3391 +// ltr then " dir=ltr",
  3392 +// rtl then " dir=rtl"
  3393 +// },
  3394 +// attr(name, value) then
  3395 +// " " + name + "=\"" + value + "\"",
  3396 +// event(e, value) then
  3397 +// " " + event_name(e) + "=\"" + value + "\""
  3398 +// },
  3399 +// current + _format(t)
  3400 +// }
  3401 +// .
  3402 +
  3403 +define Printable_tree
  3404 + format_div_option
  3405 + (
  3406 + List(CoreAttrs) options
  3407 + )=
  3408 + ["<div" + format_attrs(options) + ">"] .
  3409 +
  3410 +
  3411 +define Maybe(String)
  3412 + extract_id
  3413 + (
  3414 + List(CoreAttrs) attrbs
  3415 + ) =
  3416 + if attrbs is
  3417 + {
  3418 + [] then failure,
  3419 + [h . t] then
  3420 + if h is id(value) then success(value)
  3421 + else extract_id(t)
  3422 + }.
  3423 +
  3424 +define Maybe(String)
  3425 + extract_id
  3426 + (
  3427 + Actioner_Aspect aspect
  3428 + ) =
  3429 + if aspect is
  3430 + {
  3431 + link(_,_,_) then failure,
  3432 + img_link(_,_) then failure,
  3433 + push_button(opts,_) then extract_id(opts),
  3434 + button(_,_) then failure,
  3435 + button(_,_,_,_) then failure,
  3436 + submit(opts,_) then extract_id(opts),
  3437 + immediate_selector(_,_,_,_) then failure,
  3438 + immediate_selector(_,_,_,_,_) then failure,
  3439 + }.
  3440 +
  3441 +to do Complete format_foreign_link
  3442 +//TODO Complete format_foreign_link
  3443 +define Printable_tree
  3444 + format_foreign_link
  3445 + (
  3446 +// CommonInfo cinfo,
  3447 + Actioner_Target target,
  3448 + Actioner_Aspect aspect,
  3449 + String url,
  3450 + Bool is_https,
  3451 + ) =
  3452 + //if cinfo is info(common_name,http_port,https_port,site_dir,secret) then
  3453 + with full_url = make_foreign_link_url(target,url),
  3454 +// with action = format_action(full_url, aspect, extract_id(aspect), mb_form_name),
  3455 + if aspect is
  3456 + {
  3457 +
  3458 + link(opt, text, mb_name) then
  3459 + with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",
  3460 + [
  3461 + "<a href=\"", full_url, "\"", format_text_options(opt), name_tag, ">",
  3462 + text,
  3463 + "</a>"
  3464 + ],
  3465 + img_link(img,alt_text) then
  3466 + [
  3467 + "<a href=\"", full_url ,"\"><img src=\"", img,
  3468 + "\" alt=\"" + alt_text + "\" border=\"0\"></a>"
  3469 + ],
  3470 + push_button(options, text) then
  3471 + ["<a href=\"",full_url,"\"", format_attrs(options), ">",
  3472 + text, "</a>"
  3473 + ],
  3474 + button(url_off,url_on) then
  3475 + [ ],
  3476 +
  3477 + button(url_off,url_on,w,h) then
  3478 + [ ],
  3479 +
  3480 + submit(options, text) then
  3481 + [ ],
  3482 +
  3483 + immediate_selector(opt,name,size,choices) then
  3484 + [ ],
  3485 + immediate_selector(opt,name,size,choices,selected) then
  3486 + [ ],
  3487 + }.
  3488 +
  3489 +define Printable_tree
  3490 + format_actioner
  3491 + (
  3492 + CommonInfo cinfo,
  3493 + String state_name,
  3494 + Actioner_Connection connection,
  3495 + Actioner_Target target,
  3496 + Actioner_Aspect aspect,
  3497 + String action_name,
  3498 + List((String,String)) extra_ops,
  3499 + List(Actioner_Local_Action) local_actions,
  3500 + Maybe(String) mb_form_name,
  3501 + Bool is_https,
  3502 + Var(Int) action_count
  3503 + ) =
  3504 + if cinfo is info(common_name,http_port,https_port,site_dir,secret) then
  3505 + with url = make_actioner_url(cinfo,connection,target,
  3506 + state_name,action_name,extra_ops,is_https),
  3507 + with action = format_action(url, aspect, extract_id(aspect), mb_form_name, action_count),
  3508 + if aspect is
  3509 + {
  3510 +
  3511 + link(opt, text, mb_name) then
  3512 + with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",
  3513 + [
  3514 + "<a href=\"", url, "\"", format_text_options(opt), name_tag, ">",
  3515 + text,
  3516 + "</a>"
  3517 + ],
  3518 + img_link(img, alt_text) then
  3519 + [
  3520 + "<a href=\"", url ,"\"><img src=\"", img,
  3521 + "\" alt=\"" + alt_text + "\" border=\"0\"></a>"
  3522 + ],
  3523 + push_button(options, text) then
  3524 + [
  3525 + if action is
  3526 + {
  3527 + url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",
  3528 + text, "</a>"
  3529 + ],
  3530 + javascript(s,h) then
  3531 + if action_name = "" then
  3532 + ["<input type=\"button\" value=\"",text,"\"", format_attrs(options), " />"]
  3533 + else
  3534 + [s,"<input type=\"button\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]
  3535 + }
  3536 + ],
  3537 + button(url_off,url_on) then
  3538 + [ if action is
  3539 + {
  3540 + url(u) then ["<a href=\"",u],
  3541 + javascript(s,h) then [s,"<a onMouseDown=\"",h]
  3542 + },
  3543 + "\" style=\"text-decoration:none\">",
  3544 + "<img alt=\"",url_off,"\" src=\"",url_off,"\" border=0",
  3545 + " onMouseOver=\"this.src='",url_on,"'\" ",
  3546 + " onMouseOut=\"this.src='",url_off,"'\">",
  3547 + "</a>"
  3548 + ],
  3549 +
  3550 + button(url_off,url_on,w,h) then
  3551 + [ if action is
  3552 + {
  3553 + url(u) then ["<a href=\"",u],
  3554 + javascript(s,h2) then [s,"<a onMouseDown=\"",h2]
  3555 + },
  3556 + "\" style=\"text-decoration:none\">",
  3557 + "<img width=",w," height=",h," alt=\"",url_off,"\" src=\"",url_off,"\" border=0",
  3558 + " onMouseOver=\"this.src='",url_on,"'\" ",
  3559 + " onMouseOut=\"this.src='",url_off,"'\">",
  3560 + "</a>"
  3561 + ],
  3562 +
  3563 + submit(options, text) then
  3564 + [
  3565 + if action is
  3566 + {
  3567 + url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",
  3568 + text, "</a>"
  3569 + ],
  3570 + javascript(s,h) then
  3571 + if action_name = "" then // special case where URL (so the action_name) is provided by the form itself
  3572 + // so javascript isn't needed. This is the standard HMTL way.
  3573 + ["<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " />"]
  3574 + else
  3575 + [s,"<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]
  3576 + }
  3577 + ],
  3578 +
  3579 + immediate_selector(options,name,size,choices) then
  3580 + [ if action is
  3581 + {
  3582 + url(u) then ["<select href=\"",u]
  3583 + javascript(s,h) then [s,"<select onchange=\"",h]
  3584 + },
  3585 + "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",
  3586 + format_choices(choices),"</select>"
  3587 + ],
  3588 + immediate_selector(options,name,size,choices,selected) then
  3589 + [ if action is
  3590 + {
  3591 + url(u) then ["<select href=\"",u]
  3592 + javascript(s,h) then [s,"<select onchange=\"",h]
  3593 + },
  3594 + "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",
  3595 + format_choices(choices, selected),"</select>"
  3596 + ],
  3597 + }.
  3598 +
  3599 +
  3600 +
  3601 +
  3602 +
  3603 +
  3604 + *** [5.5] Formating a private download link.
  3605 +
  3606 + We get the absolute path of the file to be downloaded, and the name under which it
  3607 + should appear to the client. The function 'format_private_download' creates an
  3608 + hypertext link for downloading the file. The secured mecanism of private download is
  3609 + used. This function is called by the function which formats HTML_Any($T) elements.
  3610 +
  3611 +
  3612 +define Printable_tree
  3613 + format_private_download
  3614 + (
  3615 + CommonInfo cinfo,
  3616 + String sn, // state name
  3617 + String abs_path, // absolute file path on server
  3618 + String name, // name of file as it appears in the browser
  3619 + String extra, // extra extension
  3620 + Maybe((String,List((String,String)))) action
  3621 +
  3622 + ) =
  3623 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  3624 + with private_download_directory = site_directory+"/private_download",
  3625 + with auth = make_authorization(site_directory,secret,abs_path),
  3626 + [
  3627 + "<a href=\"",name,extra,"?zauth=",auth,
  3628 + if action is
  3629 + {
  3630 + failure then [ ]
  3631 + success(a) then if a is (an,args) then
  3632 + ["&amp;a=",an,format_extra_operands(args)]
  3633 + },
  3634 + "\">",
  3635 + name,
  3636 + "</a>"
  3637 + ].
  3638 +
  3639 +
  3640 +
  3641 +
  3642 + *** [5.6] Formating rows and cells in a table.
  3643 +
  3644 +define Int
  3645 + percent
  3646 + (
  3647 + Int p
  3648 + ) =
  3649 + if p < 0 then 0 else if p > 100 then 100 else p.
  3650 +
  3651 +
  3652 +
  3653 +
  3654 + Formating cell options.
  3655 +
  3656 +
  3657 +
  3658 +define String
  3659 + format
  3660 + (
  3661 + BackgroundOption o
  3662 + ) =
  3663 + if o is
  3664 + {
  3665 + repeat then "",
  3666 + repeat_horizontal then "; background-repeat: repeat-x",
  3667 + repeat_vertical then "; background-repeat: repeat-y",
  3668 + no_repeat then "; background-repeat: no-repeat",
  3669 + center then "; background-position: center top"
  3670 + }.
  3671 +
  3672 +define String
  3673 + format
  3674 + (
  3675 + List(BackgroundOption) l
  3676 + ) =
  3677 + if l is
  3678 + {
  3679 + [ ] then "",
  3680 + [h . t] then format(h)+format(t)
  3681 + }.
  3682 +
  3683 +
  3684 +define String
  3685 + format
  3686 + (
  3687 + List(Cell_Option) options
  3688 + ) =
  3689 + if options is
  3690 + {
  3691 + [ ] then "",
  3692 + [h . t] then
  3693 + if h is
  3694 + {
  3695 + core_attrs(core_attr_list) then format_attrs(core_attr_list),
  3696 + left then " align=\"left\"",
  3697 + h_center then " align=\"center\"",
  3698 + right then " align=\"right\"",
  3699 + top then " valign=\"top\"",
  3700 + v_center then " valign=\"middle\"",
  3701 + bottom then " valign=\"bottom\"",
  3702 + base_line then " valign=\"baseline\"",
  3703 + background_color(c) then " bgcolor=\""+html_format(c)+"\"",
  3704 + background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"",
  3705 + width(w) then " width=\""+w+"\"",
  3706 + percentage_width(n) then " width=\""+percent(n)+"%\"",
  3707 + height(h2) then " height=\""+h2+"\"",
  3708 + columns(n) then " colspan=\""+n+"\"",
  3709 + rows(n) then " rowspan=\""+n+"\"",
  3710 + nowrap then " nowrap",
  3711 + class(class_name) then " class=\""+class_name+"\""
  3712 + }
  3713 + + format(t)
  3714 + }.
  3715 +
  3716 +
  3717 + Normalizing a list of cell options (horizontal position must be specified; the default
  3718 + is 'left').
  3719 +
  3720 + Formating cells in a row.
  3721 +
  3722 +define Printable_tree
  3723 + format
  3724 + (
  3725 + List(HTML_Cell($T)) cells,
  3726 + $T -> Printable_tree format_element
  3727 + ) =
  3728 + if cells is
  3729 + {
  3730 + [ ] then [ ],
  3731 + [h . t] then if h is cell(options,element) then
  3732 + ["<td",format(reverse(options)),">",
  3733 + format_element(element),
  3734 + "</td>"
  3735 + . format(t,format_element)]
  3736 + }.
  3737 +
  3738 +define Printable_tree
  3739 + format
  3740 + (
  3741 + List(HTML_Header_Cell($T)) cells,
  3742 + $T -> Printable_tree format_element
  3743 + ) =
  3744 + if cells is
  3745 + {
  3746 + [ ] then [ ],
  3747 + [h . t] then if h is header_cell(options,element) then
  3748 + ["<th ",format(reverse(options)),">",
  3749 + format_element(element),
  3750 + "</th>"
  3751 + . format(t,format_element)]
  3752 + }.
  3753 +
  3754 + Formating the rows in a table.
  3755 +
  3756 +define Printable_tree
  3757 + format
  3758 + (
  3759 + List(HTML_Row($T)) rows,
  3760 + $T -> Printable_tree format_element,
  3761 + ) =
  3762 + if rows is
  3763 + {
  3764 + [ ] then [ ],
  3765 + [h . t] then if h is row(options,cells) then
  3766 + ["<tr",format(reverse(options)),">",
  3767 + format(cells,format_element),
  3768 + "</tr>\n"
  3769 + . format(t,format_element)]
  3770 + }.
  3771 +
  3772 +define Printable_tree
  3773 + format
  3774 + (
  3775 + HTML_Header_Row($T) row,
  3776 + $T -> Printable_tree format_element
  3777 + ) =
  3778 + if row is
  3779 + {
  3780 + empty then [ ],
  3781 + header_row(options,cells) then
  3782 + ["<thead> <tr",format(reverse(options)),">",
  3783 + format(cells,format_element),
  3784 + "</tr> </thead>\n"
  3785 + ]
  3786 + }.
  3787 +
  3788 +define Printable_tree
  3789 + format
  3790 + (
  3791 + HTML_Footer_Row($T) row,
  3792 + $T -> Printable_tree format_element
  3793 + ) =
  3794 + if row is
  3795 + {
  3796 + empty then [ ],
  3797 + footer_row(options,cells) then
  3798 + ["<tfoot> <tr",format(reverse(options)),">",
  3799 + format(cells,format_element),
  3800 + "</tr> </tfoot>\n"
  3801 + ]
  3802 + }.
  3803 +
  3804 +define Printable_tree
  3805 + format1
  3806 + (
  3807 + List(TextAreaOption) l
  3808 + ) =
  3809 + if l is
  3810 + {
  3811 + [] then [],
  3812 + [h . t] then if h is
  3813 + {
  3814 + input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)],
  3815 + disabled then [" disabled=\"disabled\" " . format1(t)]
  3816 + read_only then [" readonly=\"readonly\" " . format1(t)]
  3817 + wrap_lines then [" wrap=\"wrap\" " . format1(t)]
  3818 + }
  3819 + }.
  3820 +
  3821 +define Printable_tree
  3822 + format
  3823 + (
  3824 + List(TextAreaOption) l
  3825 + ) =
  3826 + if member(l,wrap_lines)
  3827 + then format1(l)
  3828 + else [" wrap=\"off\" " . format1(l)].
  3829 +
  3830 +
  3831 + *** [5.7] Formating elements which may be put anywhere.
  3832 +
  3833 + The function below involves the parameter $T which is later instantiated as
  3834 + 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions
  3835 + for these two types, and because formating of tables requires recursive calls of such
  3836 + functions, it is necessary to provide the 'format' function to be called recursively as
  3837 + an argument. Putting naively a call to 'format' will not work, because the compiler
  3838 + will look for a function able to format data of type $T (which is at that time distinct
  3839 + from any other type, including our two types). Such a function does not exist. Hence
  3840 + the function to be called for formating elements must be passed as a functional
  3841 + argument (called 'format_element' below). Actually, what we pass is a function taking
  3842 + a unique argument of type $T. Other informations (like the name of the state) are
  3843 + already in the function by way of full functionality.
  3844 +
  3845 +
  3846 + Formating text options. They are formated in CSS syntax, to be used within a
  3847 + 'style=...'.
  3848 +
  3849 +define String
  3850 + format
  3851 + (
  3852 + List(Text_Option) l
  3853 + ) =
  3854 + if l is
  3855 + {
  3856 + [ ] then "",
  3857 + [h . t] then if h is
  3858 + {
  3859 + size(n) then "font-size:"+n+"pt",
  3860 + font(fn) then "font-family:"+fn,
  3861 + color(c) then if c is rgb(r,g,b) then
  3862 + "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")",
  3863 + italic then "font-style:italic",
  3864 + oblique then "font-style:oblique",
  3865 + small_capitals then "font-variant:small-caps",
  3866 + bold then "font-weight:bold",
  3867 + underlined then "text-decoration:underline",
  3868 + left_justified then "text-align:left",
  3869 + right_justified then "text-align:right",
  3870 + justified then "text-align:justify",
  3871 + line_through then "text-decoration:line-through",
  3872 + nowrap then "white-space:nowrap",
  3873 + class(class_name)then " class=\"" + class_name +"\"",
  3874 + id(id_name) then " id=\"" + id_name +"\"",
  3875 + style(style_string) then " style=\"" + style_string + "\"",
  3876 + title(s) then " title=\"" + s +"\""
  3877 + attr(n,v) then " " + n + "=\"" + v +"\""
  3878 + } + if t is [ ] then "" else ("; "+format(t))
  3879 + }.
  3880 +
  3881 +
  3882 +
  3883 + Formating table options.
  3884 +
  3885 +define String
  3886 + format
  3887 + (
  3888 + List(Table_Option) l,
  3889 + Bool border_seen
  3890 + ) =
  3891 + if l is
  3892 + {
  3893 + [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"",
  3894 + [h . t] then if h is
  3895 + {
  3896 + background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen),
  3897 + background_image(url) then " background="+url+format(t,border_seen),
  3898 + border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+
  3899 + //" bordercolor="+format(c)+
  3900 + format(t,true),
  3901 + width(w) then " width=\""+w+"\""+format(t,border_seen),
  3902 + percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen),
  3903 + attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen),
  3904 + class(name) then " class=\""+name+"\""
  3905 + }
  3906 + }.
  3907 +
  3908 +
  3909 +
  3910 +
  3911 +
  3912 +define Printable_tree
  3913 + format_scroller
  3914 + (
  3915 + String sn,
  3916 + Int width,
  3917 + Int height,
  3918 + Int content_width,
  3919 + Int content_height,
  3920 + Int idnum, // identifying the scroller
  3921 + $T content,
  3922 + $T -> Printable_tree format_element
  3923 + ) =
  3924 + [
  3925 + "<script type = \"text/javascript\" language=\"JavaScript\">",
  3926 + "function doscroll_",idnum,"(dx,dy) {\n",
  3927 + " if (document.layers) { var c_",idnum," = eval(document.cs_",idnum,"); } else\n",
  3928 + " if (document.getElementById) {var c_",idnum," = eval(\"document.getElementById('cs_",
  3929 + idnum,"').style\"); } else\n",
  3930 + " if (document.all) { var c_",idnum," = eval(document.all.cs_",idnum,".style); };\n",
  3931 + " var x_",idnum," = parseInt(c_",idnum,".left);\n",
  3932 + " var y_",idnum," = parseInt(c_",idnum,".top);\n",
  3933 + " if ((x_",idnum,"+dx <= 0) && (x_",idnum,"+dx > ",width-content_width,"))\n",
  3934 + " { x_",idnum," += dx; }\n",
  3935 + " if ((y_",idnum,"+dy <= 0) && (y_",idnum,"+dy > ",height-content_height,"))\n",
  3936 + " { y_",idnum," += dy; }\n",
  3937 + " c_",idnum,".left = x_",idnum,";\n",
  3938 + " c_",idnum,".top = y_",idnum,";\n",
  3939 + " }\n",
  3940 + "</script>\n",
  3941 + "<table>",
  3942 + "<tbody>",
  3943 + "<tr>",
  3944 + "<td align=left valign=top",
  3945 + " width=",width,
  3946 + " height=",height,
  3947 + ">",
  3948 + "<div id=\"ws_",idnum,"\" style=\"position:absolute; width:",width,"px; height:",height,"px;",
  3949 + " clip:rect(0px ",width,"px ",height,"px 0px)\">",
  3950 + "<div id=\"cs_",idnum,"\" style=\"position:absolute; left:0px; top:0px\">",
  3951 + format_element(content),
  3952 + "</div>",
  3953 + "</div>",
  3954 + "</td>",
  3955 + "<td valign=bottom>",
  3956 + "<table>",
  3957 + "<tbody>",
  3958 + "<tr><td><img alt=\"sroll up\" src=\"scrollup.gif\" onmousedown=\"doscroll_", idnum,"(0,20);\"></td></tr>",
  3959 + "<tr><td><img alt=\"scroll down\" src=\"scrolldown.gif\" onmousedown=\"doscroll_", idnum,"(0,-20);\"></td></tr>",
  3960 + "</tbody>",
  3961 + "</table>",
  3962 + "</td>",
  3963 + "</tr>",
  3964 + (if content_width > width then
  3965 + [
  3966 + "<tr>",
  3967 + "<td align=right>",
  3968 + "<table>",
  3969 + "<tbody>",
  3970 + "<tr>",
  3971 + "<td><img alt=\"scroll left\" src=\"scrollleft.gif\" onmousedown=\"doscroll_", idnum,"(20,0);\"></td>",
  3972 + "<td><img alt=\"scroll right\" src=\"scrollright.gif\" onmousedown=\"doscroll_", idnum,"(-20,0);\"></td>",
  3973 + "</tr>",
  3974 + "</tbody>",
  3975 + "</table>",
  3976 + "</td>",
  3977 + "</tr>",
  3978 + ] else [ ]),
  3979 + "</tbody>",
  3980 + "</table>"
  3981 + ].
  3982 +
  3983 +
  3984 +
  3985 +define Printable_tree
  3986 + format
  3987 + (
  3988 + Body_Option o
  3989 + ) =
  3990 + if o is
  3991 + {
  3992 + core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)],
  3993 + background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""],
  3994 + background_image(n) then [" background=", n],
  3995 + background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""]
  3996 +
  3997 + }.
  3998 +
  3999 +
  4000 +
  4001 +define Printable_tree
  4002 + format
  4003 + (
  4004 + List(Body_Option) l
  4005 + ) =
  4006 + if l is
  4007 + {
  4008 + [ ] then [ ],
  4009 + [h . t] then [format(h) . format(t)]
  4010 + }.
  4011 +
  4012 +define Printable_tree
  4013 + add_css_files
  4014 + (
  4015 + List(CSS_File) l
  4016 + ) =
  4017 + if l is
  4018 + {
  4019 + [ ] then [ ],
  4020 + [h . t] then
  4021 + [ ["<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file_name(h) + "\" />\n" ]
  4022 + . add_css_files(t)]
  4023 + }.
  4024 +
  4025 +define Printable_tree
  4026 + add_js_files_attributes
  4027 + (
  4028 + List(JS_Attribute) l
  4029 + ) =
  4030 + if l is
  4031 + {
  4032 + [ ] then [ ],
  4033 + [h . t] then
  4034 + if h is attr(name, value) then
  4035 + [ " " + name + "=\"" + value + "\""
  4036 + . add_js_files_attributes(t)]
  4037 + }.
  4038 +
  4039 +
  4040 +define Printable_tree
  4041 + add_js_files
  4042 + (
  4043 + List(JS_File) l
  4044 + ) =
  4045 + if l is
  4046 + {
  4047 + [ ] then [ ],
  4048 + [h . t] then
  4049 + [ ["<script src=\""+ file_name(h) +"\" type=\"text/javascript\""
  4050 + . add_js_files_attributes(attributes(h)) ]
  4051 + . ["></script>\n"
  4052 + . add_js_files(t)] ]
  4053 + }.
  4054 +
  4055 +define Printable_tree
  4056 + add_script
  4057 + (
  4058 + List(Script) l
  4059 + ) =
  4060 + if l is
  4061 + {
  4062 + [ ] then [ ],
  4063 + [h . t] then [ "<script type=\""+ script_type(h) +"\">\n"+ content(h) + "\n</script>\n" . add_script(t) ]
  4064 + }.
  4065 +
  4066 +define Printable_tree
  4067 + add_css_styles
  4068 + (
  4069 + List(CSS_Style) css_styles
  4070 + ) =
  4071 +
  4072 + if css_styles is
  4073 + {
  4074 + [] then [],
  4075 + [_ . _] then [ "<style type=\"text/css\"><!--\n",
  4076 + format_css_styles(css_styles),
  4077 + " --></style>\n"
  4078 + ]
  4079 + }.
  4080 +
  4081 +
  4082 + // The function below formats a datum of type 'HTML_Any($T)'.
  4083 +
  4084 +define Printable_tree
  4085 + format
  4086 + (
  4087 + CommonInfo cinfo,
  4088 + String sn, // state_name
  4089 + Var(Int) ic_v,
  4090 + HTML_Any($T) element,
  4091 + $T -> Printable_tree format_element, // able to format a datum of type $T
  4092 + Bool is_https,
  4093 + Var(Int) action_count
  4094 + ) =
  4095 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4096 + if element is
  4097 + {
  4098 + any_text(opts , t) then
  4099 + if opts is
  4100 + {
  4101 + [] then [t],
  4102 + [_ . _] then ["<span", format_text_options(opts), ">",t,"</span>"]
  4103 + },
  4104 + any_preformated(opts,s) then
  4105 + ["<span", format_text_options(opts), "><pre>",s,"</pre></span>"],
  4106 + //["<pre>",s,"</pre>"],
  4107 + any_paragraph(opts,e) then
  4108 + ["<p", format_text_options(opts), ">",format_element(e),"</p>\n"],
  4109 + any_image(opts, url, alt) then
  4110 + ["<img alt=\"",alt,"\" src=\"",url,"\" ", format_attrs(opts)," />"],
  4111 + any_image(opts, url, alt, w, h) then
  4112 + ["<img alt=\"",alt,"\" src=\"",url,"\" width=\"",w,"\" height=\"",h,"\" ", format_attrs(opts)," />"],
  4113 + any_table(opts,h_row, rows, f_row) then
  4114 + ["<table",format(reverse(opts),false),">",
  4115 + format(h_row, format_element),
  4116 + "<tbody>",format(rows,format_element),"</tbody>",
  4117 + format(f_row, format_element),
  4118 + "</table>\n"],
  4119 + any_center(e) then
  4120 + ["<center>",format_element(e),"</center>"],
  4121 + any_mail_to(email,elem) then
  4122 + ["<a href=\"mailto:",email,"\">",format_element(elem),"</a>"],
  4123 + any_scroller(w,h,cw,ch,c) then
  4124 + format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element),
  4125 + any_fixed_size(w,h,c) then
  4126 + with url = create_secondary_document(site_directory,secret,sn,format_element,c,w),
  4127 + ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",
  4128 + "secondary document",
  4129 + "</object>"],
  4130 + any_fixed_size_2(w,h,fn) then
  4131 + with url = fn+"?zauth="+make_authorization(site_directory,secret,
  4132 + fn),
  4133 + ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",
  4134 + "secondary document",
  4135 + "</object>"],
  4136 + any_actioner(c,t,a,an,eo,ja,fn) then
  4137 + format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https, action_count),
  4138 +
  4139 + any_foreign_link_new(target, aspect, url) then
  4140 + format_foreign_link(target, aspect, url, is_https),
  4141 +
  4142 + any_foreign_link(options,url) then
  4143 + ["<a href=\"",url,"\" ", format_text_options(options), "></a>"], // IE7 doesn't support the form <a href="..." />
  4144 + any_foreign_link(options,url,name) then
  4145 + ["<a href=\"",url,"\"><span ", format_text_options(options), ">",name,"</span></a>"],
  4146 + any_private_download(url,name,extra_ext,action) then
  4147 + format_private_download(cinfo,sn,url,name,extra_ext,action),
  4148 + any_div(options, e) then
  4149 + [format_div_option(options), format_element(e),"</div>\n"],
  4150 + any_div_empty(options) then
  4151 + [format_div_option(options), "</div>\n"],
  4152 + any_coreattrs(attributs) then
  4153 + [format_attrs(attributs)]
  4154 + }.
  4155 +
  4156 +
  4157 +
  4158 +
  4159 + // *** [5.8] Formating 'in form' elements.
  4160 +
  4161 +
  4162 +define Printable_tree
  4163 + maybe_label
  4164 + (
  4165 + String label_text,
  4166 + HtmlId id
  4167 + ) =
  4168 + if length(label_text) > 0 then ["<label for=\"",id,"\">",label_text,"</label>"]
  4169 + else [].
  4170 +
  4171 +
  4172 +define Printable_tree
  4173 + format
  4174 + (
  4175 + CommonInfo cinfo,
  4176 + String fn, // form_name
  4177 + String sn, // state_name
  4178 + Var(Int) ic_v, // idnum counter variable
  4179 + HTML_In_Form element,
  4180 + Bool is_https,
  4181 + Var(Int) action_count
  4182 + ) =
  4183 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4184 + with format_element = (HTML_In_Form e) |-> format(cinfo, fn, sn, ic_v, e, is_https, action_count),
  4185 + if element is
  4186 + {
  4187 + literal_pt(t) then t,
  4188 + literal(t) then [t],
  4189 + sequence(l) then flat(map(format_element,l))
  4190 + text(opts,t) then
  4191 + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https, action_count),
  4192 + preformated(o,s) then
  4193 + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https, action_count),
  4194 + paragraph(opts,t) then
  4195 + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https, action_count),
  4196 + image(opts, url, alt) then
  4197 + format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https, action_count),
  4198 + image(opts, url, alt, w, h) then
  4199 + format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https, action_count),
  4200 + table(opts,header_row,rows,footer_row) then
  4201 + format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https, action_count),
  4202 + center(e) then
  4203 + format(cinfo,sn,ic_v,any_center(e),format_element,is_https, action_count),
  4204 + mail_to(a,e) then
  4205 + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https, action_count),
  4206 + scroller(w,h,cw,ch,c) then
  4207 + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https, action_count),
  4208 + actioner(c,t,a,an,eo,ja) then
  4209 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https, action_count),
  4210 +
  4211 + foreign_link_new(target, aspect, url) then
  4212 + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https, action_count),
  4213 +
  4214 + foreign_link(options,url) then
  4215 + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https, action_count),
  4216 + foreign_link(options,url,name) then
  4217 + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https, action_count),
  4218 + private_download(url,name,extra,action) then
  4219 + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https, action_count),
  4220 + text_input(options, label_text, id, name, i, w) then
  4221 + [ maybe_label(label_text, id),
  4222 + "<input type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4223 + text_input_ro(options, label_text, id, name,i,w) then
  4224 + [ maybe_label(label_text, id),
  4225 + "<input readonly=\"readonly\" type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4226 + password_input(options, label_text, id, name,i,w) then
  4227 + [ maybe_label(label_text, id),
  4228 + "<input type=\"password\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4229 + text_area(opts,label_text, id, n,i,w,h) then
  4230 + [ maybe_label(label_text, id), "<textarea ",format(opts)," id=\"",id,"\" name=\"",n,"\" cols=\"",w,"\" rows=\"",h,"\">",i,"</textarea>"],
  4231 + file_upload(options, label, id, n, w) then
  4232 + [ maybe_label(label, id),
  4233 + "<input type=\"file\" id=\"",id,"\" size=\"",w,"\" name=\"",n,"\"",format_attrs(options)," />"],
  4234 + selector(opts, label, id, n,s,cs) then
  4235 + [ maybe_label(label, id),
  4236 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],
  4237 + selector(opts, label, id, n,s,cs,sd) then
  4238 + [ maybe_label(label, id),
  4239 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],
  4240 + selector_c(opts, label, id, n,s,cs) then
  4241 + [ maybe_label(label, id),
  4242 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],
  4243 + selector_c(opts, label, id, n,s,cs,sd) then
  4244 + [ maybe_label(label, id),
  4245 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],
  4246 +
  4247 + radio_button(options, label_text, id, n, v, c) then
  4248 + [ maybe_label(label_text, id),
  4249 + "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />"],
  4250 + radio_button_r(options, label_text, id, n, v, c) then
  4251 + [ "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />",
  4252 + maybe_label(label_text, id)],
  4253 + check_box(options, label_text, id, n, v, c) then
  4254 + [ maybe_label(label_text, id),
  4255 + "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />"]
  4256 + check_box_r(options, label_text, id, n, v, c) then
  4257 + [ "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />",
  4258 + maybe_label(label_text, id)]
  4259 + div(options, e) then
  4260 + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https, action_count),
  4261 + div_empty(options) then
  4262 + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https, action_count),
  4263 + hidden(id, name, value) then
  4264 + ["<input type=\"hidden\" id=\"",id,"\" name=\"",name,"\" value=\"",value,"\" />"],
  4265 +
  4266 + }.
  4267 +
  4268 +
  4269 +
  4270 +
  4271 +
  4272 +
  4273 + *** [5.9] Formating 'off form' elements.
  4274 +
  4275 + The encryption type 'multipart/form-data' is required for a form containing an upload.
  4276 +
  4277 +
  4278 +define Bool
  4279 + contains_an_upload
  4280 + (
  4281 + HTML_In_Form form_content
  4282 + ).
  4283 +
  4284 +define Bool
  4285 + contains_an_upload
  4286 + (
  4287 + HTML_Row(HTML_In_Form) row
  4288 + ) =
  4289 + mapor(contains_an_upload,
  4290 + map(content,cells(row))).
  4291 +
  4292 +define Bool
  4293 + contains_an_upload
  4294 + (
  4295 + HTML_Footer_Row(HTML_In_Form) row
  4296 + ) =
  4297 + if row is
  4298 + {
  4299 + empty then false,
  4300 + footer_row(_, cells) then
  4301 + mapor(contains_an_upload,
  4302 + map(content,cells))
  4303 + }.
  4304 +
  4305 +define Bool
  4306 + contains_an_upload
  4307 + (
  4308 + HTML_In_Form form_content
  4309 + ) =
  4310 + if form_content is
  4311 + {
  4312 + literal_pt(t) then false,
  4313 + literal(t) then false,
  4314 + sequence(l) then mapor(contains_an_upload,l)
  4315 + text(o,t) then false,
  4316 + preformated(o,s) then false,
  4317 + paragraph(o,t) then false,
  4318 + image(o,u,a) then false,
  4319 + image(o,u,a,w,h) then false,
  4320 + table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true
  4321 + else contains_an_upload(f_row),
  4322 + center(e) then contains_an_upload(e),
  4323 + mail_to(m,e) then false, // 'e' may but should not contain an upload
  4324 + scroller(w,h,cw,ch,e) then contains_an_upload(e),
  4325 + actioner(c,t,a,an,eo,ja) then false,
  4326 + foreign_link_new(_,_,_) then false,
  4327 + foreign_link(o,u) then false,
  4328 + foreign_link(o,u,n) then false,
  4329 + private_download(p,n,e,a) then false,
  4330 + text_input(o,lt,l,n,i,w) then false,
  4331 + text_input_ro(o,lt,l,n,i,w) then false,
  4332 + password_input(o,lt,l,n,i,w) then false,
  4333 + text_area(o,lt,id,n,i,w,h) then false,
  4334 + file_upload(o,l,i,n,w) then true,
  4335 + selector(o,l,i,n,s,c) then false,
  4336 + selector(o,l,i,n,s,c,p) then false,
  4337 + selector_c(o,l,i,n,s,c) then false,
  4338 + selector_c(o,l,i,n,s,c,p) then false,
  4339 + radio_button(o,_,_,n,v,c) then false,
  4340 + radio_button_r(o,_,_,n,v,c) then false,
  4341 + check_box(o,_,_,n,v,c) then false,
  4342 + check_box_r(o,_,_,n,v,c) then false,
  4343 + div(o,c) then contains_an_upload(c),
  4344 + div_empty(o) then false,
  4345 + hidden(_,_,_) then false
  4346 + }.
  4347 +
  4348 +define String
  4349 + enctype
  4350 + (
  4351 + HTML_In_Form form_content
  4352 + ) =
  4353 + if contains_an_upload(form_content)
  4354 + then " enctype=\"multipart/form-data\""
  4355 + else "".
  4356 +
  4357 +
  4358 +
  4359 +define Printable_tree
  4360 + format
  4361 + (
  4362 + CommonInfo cinfo,
  4363 + String sn, // state_name
  4364 + Var(Int) ic_v, // 'idnum' counter variable
  4365 + HTML_Off_Form element,
  4366 + Bool is_https,
  4367 + Var(Int) action_count
  4368 + ) =
  4369 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4370 + with format_element = (HTML_Off_Form e) |-> format(cinfo, sn, ic_v, e, is_https, action_count),
  4371 + if element is
  4372 + {
  4373 + literal_pt(t) then t,
  4374 + literal(t) then [t],
  4375 + sequence(l) then flat(map(format_element,l)),
  4376 + text(opts,t) then
  4377 + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https, action_count),
  4378 + preformated(o,s) then
  4379 + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https, action_count),
  4380 + paragraph(opts,t) then
  4381 + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https, action_count),
  4382 + image(opts,url,alt) then
  4383 + format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https, action_count),
  4384 + image(opts,url,alt,w,h) then
  4385 + format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https, action_count),
  4386 + table(opts,header_row, rows, footer_row) then
  4387 + format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https, action_count),
  4388 + center(e) then
  4389 + format(cinfo,sn,ic_v,any_center(e),format_element,is_https, action_count),
  4390 + mail_to(a,e) then
  4391 + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https, action_count),
  4392 + scroller(w,h,cw,ch,c) then
  4393 + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https, action_count),
  4394 + fixed_size(w,h,c) then
  4395 + format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https, action_count),
  4396 + fixed_size_2(w,h,fn) then
  4397 + format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https, action_count),
  4398 + actioner(c,t,a,an,eo,ja) then
  4399 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https, action_count),
  4400 + actioner(c,t,a,an,eo,ja,fn) then
  4401 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https, action_count),
  4402 + foreign_link_new(target, aspect, url) then
  4403 + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https, action_count),
  4404 + foreign_link(options,url) then
  4405 + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https, action_count),
  4406 + foreign_link(options,url,name) then
  4407 + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https, action_count),
  4408 + private_download(url,name,extra,action) then
  4409 + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https, action_count),
  4410 + label(n) then ["<a name=\"",n,"\">"],
  4411 + form(fn,attributs, c) then
  4412 + [
  4413 + "<form id=\"",fn,"\"",
  4414 + format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https, action_count),
  4415 + " method=\"post\"",
  4416 + enctype(c),
  4417 + " action=\"http",
  4418 + if is_https then "s" else "",
  4419 + "://",common_name,":",to_decimal(http_port),"/\">",
  4420 + // action is set dynamically by
  4421 + // the actioner using JavaScript
  4422 + if fn is htmlId(id) then
  4423 + format(cinfo,id,sn,ic_v,c,is_https, action_count),
  4424 + "</form>"
  4425 + ]
  4426 + form(fn,attributs, action_name, extra_ops, c) then
  4427 + with url = make_actioner_url(cinfo, same, same,
  4428 + sn, action_name, extra_ops, is_https),
  4429 + [
  4430 + "<form id=\"",fn,"\"",
  4431 + format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https, action_count),
  4432 + " method=\"post\"",
  4433 + enctype(c),
  4434 + " action=\"" + url + "\">",
  4435 +// " action=\"http",
  4436 +// if is_https then "s" else "",
  4437 +// "://",common_name,":",http_port,"/\">",
  4438 + // action is set dynamically by
  4439 + // the actioner using JavaScript
  4440 + if fn is htmlId(id) then
  4441 + format(cinfo,id,sn,ic_v,c,is_https, action_count),
  4442 + "</form>"
  4443 + ]
  4444 + div(options, e) then
  4445 + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https, action_count),
  4446 + div_empty(options) then
  4447 + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https, action_count),
  4448 + iframe(options, css_styles, css_files, js_files, body) then
  4449 + if body is body(body_options,element) then
  4450 + [ "<iframe", format_attrs(options), ">\n",
  4451 + "<html style=\"margin: 0pt; padding: 0pt;\">\n",
  4452 + "<head>\n",
  4453 + add_css_styles(css_styles),
  4454 + add_css_files(css_files),
  4455 + add_js_files(js_files),
  4456 + "</head>\n",
  4457 + "<body ", format(body_options), ">\n", // format body options
  4458 + format(cinfo,sn,ic_v,element,is_https, action_count),
  4459 + "</body>\n",
  4460 + "</html>\n",
  4461 + "</iframe>\n",
  4462 + ],
  4463 +
  4464 + }.
  4465 +
  4466 +
  4467 +
  4468 +
  4469 + *** [5.10] Formating meta-tags.
  4470 +
  4471 +define Printable_tree
  4472 + format_keywords
  4473 + (
  4474 + List(String) l
  4475 + ) =
  4476 + if l is
  4477 + {
  4478 + [] then [ ],
  4479 + [h . t] then if t is []
  4480 + then [h]
  4481 + else [h , ", " . format_keywords(t)]
  4482 + }.
  4483 +
  4484 +
  4485 +define Printable_tree
  4486 + format
  4487 + (
  4488 + CommonInfo cinfo,
  4489 + String state_name,
  4490 + HTML_Meta m,
  4491 + Bool is_https
  4492 + ) =
  4493 + if m is
  4494 + {
  4495 + keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],
  4496 + refresh(co,ta,an,delay) then
  4497 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",
  4498 + make_actioner_url(cinfo,co,ta,state_name,an,[],is_https),"\" />\n"],
  4499 + refresh(url,delay) then
  4500 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],
  4501 + meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],
  4502 + http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],
  4503 + generic_meta(l) then ["<meta ",
  4504 + flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],
  4505 + l)),
  4506 + " />\n"],
  4507 + literal(s) then [s]
  4508 + }.
  4509 +
  4510 +define Printable_tree // c'est le nรดtre et c'est meilleur
  4511 + format
  4512 + (
  4513 + HTML_Meta m,
  4514 + ) =
  4515 + if m is
  4516 + {
  4517 + keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],
  4518 + refresh(co,ta,an,delay) then
  4519 + ["<!-- TODO refresh(co,ta,an,delay) --> "], // TODO
  4520 + refresh(url,delay) then
  4521 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],
  4522 + meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],
  4523 + http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],
  4524 + generic_meta(l) then ["<meta ",
  4525 + flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],
  4526 + l)),
  4527 + " />\n"],
  4528 + literal(s) then [s]
  4529 + }.
  4530 +
  4531 +
  4532 +define Printable_tree
  4533 + format
  4534 + (
  4535 + CommonInfo cinfo,
  4536 + String state_name,
  4537 + List(HTML_Meta) metas,
  4538 + Bool is_https,
  4539 + String charset
  4540 + ) =
  4541 + if metas is
  4542 + {
  4543 + [] then [format(cinfo,state_name,http_equiv("content-type",
  4544 + "text/html; charset="+charset),is_https)],
  4545 + [h . t] then [format(cinfo,state_name,h,is_https)
  4546 + . format(cinfo,state_name,t,is_https,charset)]
  4547 + }.
  4548 +
  4549 +define Printable_tree
  4550 + _format_html_head
  4551 + (
  4552 + List(HTML_Head_Tag) lwf,
  4553 + Printable_tree so_far
  4554 + )
  4555 + =
  4556 + if lwf is
  4557 + {
  4558 + [] then reverse(so_far),
  4559 + [ h . t] then
  4560 + if h is
  4561 + {
  4562 + meta(meta) then
  4563 + [format(meta) . _format_html_head(t, so_far)],
  4564 + title(title) then
  4565 + ["<title>"+title+"</title>\n" . _format_html_head(t, so_far)],
  4566 + js(jsf) then
  4567 + [add_js_files([jsf]) . _format_html_head(t, so_far)],
  4568 + js_inline(jsi) then
  4569 + ["<script>"+content(jsi)+"</script>\n" . _format_html_head(t, so_far)],
  4570 + css(cssf) then
  4571 + ["<link rel=\"stylesheet\" type=\"text/css\" href=\""+file_name(cssf)+"\" />\n" . _format_html_head(t, so_far)],
  4572 + css_inline(cssi) then
  4573 + ["<style>"+cssi+"</style>\n" . _format_html_head(t, so_far)]
  4574 + }
  4575 + }
  4576 + .
  4577 +
  4578 +public define Printable_tree
  4579 + format_html_head
  4580 + (
  4581 + List(HTML_Head_Tag) lwf,
  4582 + String charset
  4583 + )
  4584 + =
  4585 + with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf],
  4586 + if lwf is
  4587 + {
  4588 + [] then
  4589 + [],
  4590 + [ h . t] then
  4591 + _format_html_head(lwf, [])
  4592 + }
  4593 + .
  4594 +
  4595 +define Printable_tree
  4596 + format
  4597 + (
  4598 + CommonInfo cinfo,
  4599 + String state_name,
  4600 + List(HTTP_header) additional_headers,
  4601 + HTTP_Answer page,
  4602 + Bool is_https,
  4603 + String charset
  4604 + ) =
  4605 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4606 + with ic_v = var((Int)0),
  4607 + if page is
  4608 + {
  4609 + html_page(status, head_tags, body) then
  4610 + if body is body(options,element) then
  4611 + if format(status) is (status_string, status_headers) then
  4612 + with answer_body =
  4613 + [doctype_w3c_header,
  4614 + html_header,
  4615 +
  4616 + "<head>\n", format_html_head(head_tags, charset),"</head>\n",
  4617 +
  4618 + "<body ", format(options), ">", // format body options
  4619 + format(cinfo,state_name,ic_v,element,is_https, var(0)),
  4620 + "</body>\n",
  4621 +
  4622 + "</html>"],
  4623 + [ "HTTP/1.1 " + status_string, crlf,
  4624 + format_headers(standard_headers),
  4625 + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),
  4626 + format_headers(status_headers),
  4627 + format_headers(additional_headers),
  4628 + crlf
  4629 + . answer_body
  4630 + ]
  4631 +
  4632 + html_page(status, title, metas, css_styles, css_files, js_files, script, body) then
  4633 + if body is body(options,element) then
  4634 + if format(status) is (status_string, status_headers) then
  4635 + with answer_body =
  4636 + [ doctype_w3c_header,
  4637 + html_header,
  4638 + "<head>\n",
  4639 + add_css_styles(css_styles),
  4640 + add_css_files(css_files),
  4641 + add_js_files(js_files),
  4642 + add_script(script),
  4643 + "<link rel=\"shortcut icon\" href=\"favicon.ico\" />\n",
  4644 + "<script type = \"text/javascript\" language=\"JavaScript\">",
  4645 + " function show_local_popup(divname,stvname) {",
  4646 + " if (document.layers) { var d = eval(document.divname); } else\n",
  4647 + " if (document.getElementById) { var d = eval(\"document.getElementById(divname)\"); } else\n",
  4648 + " if (document.all) { var d = eval(document.all.divname.style)};\n",
  4649 + // " alert(typeof(eval(stvname))); ",
  4650 + " var s = eval(stvname); ",
  4651 + " if (s[0]==0) ",
  4652 + " { s[0]=1; d.style.visibility = 'visible'; d.zIndex = 100; } else\n",
  4653 + " { s[0]=0; d.style.visibility = 'hidden'; }; }",
  4654 + "</script>\n",
  4655 + "<title>",title,"</title>\n", // put title
  4656 + format(cinfo,state_name,metas,is_https,charset), // format the metas
  4657 + "</head>\n",
  4658 + "<body ", format(options), ">", // format body options
  4659 + //"<center>",
  4660 + format(cinfo,state_name,ic_v,element,is_https, var(0)),
  4661 + //"</center>",
  4662 + "</body>\n",
  4663 + "</html>"
  4664 + ],
  4665 + [ "HTTP/1.1 " + status_string, crlf,
  4666 + format_headers(standard_headers),
  4667 + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),
  4668 + format_headers(status_headers),
  4669 + format_headers(additional_headers),
  4670 + crlf
  4671 + . answer_body
  4672 + ],
  4673 +
  4674 + plain_text (HTTP_Status status, String text) then
  4675 + if format(status) is (status_string, status_headers) then
  4676 + [ "HTTP/1.1 " + status_string, crlf,
  4677 + format_headers(standard_headers),
  4678 + format_headers(standard_headers_for("text/plain", length(text), success(charset))),
  4679 + format_headers(status_headers),
  4680 + format_headers(additional_headers),
  4681 + crlf,
  4682 + text . (Printable_tree)[]
  4683 + ],
  4684 +
  4685 + custom_text(HTTP_Status status, String mime_type, String content) then
  4686 + if format(status) is (status_string, status_headers) then
  4687 + [ "HTTP/1.1 " + status_string, crlf,
  4688 + format_headers(standard_headers),
  4689 + format_headers(standard_headers_for(mime_type, length(content), success(charset))),
  4690 + format_headers(status_headers),
  4691 + format_headers(additional_headers),
  4692 + crlf,
  4693 + content . (Printable_tree)[]
  4694 + ],
  4695 + custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then
  4696 + if format(status) is (status_string, status_headers) then
  4697 + [ "HTTP/1.1 " + status_string, crlf,
  4698 + format_headers(status_headers),
  4699 + format_headers(standard_headers_for(mime_type, length(content), failure)),
  4700 + format_headers(status_headers),
  4701 + format_headers(other_headers),
  4702 + format_headers(additional_headers),
  4703 + crlf,
  4704 + content . (Printable_tree)[]
  4705 + ],
  4706 +
  4707 + custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then
  4708 + if format(status) is (status_string, status_headers) then
  4709 + [ "HTTP/1.1 " + status_string, crlf,
  4710 + format_headers(standard_headers),
  4711 + format_headers(standard_headers_for(mime_type, length(content), success(charset))),
  4712 + format_headers(status_headers),
  4713 + format_headers(additional_headers),
  4714 + crlf .
  4715 + content
  4716 + ],
  4717 +
  4718 + http_raw(Printable_tree content) then content,
  4719 +
  4720 + html_content(HTTP_Status status, HTML_Off_Form content_HTML) then
  4721 + if format(status) is (status_string, status_headers) then
  4722 + with content = format(cinfo, state_name, ic_v, content_HTML, is_https, var(0)),
  4723 + [ "HTTP/1.1 " + status_string, crlf,
  4724 + format_headers(standard_headers),
  4725 + format_headers(standard_headers_for("text/html", length(content), success(charset))),
  4726 + format_headers(status_headers),
  4727 + format_headers(additional_headers),
  4728 + crlf .
  4729 + content
  4730 + ],
  4731 + }.
  4732 +