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

3 4 5 6
(* The types *)

include "siteTypes.cd";;

7 8
(** Command line **)

9
let (input,outdir) =
10
  match argv [] with
11
  | [ s ("-o" o | /(o := "www")) ] -> (s,o)
12
  | _ -> raise "Please use --arg to specify an input file on the command line"
13

14 15 16 17
(** Generic purpose functions **)

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

18
let load_include (Latin1 -> [Any*])
19
 name ->
20
(*   let _ = print [ 'Loading ' !name '... \n' ] in  *)
21
   xtransform [ (load_xml name) ] with 
22 23
   | <include file=(s & Latin1)>[] -> load_include s
   | <include-verbatim file=(s & Latin1)>[] -> load_file s 
24 25 26 27
   | <include-forest file=(s & Latin1)>[] -> 
         match load_xml ("string:<fake>"@(load_file s)@"</fake>") with
            <fake> x -> x | _ -> raise "Uhh?"

28

29 30
(* Loading *)

31 32 33
let [<site>[ <title>site 
             (<header>header | /(header:=[])) 
             (<footer>footer | /(footer:=[])) 
34
             extra_head::H.script*
35
             main_page ] ] = 
36 37 38
(* match load_include input with
   [ Site ] & x -> x
 | _ -> exit 2 *)
39
 try (load_include input :? [ Site ])
40
 with err & Latin1 -> 
41
   print ['Invalid input document:\n' !err '\n']; 
42
   exit 2
43

44
(* Highlighting text between {{...}} *)
45

46
let highlight (String -> [ (Char | H.strong | H.i)* ] )
47
 | [ '{{ON}}'; rest ] -> xhighlight rest
48 49
 | [ '{{%%' h ::(Char *?) '%%}}' ; rest ] -> 
          [ <strong class="highlight">[<i>h]; highlight rest ]
50
 | [ '{{' h ::(Char *?) '}}' ; rest ] -> 
51
          [ <strong class="highlight">h; highlight rest ]
52 53 54 55
 | [ '$$%%' h ::(Char *?) '%%$$' ; rest ] -> 
          [ <strong class="ocaml">[<i>h]; highlight rest ]
 | [ '$$' h ::(Char *?) '$$' ; rest ] -> 
          [ <strong class="ocaml">h; highlight rest ]
56
 | [ '%%' h ::(Char *?) '%%' ; rest ] ->
57
          [ <i>h; highlight rest ] 
58
 | [ c; rest ] -> [ c; highlight rest ]
59
 | [] -> []
60

61 62 63 64 65 66 67
let xhighlight (String -> [ (Char | H.strong | H.i)* ] )
 | [ x::('}}' | ':}' | '{{' | '{:') h::Char*? 
     y::('}}' | ':}' | '{:' | '{{'); rest ] -> 
          [ !x <strong class="highlight">h !y; xhighlight rest ]
 | [ c; rest ] -> [ c; xhighlight rest ]
 | [] -> []

68 69
(* Split a comma-separated string *)

70
let split_comma (String -> [String*])
71
 | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest)
72
 | s -> [ s ]
73

74 75 76 77 78 79 80 81
type wschar = ' ' | '\n' | '\t' | '\r'

let split_thumbnails (String -> [(String,String)*])
 | [ wschar* x::(Char\wschar\':')+ ':' y::_*? '.'; rest ] -> 
        ((x,y), split_thumbnails rest)
 | [ wschar* x::(Char\wschar)+; rest ] -> 
        ((x,""), split_thumbnails rest)
 | [ wschar* ] -> []
82

83
(** Internal types **)
84

85 86 87
type Path = [ { url=String title=String }* ]
type Tree = { name=String url=String title=String
              children=[Tree*] boxes=[H.ul?] } 
88

89
let url_of_page (Page -> String)
90 91
 | <page url=u ..>_ -> u
 | <page name=n ..>_ -> n @ ".html"
92

93 94 95 96
let render(a : String)(p : {presenter=?"yes"|"no" ..}) : H.Flow =
 match p with
 | {presenter="yes" ..} -> [<strong class="ocaml">a] 
 | _ -> a
97

98
let authors ([Author+] -> H.Flow)
99
 | [ <author (p)>a ] -> render a p
100 101
 | [ <author (p1)>a1 <author (p2)>a2 ] -> 
     (render a1 p1) @ ", and " @ (render a2 p2)
102
 | [ <author (p)>a; rem ] -> (render a p)@ ", " @ authors rem
103

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

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

129
let ul([H.li*] -> [H.ul?]) [] -> [] | l -> [ <ul>l ]
130

131 132 133
let ol(([H.li*],{style=?String}) -> [H.ol?]) 
 | ([],_) -> [] 
 | (l,s) -> [ <ol (s)>l ] 
