site.cd 12.8 KB
Newer Older
1
2
(* This CDuce script produces CDuce web site. *)

3
4
(** Command line **)

5
let input =
6
  match argv with
7
  | [ s ] -> s
8
  | _ -> raise "Please use --arg to specify an input file on the command line"
9

10
(** Output types **)
11

12
using H = "xhtml"
13

14
15
(** Input types **)

16
type Page =  <page name=String new=?Any>[ <title>String <banner>[InlineText*]? Item* ]
17
type External = <external {|href=String; title=String; name=String |}>[]
18
19

type Item = 
20
   <box noindex=?String title=String link=String>Content
21
22
23
 | <meta>Content
 | <left>Content
 | Page
24
 | External
25

26
type Author = <author>String
27
type Paper = 
28
  <paper file=?String old=?String>[ 
29
     <title>String Author+ <comment>[InlineText*] <abstract>Content ]
30
31

type Slides = 
32
  <slides file=String>[ <title>String Author+ <comment>[InlineText*] ]
33
34

type Link =
35
  <link url=String title=String>[ InlineText* ]
36
37

type Content =      
38
   [ ( <p {|style=?String|}>[InlineText*]
39
40
     | <ul {||}>[<li {||}>Content +]
     | <section title=String>Content
41
     | <sample highlight=?"true"|"false">String
42
     | <xmlsample highlight=?"true"|"false">String
43
     | H:Xtable
44
     | Paper | Slides | Link
45
46
     | <boxes-toc sections=?"">[]    (* the presence optional "section" attr produces  *)
     | <pages-toc sections=?"">[]    (* a two-level depth toc to include also sections *) 
47
48
     | <site-toc>[]
     | <local-links href=String>[]
49
     | <two-columns>[ <left>Content <right>Content ]
50
     | <note> Content 
51
     | InlineText
52
     )* ]
53
54
55

type InlineText =
     Char
56
   | <(`b|`i|`tt|`em) {| style=?String |}>[InlineText*]
57
   | <code>String
58
   | <local href=String>String
59
   | <footnote>[InlineText*]
60
   | H:Xa | H:Ximg | H:Xbr 
61

62
63
64
65
(** Generic purpose functions **)

(* Recursive inclusion of XML files and verbatim text files *)

66
let load_include (String -> [Any*])
67
 name ->
68
(*   let _ = print [ 'Loading ' !name '... \n' ] in *)
69
   xtransform [ (load_xml name) ] with 
70
   | <include file=(s & String)>[] -> load_include s
71
   | <include-verbatim file=(s & String)>[] -> load_file s 
72

73
(* Highlighting text between {{...}} *)
74

75
let highlight (String -> [ (Char | H:Xvar | H:Xi)* ] )
76
77
 | [ '{{' h ::(Char *?) '}}' ; rest ] -> 
          [ <var class="highlight">h; highlight rest ]
78
 | [ '%%' h ::(Char *?) '%%' ; rest ] ->
79
          [ <i>h; highlight rest ] 
80
 | [ c; rest ] -> [ c; highlight rest ]
81
 | [] -> []
82

83
84
(* Split a comma-separated string *)

85
let split_comma (String -> [String*])
86
 | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest)
87
 | s -> [ s ]
88
89


90
(** Internal types **)
91

92
type Path = [ { url = String; title = String }* ]
93
type Tree = { name = String; url = String; title = String; 
94
              children = [Tree*] } 
95

96
let url_of_name (String -> String)
97
   "index" -> "/"
98
 | s -> s @ ".html"
99

100
let authors ([Author+] -> String)
101
102
   | [ <author>a ] -> a
   | [ <author>a1 <author>a2 ] -> a1 @ ", and " @ a2
103
   | [ <author>a; rem ] -> a @ ", " @ authors rem
104

105
let find_local_link (sitemap : [Tree*], l : String) : Tree =
106
107
match sitemap with
 | (h,t) ->
108
   if (h . name = l) then h