134

135
let display_sitemap (h : Tree) :  H.li =
136
  let ch = map h . children with x -> display_sitemap x in
137
  <li>[ <a href=(h . url)>[ '[' !(h . title) ']' ] !(h . boxes); (ul ch) ]
138

139

140 141
let boxes_of (Page -> [H.ul?])
<page ..>[ (items::Item | _)*] & p ->
142
 let toc = transform items with 
143 144
 | <box title=t link=l ..>_ -> 
     [ <li>[ <a href=[ !(url_of_page p) '#' !l ]>t ] ] 
145 146 147
 in
 ul toc

148 149 150
let link_to (<page (r)>[<title>t _* ] & p : Page) : H.a =
 let t = match r with
 | {new="" ..} -> t @ [ <img src="img/new.gif" alt="(new)" style="border:0">[]]
151
 | _ -> t in
152
 <a href=(url_of_page p)>t
153

154 155
let small_box (x : H.Flow) : H.Block = <div class="smallbox">x
let meta (x : H.Flow) : H.Block = <div class="meta">x
156
let box_title (x : H.Flow, a : String, t : String) : H.Block =
157 158
   <div>[ <h2>[<a name=a>t ] !x ]
let box (x : H.Flow) : H.Block = <div>[ !x ]
159

160 161
type PageO = Page | []

162

163
let button(title : String)(onclick : String) : H.Inline =
164 165
  <input type="submit" style="font-size:8px;" value=title onclick=onclick>[] 
let button_id(id : String)(title : String)(onclick : String)(style : String) 
166
: H.Inline =
167 168 169
  <input type="submit" id=id 
   style=("font-size:8px;"@style) value=title 
   onclick=onclick>[] 
170

171
let demo(no : Int)(name : String)(prefix : String)(txt : String) : H.Flow = 
172 173
 let n = [ 'a' !name '_' ] in
 let prefix = if prefix = "" then "" else [ 'a' !prefix '_' ] in
174
 [ !(if (no = 1) then [<script src="demo.js" type="text/javascript">" "]
175 176 177 178
     else [])
  <table style="width:100%">[
   <tr>[ 
    <td style="width:50%">[
179
     (button_id (n@"btn") "Edit" ("editable('"@n@"','');") "")
180
     (button "Evaluate" ("submit('"@n@"');"))
181
     (button "Default" ("defreq('"@n@"');"))
182 183
     (button_id (n@"btnclear") "Clear" ("clearreq('"@n@"');") 
              "visibility:hidden;")
184 185
    ]
    <td style="width:50%">[
186
     <input id=(n@"def") type="hidden" value=txt>[]
187
     <input id=(n@"prefix") type="hidden" value=prefix>[]
188
     (button "Clear" ("clearres('"@n@"');"))
189 190
    ] ]
   <tr>[
191
    <td valign="top">[ 
192 193
     <div id=(n@"container")>[
      <pre id=(n@"req")>txt
194 195 196
      <textarea id=(n@"edit") cols="50" rows="25" 
    style="display:none;border:1px solid #CCCCCC; background-color:#F0F0F0;">
          txt 
197 198
     ]
    ]
199 200
    <td valign="top">[ <div id=(n@"res")>[] ] ] ] 
  ]
201

202 203
(* Main transformation function *)

204
(* returns the last page of the descendance *)
205 206

let thumbnail(w : String, h : String)
207
 (url : String)(title : String) : H.Inlines =
208 209 210
 [ <a href=url>[ 
   <img src=url width=w height=h alt="Click to enlarge" title=title>[] ] ]

211
let thumbwh({ width=?IntStr height=?IntStr ..} -> 
212
   (String -> String ->H.Inlines))
213 214 215 216 217 218 219
  | { width = w; height = h } ->
      let w = int_of w in let h = int_of h in
      (match h with
       | 0 -> raise "Thumbnail height = 0"
       | h -> let w = string_of ((w * 200) div h) in thumbnail (w,"200"))
  | _ -> thumbnail ("266","200")

220 221
let gen_page (site : String,
              prev : PageO, page : Page, next : PageO, 
222 223
              path : Path, sitemap : Tree) : PageO = 
match page with 
224
<page name=name leftbar="false"&(leftbar:=`false) else (leftbar:=`true) ..>[ 
225 226
 (<title>title <banner>banner | <title>(title & banner)) 
 items::_* ] ->
227
 let items = header @ items @ footer in
228

229
 let footnote_counter = ref Int 0 in 
230
 let footnotes = ref H.Flow [] in
231
 let demo_no = ref Int 0 in
232
 let last_demo = ref String "" in
233

234
 let text (t : [InlineText*]) : H.Inlines =
235 236
  transform t with
   | <code>x -> [ <b>[ <tt>(highlight x) ] ]
237
   | <local href=l>txt -> local_link (sitemap,l,txt)
238
   | <(tag & (`b|`i|`tt|`em)) (attr)>x -> [ <(tag) (attr)>(text x) ]
239
   | <footnote nocount="true">_ -> 
240 241 242 243
      let n = string_of !footnote_counter in
      [ <a name=[ 'bnote' !n ]>[]
        <a href=[ '#note' !n ]>[ '[' !n ']' ] ]

244 245 246 247 248 249 250 251 252 253 254
   | <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 ']' ] ]
255
   | <thumbnail ({href=url ..} & r)>[] ->
256
      thumbwh r url ""
257
   | <thumbnails ({href=url ..} & r)>l ->
258 259 260 261 262 263 264
      let l = split_thumbnails l in
      let f = thumbwh r in
      let c = ref Int 0 in
      (transform l with (x,y) -> 
          let t = f (url @ x) y in
          if (!c = 4) then (c := 1; [ <br>[] ] @ t)
          else (c := !c + 1; t))
265
   | z -> [ z ] 
266
 in
267

268
 let content (t : Content) : H.Flow =
269
  transform t with
270
   | <section title=title>c -> 
271
         [ <h3>title !(content c) ]
272
   | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab  ] ->
273
         [ (match r with
274
           | { file = f; old = "" } -> <a class="old" href=f>tit
275 276
           | { file = f } -> <a href=f>tit
           | _ -> <b>tit) '. '
277
           !(authors aut) '. '
278
	   !(text com)
279 280 281
           <div class="abstract">[ 'Abstract:' !(content ab) ]
         ]
   | <slides file=f>[ <title>tit aut::Author* <comment>com ]  ->
282
        [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ]
283 284
   | <sample highlight="false">s ->
        [ <div class="code">[ <pre>s ] ]
285
   | <sample ..>s ->
286
        [ <div class="code">[ <pre>(highlight s) ] ]
287 288
   | <xmlsample highlight="false">s ->
        [ <div class="xmlcode">[ <pre>s ] ]
289
   | <xmlsample ..>s ->
290
        [ <div class="xmlcode">[ <pre>(highlight s) ] ]
291 292
   | <sessionsample highlight="false">s ->
        [ <div class="session">[ <pre>s ] ]
293
   | <sessionsample ..>s ->
294
        [ <div class="session">[ <pre>(highlight s) ] ]
295
   | <link url=url title=title>com -> 
296
        [ <ul>[ <li>[ <a href=url>title '. ' !(text com) ] ] ]
297
   | <ul>lis -> 
298
        ul (map lis with <li>x -> <li>(content x))
299 300
   | <ol (attr) >lis -> 
        ol ((map lis with <li>x -> <li>(content x) ),(attr))
301
   | H.table & x -> 
302
       [ <table width="100%">[<tr>[<td align="center">[x]]] ]
303
   | <p (attr)>x -> [ <p (attr)>(text x) ]
304
   | <pages-toc (a)>[] ->
305 306
      let toc = transform items with 
      | Page & p -> 
307
        let sects = match a with {sections=_ ..} -> boxes_of p | _ -> [] in
308
        [ <li>[ (link_to p) ; sects ] ]
309
      | <external href title=t ..>[] -> [ <li>[ <a href>t ] ] in
310
      ul toc
311
   | <boxes-toc (a)>[] ->
312 313
      let sections = match a with { sections=_ ..} -> `true | _ -> `false in
      let short = match a with { short=_ ..} -> `true | _ -> `false in
314
      let toc = transform items with 
315
      | <box ({title=t link=l ..} & ({short=s ..} | {title=s ..}))>b ->
316 317 318
        let t = if short then s else t in
        let sects = 
         if sections then
319
          (transform b with <section title=t>_ -> [<br>[] '-' !t])
320
         else [] in
321 322
        [ <li>[ <a href=('#',l)>t !sects ]] in
      ul toc
323 324 325
   | <site-toc>[] ->
        [ <ul>[ (display_sitemap sitemap) ] ]
   | <local-links href=s>[] ->
326 327
        ul (transform (split_comma s) with x -> 
             match local_link(sitemap,x,"") with [] -> [] | x -> [<li>x])
328 329 330 331 332
   | <two-columns>[ <left>x <right>y ] ->
	[ <table width="100%">[ 
            <tr>[ 
              <td valign="top">(content x) 
              <td valign="top">(content y) ] ] ]
333
   | <note title=t>c ->  [ <div class="note">[ <b>[!t ':  '] !(content c) ]]