109
110
111
   else 
    (try find_local_link (t,l) with `Not_found -> 
         find_local_link (h . children,l))
112
 | [] -> raise `Not_found
113

114
let local_link (sitemap : Tree, l : String, txt : String) : H:Inline =
115
116
117
118
 try 
  let h = find_local_link ([sitemap],l)  in
  let txt = if txt = "" then h . title else txt in
  <a href=(h . url)>txt
119
 with `Not_found -> raise [ 'Local link not found: ' !l ]
120
 
121
let compute_sitemap ((Page|External) -> Tree)
122
123
 <page name=name>[ <title>title (c::(Page|External) | _)* ] ->
   let children = map c with p -> compute_sitemap p in
124
   { name = name; url = (url_of_name name); title = title; children =children }
125
|<external name=name href=h title=t>[] ->
126
   { name = name; url = h; title = t; children = [] }
127

128
let display_sitemap (h : Tree) :  H:Xli =
129
130
  let ch = map h . children with x -> display_sitemap x in
  let ch = match ch with [] -> [] | l -> [ <ul>l ] in
131
  <li>[ <a href=(h . url)>(h . title); ch ]
132

133

134
let boxes_of  (Page -> [H:Xul?])
135
     <page name=n>[ (items::Item | _)*] ->
136
137
        let toc = 
         transform items with 
138
139
          | <box noindex=_>_ -> []
          | <box title=t link=l>_ -> [ <li>[ <a href=((url_of_name n)@('#',l))>t ] ] in
140
141
        (match toc with [] -> [] | lis -> [ <ul>lis ])
 
142
let link_to (Page -> H:Xa)
143
144
145
 <page name=n new=_>[<title>t ; _ ] -> 
               <a href=(url_of_name n)>[!t 
                      <img src="img/new.gif" alt="(new)" style="border:0">[]]
146
| <page name=n>[<title>t ; _ ] -> <a href=(url_of_name n)>t
147

148
let box (x : H:Flow) : H:Block =
149
 <table cellpadding="2" 
150
151
    style="font-size:11px ; font-family:arial,sans-serif;
           border: solid 2px black; background: #ffffff" width="100%">
152
153
   [ <tr> [<td>x] ]

154
let meta (x : H:Flow) : H:Block =
155
 <table cellpadding="2" 
156
    style="border: solid 1px #b0b0b0; background: #e0e0e0; font-size: 80%"  
157
158
159
    width="100%">
   [ <tr> [<td>x] ]

160
let box_title (x : H:Flow, t : String) : H:Block =
161
162
163
164
165
166
167
168
169
170
171
 <table cellpadding="5" 
    style="border: solid 2px black; background: #ffffff" width="100%">
   [ <tr>[ <td style="background: #fff0f0; color: #0000ff; font: bold
100% helvetica">t ] <tr> [<td>x] ]

let style = "
a:link:hover, a:visited:hover {
  text-decoration: none;
  background: #FFFFD0;
  color: #FF0000;
}
172
173
174
a.old, a.old:hover, a.old:visited:hover {
  text-decoration: line-through;
}
175
176
177
178
179
180
181
182
p {
  text-align: justify;
  margin: 1ex 1em 0 1em;
}
pre {
  margin: 1ex 1em 0 1em;
}
var.highlight {
183
  font: roman; 
184
185
186
187
188
189
190
191
192
193
  color: #FF0000;
}
img.icon {
  border: 0;
}
div.code {
  background: #E0E0E0;
  margin: 0.5ex 0.5em 0 0.5em;
  padding: 0.2ex;
}
194

195
196
197
198
199
div.xmlcode {
  background: #ebefa2;
  margin: 0.5ex 0.5em 0 0.5em;
  padding: 0.2ex;
}
200

201
div.abstract { 
202
  font: bold helvetica;
203
204
205
206
  margin: 1ex 1em 1ex 1em;
  padding: 1ex 1em 1ex 1em;
  background: #F0F0F0;
}
207
208

div.note { 
209
  text-align: justify;
210
211
212
213
214
215
216
  font: bold helvetica;
  margin: 1ex 3em 1ex 3em;
  padding: 1ex 1em 1ex 1em;
  background: #D0E2D2;
}


217
div.abstract p { 
218
  font: sans-serif;
219
220
221
}
"

222
223
(* Main transformation function *)

224
(* returns the last page of the descendance *)
225
let gen_page (prev : Page|[], page : Page, next : Page|[], 
226
                  path : Path, sitemap : Tree) : (Page|[]) = 
227
match page with
228
229
<page name=name>[ 
        <title>title <banner>banner | <title>(title & banner); items ] ->
230

231
 let footnote_counter = ref Int 0 in 
232
 let footnotes = ref H:Flow [] in
233

234
 let text (t : [InlineText*]) : H:Inlines =
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  transform t with
   | <code>x -> [ <b>[ <tt>(highlight x) ] ]
   | <local href=l>txt -> [ (local_link (sitemap,l,txt)) ]
   | <(tag & (`b|`i|`tt|`em)) (attr)>x -> [ <(tag) (attr)>(text x) ]
(*   | <a href=url>_ & z -> let [] = print [ 'Link: ' !url '\n'] in [z] *)
   | <footnote>c -> 
      footnote_counter := !footnote_counter + 1;
      let n = string_of !footnote_counter in
      let fn = !footnotes in
      footnotes := [];
      let c = <p>[ <a name=[ 'note' !n ]>[] 
                   <a href=[ '#bnote' !n ]>[ '[' !n ']' ]
		   ' ' ; text c ] in
      footnotes := fn @ [ c ] @ !footnotes;
      [ <a name=[ 'bnote' !n ]>[]
        <a href=[ '#note' !n ]>[ '[' !n ']' ] ]
251
   | z -> [ z ] 
252
 in
253

254
 let content (t : Content) : H:Flow =
255
  transform t with
256
   | <section title=title>c -> 
257
         [ <p>[ <b style="color: #008000">title ] !(content c) ]
258
   | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab  ]  ->
259
260
261
262
         [ (match r with
           | { file = f; old = "true" } -> <a class="old" href=f>tit
           | { file = f } -> <a href=f>tit
           | _ -> <b>tit) '. '
263
           !(authors aut) '. '
264
	   !(text com)
265
266
267
           <div class="abstract">[ 'Abstract:' !(content ab) ]
         ]
   | <slides file=f>[ <title>tit aut::Author* <comment>com ]  ->
268
        [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ]
269
270
   | <sample highlight="false">s ->
        [ <div class="code">[ <pre>s ] ]
271
   | <sample>s ->
272
        [ <div class="code">[ <pre>(highlight s) ] ]
273
274
275
276
   | <xmlsample highlight="false">s ->
        [ <div class="xmlcode">[ <pre>s ] ]
   | <xmlsample>s ->
        [ <div class="xmlcode">[ <pre>(highlight s) ] ]
277
   | <link url=url title=title>com -> 
278
279
280
        [ <a href=url>title '. ' !(text com) ]
   | <ul>lis -> 
        [ <ul>(map lis with <li>x -> <li>(content x)) ]
281
   | H:Xtable & x -> 
282
        [ x ]
283
   | <p (attr)>x -> [ <p (attr)>(text x) ]
284
285
   | <pages-toc (a)>[] ->
       let toc = 
286
         transform items with 
287
288
         | Page & p ->  [ <li>[ (link_to p) 
                           !(match a with {|sections=_|} -> (boxes_of p) | _ -> [])] ]
289
         | <external href=l title=t>[] -> [ <li>[ <a href=l>t ] ] in
290
        (match toc with [] -> [] | lis -> [ <ul>lis ])
291
   | <boxes-toc (a)>[] ->
292
293
        let toc = 
         transform items with 
294
295
	 | <box noindex=_>_ -> []
         | <box title=t link=l>b -> [ <li>[ <a href=('#',l)>t 
296
297
298
299
300
             !(match a with 
                | {|sections=_|} -> 
                     (transform b with <section title=t>_ -> [<br>[] '-' !t])
                | _ ->[])]]
        in (match toc with [] -> [] | lis -> [ <ul>lis ])
301
302
303
304
305
   | <site-toc>[] ->
        [ <ul>[ (display_sitemap sitemap) ] ]
   | <local-links href=s>[] ->
         (match (split_comma s) with
           | [] -> []
306
           | l -> let l = map l with x -> <li>[ (local_link(sitemap,x,"")) ]
307
                  in [ <ul>l ])
308
309
310
311
312
   | <two-columns>[ <left>x <right>y ] ->
	[ <table width="100%">[ 
            <tr>[ 
              <td valign="top">(content x) 
              <td valign="top">(content y) ] ] ]
313
   | <note>  c   ->  [ <div class="note">[ <b>"Note:  " !(content c) ]]
314
315
   | t -> text [ t ]
 in
316

317
(* Preparing left panel *)
318

319
320
321
322
 let navig = transform items with <left>c -> [ c ] in
 let left = match navig with [] -> [ [<boxes-toc>[]] ] | n -> n in
 let left = 
   <td valign="top" align="left">[
323
     <table cellpadding="0" cellspacing="15" 
324
325
            width="200"
            style="font-size:80%; border: 1px dashed black;
326
                   background: #ffcd72">	(* altbg 9aa8ba *)
327
328
     (map left with x -> <tr>[ <td>[ (box (content x)) ] ]) ] in

329
 let dpath : H:Inlines = transform path with 
330
  | { url = f; title = t } -> [ <a href=f>t ': '] 
331
 in
332
 let npath = path @ [ { url = (url_of_name name); title = title } ] in
333
 let subpages = transform items with p & Page -> [ p ] in
334
 let (next,last) = gen_page_seq (page, subpages, next, npath, sitemap) in
335
336
337
 let next = match next with [] -> [] 
   | <page name=n>[ <title>t; _ ] -> 
      [ <a href=(url_of_name n)>[ 
338
          <img width="16" height="16" class="icon" alt="Next page:"
339
               src="img/right.gif">[]
340
341
342
343
344
          ' ' !t
        ] ] in
 let prev = match prev with [] -> [] 
   | <page name=n>[ <title>t; _ ] -> 
      [ <a href=(url_of_name n)>[ 
345
          <img width="16" height="16" class="icon"
346
               alt="Previous page:" src="img/left.gif">[]
347
348
          ' ' !t
        ] ] in
349
 let navig = 
350
   if prev = [] then [] else
351
   [ (box [
352
     <p>[ !dpath !title ]
353
354
355
356
357
358
359
360
361
362
363
     <p>[ !prev ' ' !next ] ]) ] in

(* Preparing main panel *)
 let main = transform items with
  | <box (r)>c ->
      let b = [
         <a name=(r . link)>[] 
         !(content c) ] in
      [ (box_title (b,r . title)) ]
 | <meta>c -> [ (meta (content c)) ]
 in
364
365
366
367
 let notes = match !footnotes with
   | [] -> []
   | n -> [ (meta n) ] in
 let main = match (navig @ main @ notes @ navig) with
368
369
370
   | [] -> raise "Empty page !"
   | x -> x in

371
 let right : H:Xtd =
372
373
374
375
376
377
378
379
380
381
  <td valign="top" align="left" style="width:100%">[
   <table width="100%">[
    <tr>[ <td valign="top" align="left"
              style="border: 2px solid black; background: #ffffff;
text-align:center; color: #aa0000; font: bold 200% helvetica" >
          (text banner)
        ]
 
    <tr>[
      <td valign="top" align="left"
382
          style="border: 1px solid black; background: #fccead">[ (* altbg c8ccd1 *)
383
       <table width="100%" cellpadding="0" cellspacing="17">
384
385
386
387
         (map main with x -> <tr>[ <td>[x] ])
      ] ]
  ] ] in

388
 let html : H:Xhtml =
389
390
 <html>[
  <head>[ 
391
   <title>[ 'CDuce: ' !title ]
392
   <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">[]
393
   <style type="text/css">style
394
  ]
395
  <body style="margin: 0; padding : 0; background: #fcb333">[  (* altbg  4e6e99 *)
396
397
398
   <table cellspacing="10" cellpadding="0" width="100%" border="0">[
    <tr>[ left right ]
   ]
399
  ]
400
401
 ]
 in
402
 let txt : Latin1 = 
403
   [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
404
     '  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
405
406
     !(print_xml html) ] in
 let fn = "www/" @ name @ ".html" in
407
 dump_to_file fn txt;
408
 last
409
	
410

411
let gen_page_seq 
412
 (prev : Page|[], pages : [Page*], next : Page|[], 
413
  path : Path, sitemap : Tree) : (Page|[], Page|[]) =
414
415
 match pages with
 | [ p1 p2 ; _ ] & [ _; rest ] -> 
416
417
418
     let last = gen_page (prev,p1,p2, path, sitemap) in
     let (_,last)  = gen_page_seq (last, rest, next, path, sitemap) in 
     (p1,last)
419
 | [ p ] ->
420
     let last = gen_page (prev,p,next, path, sitemap) in (p,last)
421
 | [] -> (next,prev)
422

423

424
;;
425

426
match load_include input with
427
 | [ Page & p ] -> let _ = gen_page ([],p,[], [], compute_sitemap p) in []
428
 | _ -> raise ("Invalid input document " @ input)
429

430