334 335 336 337 338
   | <note>c ->  [ <div class="note">[ <b>"Note:  " !(content c) ]]
   | <footnotes>[] -> 
       (match !footnotes with 
        | [] -> [] 
        | n -> footnotes := []; [ <br>[] (meta n) ] )
339
   | <xhtml>i -> i
340 341
   | <demo (r)>s -> 
       demo_no := !demo_no + 1; 
342 343
       let name = match r with { label .. } -> label | _ -> 
                     string_of !demo_no in
344
       let prefix = 
345 346
           match r with { prefix = "last" .. } -> !last_demo 
                      | { prefix .. } -> prefix
347 348 349
                      | _ -> "" in
       last_demo := name;
       demo !demo_no name prefix s
350 351
   | t -> text [ t ]
 in
352

353
(* Preparing left panel *)
354

355
 let left =
356 357 358 359
  if leftbar then
  let navig = transform items with <left>c -> [ c ] in
  let left = match navig with [] -> [ [<boxes-toc>[]] ] | n -> n in
  [
360
  
361 362 363 364
   <td valign="top" align="left" style="width:20%;">[
     <div class="leftbar" id="leftbar">
       (map left with x -> small_box (content x)) ]
 ]
365
 else [] in
366

367
 let dpath : H.Inlines = transform path with 
368
  | { url = f title = t } -> [ <a href=f>t ': '] 
369
 in
370
 let npath = path @ [ { url = (url_of_page page); title = title } ] in
371
 let subpages = transform items with p & Page -> [ p ] in
372
 let (next,last) = gen_page_seq (site,page, subpages, next, npath, sitemap) in
373
 let next = match next with [] -> [] 
374
   | <page ..>[ <title>t; _ ] & p -> 
375
      [ <a href=(url_of_page p)>[ 
376
          <img width="16" height="16" class="icon" alt="Next page:"
377
               src="img/right.gif">[]
378 379 380
          ' ' !t
        ] ] in
 let prev = match prev with [] -> [] 
381
   | <page ..>[ <title>t; _ ] & p -> 
382
      [ <a href=(url_of_page p)>[ 
383
          <img width="16" height="16" class="icon"
384
               alt="Previous page:" src="img/left.gif">[]
385 386
          ' ' !t
        ] ] in
387
 let navig = 
388
   if prev = [] then [] else
389
   [ (small_box [
390
     <p>[ !dpath !title ]
391 392 393 394
     <p>[ !prev ' ' !next ] ]) ] in

(* Preparing main panel *)
 let main = transform items with
395
   | <box title=t link=l ..>c -> [ (box_title (content c, l, t)) ]
396
   | <box>c -> [ (box (content c)) ]
397 398 399 400
   | <footnotes>[] -> 
       (match !footnotes with 
        | [] -> [] 
        | n -> footnotes := []; [ (meta n) ] )
401
   | <meta>c -> [ (meta (content c)) ]
402
 in
403 404 405 406
 let notes = match !footnotes with
   | [] -> []
   | n -> [ (meta n) ] in
 let main = match (navig @ main @ notes @ navig) with
407 408 409
   | [] -> raise "Empty page !"
   | x -> x in

410 411 412 413
 let right =
  [ <h1>(text banner)
    <div class="mainpanel">[ !main ] ]
 in
414

415
 let html : H.html =
416 417
 <html>[
  <head>[ 
418
   <title>[ !site ': ' !title ]
419
   <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">[]
420
   <link rel="stylesheet" href="cduce.css" type="text/css">[]
421
   !extra_head
422
  ]
423 424 425
  <body style="margin: 0; padding : 0;">[
    <table cellspacing="10" cellpadding="0" width="100%" border="0">[
    <tr>[ !left <td>right ]
426
   ]
427
  ]
428 429
 ]
 in
430
 let txt : Latin1 = 
431
   [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
432
     '  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
433
     !(print_xml html) ] in
434
 let fn = outdir @ "/" @ name @ ".html" in
435
 dump_to_file fn txt;
436
 last
437
	
438

439
let gen_page_seq 
440 441
 (site : String,
  prev : PageO, pages : [Page*], next : PageO, 
442
  path : Path, sitemap : Tree) : (PageO, PageO) =
443 444
 match pages with
 | [ p1 p2 ; _ ] & [ _; rest ] -> 
445 446
     let last = gen_page (site,prev,p1,p2, path, sitemap) in
     let (_,last)  = gen_page_seq (site,last, rest, next, path, sitemap) in 
447
     (p1,last)
448
 | [ p ] ->
449
     let last = gen_page (site,prev,p,next, path, sitemap) in (p,last)
450
 | [] -> (next,prev)
451

452

453
;;
454

455
gen_page (site,[],main_page,[], [], compute_sitemap main_page)