--- web/site.cd 2007/07/10 17:20:22 261 +++ web/site.cd 2007/07/10 17:46:38 589 @@ -1,197 +1,367 @@ -include "xhtml-strict.cd";; (* XHTML 1 Strict DTD *) -include "xhtml-categ.cd";; (* Categories (Inline, ...) from this DTD *) +(* This CDuce script produces CDuce web site. *) -type SitePage = - [] - | [];; -type Site = [ SitePage* ];; - -type Page = - [ - String - <banner>[InlineText*] - <navig>[ NavigBox* ] <main>[ Box* ] ];; +(** Command line **) -type Author = <author>String;; +let input = + match argv with + | [ s ] -> s + | _ -> raise "Please specify an input file on the command line" + + +(** Output types **) + +include "xhtml-strict.cd" (* XHTML 1 Strict DTD *) +include "xhtml-categ.cd" (* Categories (Inline, ...) from this DTD *) + + +(** Input types **) + +type Page = <page name=String>[ <title>String <banner>[InlineText*]? Item* ] +type External = <external {|href=String; title=String; name=String |}>[] + +type Item = + <box title=String link=String>Content + | <meta>Content + | <left>Content + | Page + | External + +type Author = <author>String type Paper = <paper file=?String>[ - <title>String - Author+ - <comment>[InlineText*] - <abstract>Content ];; + <title>String Author+ <comment>[InlineText*] <abstract>Content ] type Slides = - <slides file=String>[ - <title>String - Author+ - <comment>[InlineText*] ];; + <slides file=String>[ <title>String Author+ <comment>[InlineText*] ] type Link = - <link url=String; title=String>[ InlineText* ];; + <link url=String title=String>[ InlineText* ] type Content = [ ( <p {||}>[InlineText*] | <ul {||}>[<li {||}>Content +] | <section title=String>Content + | <sample highlight=?"true"|"false">String | Xtable - | Paper | Slides | Link - | <include-verbatim file=String>[] - | InlineText )* ];; + | Paper | Slides | Link + | <boxes-toc>[] + | <pages-toc>[] + | <site-toc>[] + | <local-links href=String>[] + | <two-columns>[ <left>Content <right>Content ] + | InlineText + )* ] type InlineText = Char - | <(`b|`i) {||}>[InlineText*] - | <duce>[InlineText*] - | Xa - | Ximg | Xbr ;; - -type Box = <box title=String; subtitle=?String; link=String>Content - | <meta>Content;; -type NavigBox = <box>Content | <toc>[];; + | <(`b|`i|`tt|`em) {||}>[InlineText*] + | <code>String + | <local href=String>String + | Xa | Ximg | Xbr + + +(** Generic purpose functions **) + +(* Recursive inclusion of XML files and verbatim text files *) -let fun authors ([Author+] -> String) +let load_include (String -> [Any*]) + name -> +(* let _ = print [ 'Loading ' !name '... \n' ] in *) + xtransform [ (load_xml name) ] with + | <include file=(s & String)>[] -> load_include s + | <include-verbatim file=(s & String)>[] -> load_file s + +(* Highlighting text between {{...}} *) + +let highlight (String -> [ (Char | Xvar | Xi)* ] ) + | [ '{{' h ::(Char *?) '}}' ; rest ] -> + [ <var class="highlight">h; highlight rest ] + | [ '%%' h ::(Char *?) '%%' ; rest ] -> + [ <i>h; highlight rest ] + | [ c; rest ] -> [ c; highlight rest ] + | [] -> [] + +(* Split a comma-separated string *) + +let split_comma (String -> [String*]) + | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest) + | s -> [ s ] + + +(** Internal types **) + +type Path = [ { url = String; title = String }* ] +type Tree = { name = String; url = String; title = String; + children = [Tree*] } + +let url_of_name (String -> String) + "index" -> "/" + | s -> s @ ".html" + +let authors ([Author+] -> String) | [ <author>a ] -> a | [ <author>a1 <author>a2 ] -> a1 @ ", and " @ a2 - | [ <author>a; rem ] -> a @ ", " @ authors rem;; + | [ <author>a; rem ] -> a @ ", " @ authors rem + +let find_local_link (sitemap : [Tree*], l : String) : Tree = +match sitemap with + | (h,t) -> + if (h . name = l) then h + else + (try find_local_link (t,l) with `Not_found -> + find_local_link (h . children,l)) + | [] -> raise `Not_found + +let local_link (sitemap : Tree, l : String, txt : String) : Inline = + try + let h = find_local_link ([sitemap],l) in + let txt = if txt = "" then h . title else txt in + <a href=(h . url)>txt + with `Not_found -> raise [ 'Local link not found: ' !l ] + +let compute_sitemap ((Page|External) -> Tree) + <page name=name>[ <title>title (c::(Page|External) | _)* ] -> + let children = map c with p -> compute_sitemap p in + { name = name; url = url_of_name name; title = title; children =children } +|<external name=name href=h title=t>[] -> + { name = name; url = h; title = t; children = [] } + +let display_sitemap (h : Tree) : Xli = + let ch = map h . children with x -> display_sitemap x in + let ch = match ch with [] -> [] | l -> [ <ul>l ] in + <li>[ <a href=(h . url)>(h . title); ch ] + +let link_to (Page -> Xa) + <page name=n>[<title>t ; _ ] -> <a href=(url_of_name n)>t + +let box (x : Flow) : Block = + <table cellpadding="2" + style="font-size:11px ; font-family:arial,sans-serif; + border: solid 2px black; background: #ffffff" width="100%"> + [ <tr> [<td>x] ] + +let meta (x : Flow) : Block = + <table cellpadding="2" + style="border: solid 1px #b0b0b0; background: #e0e0e0; font-size: 80%" + width="100%"> + [ <tr> [<td>x] ] + +let box_title (x : Flow, t : String) : Block = + <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; +} +p { + text-align: justify; + margin: 1ex 1em 0 1em; +} +pre { + margin: 1ex 1em 0 1em; +} +var.highlight { + color: #FF0000; +} +img.icon { + border: 0; +} +div.code { + background: #E0E0E0; + margin: 0.5ex 0.5em 0 0.5em; + padding: 0.2ex; +} +div.abstract { + font: bold 80% helvetica; + margin: 1ex 1em 1ex 1em; + padding: 1ex 1em 1ex 1em; + background: #F0F0F0; +} +div.abstract p { + font: 100% sans-serif; +} +" + +(* Main transformation function *) -let fun text (t : [InlineText*]) : Inlines = - map t with - <duce>x -> <b>[ <tt>(text x) ] - | <b>x -> <b>(text x) - | <i>x -> <i>(text x) - | z -> z;; -let fun content (t : Content) : Flow = +(* returns the last page of the descendance *) +let gen_page (prev : Page|[], page : Page, next : Page|[], + path : Path, sitemap : Tree) : (Page|[]) = +match page with +<page name=name>[ + <title>title <banner>banner | <title>(title & banner); items ] -> + + let text (t : [InlineText*]) : Inlines = + map t with + | <code>x -> <b>[ <tt>(highlight x) ] + | <local href=l>txt -> local_link (sitemap,l,txt) + | <(tag & (`b|`i|`tt|`em))>x -> <(tag)>(text x) +(* | <a href=url>_ & z -> let [] = print [ 'Link: ' !url '\n'] in z *) + | z -> z + in + + let content (t : Content) : Flow = transform t with - | <section title=title>c -> [ <h4>title !(content c) ] + | <section title=title>c -> + [ <p>[ <b style="color: #008000">title ] !(content c) ] | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab ] -> - [ - (match r with - | { file = f } -> <a href=f>tit - | _ -> <b>tit - ) '. ' + [ (match r with { file = f } -> <a href=f>tit | _ -> <b>tit) '. ' !(authors aut) '. ' !(text com) <div class="abstract">[ 'Abstract:' !(content ab) ] ] | <slides file=f>[ <title>tit aut::Author* <comment>com ] -> [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ] - | <include-verbatim file=f>[] -> - let code = load_file f in - let code = transform code with -(* | c & ('a'--'z') -> [ <b>[c] ] *) -(* | ' ' -> "\160" *) - | c -> [c] in - [ - <div class="code">[ <pre>code ] - ] - | <link url=url; title=title>com -> [ <a href=url>title '. ' !(text com) ] - | <ul>lis -> [ <ul>(map lis with <li>x -> <li>(content x)) ] - | Xtable & x -> [ x ] + | <sample highlight="false">s -> + [ <div class="code">[ <pre>s ] ] + | <sample>s -> + [ <div class="code">[ <pre>(highlight s) ] ] + | <link url=url title=title>com -> + [ <a href=url>title '. ' !(text com) ] + | <ul>lis -> + [ <ul>(map lis with <li>x -> <li>(content x)) ] + | Xtable & x -> + [ x ] | <p>x -> [ <p>(text x) ] - | <ul>x -> [ <ul>(text x) ] - | x -> text [ x ];; + | <pages-toc>[] -> + let toc = + transform items with + | Page & p -> [ <li>[ (link_to p) ] ] + | <external href=l title=t>[] -> [ <li>[ <a href=l>t ] ] in + (match toc with [] -> [] | lis -> [ <ul>lis ]) + | <boxes-toc>[] -> + let toc = + transform items with + <box title=t link=l>_ -> [ <li>[ <a href=('#',l)>t ] ] in + (match toc with [] -> [] | lis -> [ <ul>lis ]) + | <site-toc>[] -> + [ <ul>[ (display_sitemap sitemap) ] ] + | <local-links href=s>[] -> + (match (split_comma s) with + | [] -> [] + | l -> let l = map l with x -> <li>[ (local_link(sitemap,x,"")) ] + in [ <ul>l ]) + | <two-columns>[ <left>x <right>y ] -> + [ <table width="100%">[ + <tr>[ + <td valign="top">(content x) + <td valign="top">(content y) ] ] ] + | t -> text [ t ] + in + + +(* Preparing left panel *) + 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">[ + <table cellpadding="0" cellspacing="15" + width="200" + style="font-size:80%; border: 1px dashed black; + background: #ffcd72"> + (map left with x -> <tr>[ <td>[ (box (content x)) ] ]) ] in -let fun main2html (Box -> Flow) - <box (r)>c -> - [ <div class="box">[ - <h2>(r.title) - !(match r with { subtitle = t } -> [<b>t] | _ -> []) - <a name=r.link>[] - !(content c) ] ] -| <meta>c -> [ <div class="meta">(content c) ];; - - -let php_css : String = -[' <?php -$browser = getenv("HTTP_USER_AGENT"); -if (preg_match("/MSIE/i", "$browser")) { - $css = "<link rel=\"stylesheet\" href=\"cduce.css\" -type=\"text/css\">"; -} elseif (preg_match("/Mozilla/i", "$browser")) { - $css = "<blink>For better presentation use a more recent version -of your browser, like Netscape 6</blink>"; -} if (preg_match("/Mozilla\/5.0/i", "$browser")) { - $css = "<link rel=\"stylesheet\" href=\"cduce.css\" -type=\"text/css\">"; -} elseif (preg_match("/opera/i", "$browser")) { - $css = "<link rel=\"stylesheet\" href=\"cduce.css\" -type=\"text/css\">"; -} -echo "$css"; -?> '];; - - -let fun patch_css (String -> String) -| [ a::_*? '<meta content="css"/>'; rem ] -> a @ php_css @ rem -| s -> s;; - -let fun page2html (Page -> Xhtml) -<page>[ <title>title <banner>banner <navig>navig <main>main ] -> - let toc = - transform main with <box title=t; link=l>_ -> [ <li>[ <a href=('#',l)>t ] ] in - let toc = match toc with [] -> [] | lis -> [ <ul>lis ] in - let navig : Flow = transform navig with - | <box>c -> [ <div class="box">(content c) ] - | <toc>[] -> [ <div class="box">toc ] + let dpath : Inlines = transform path with + | { url = f; title = t } -> [ <a href=f>t ': '] in + let npath = path @ [ { url = url_of_name name; title = title } ] in + let subpages = transform items with p & Page -> [ p ] in + let (next,last) = gen_page_seq (page, subpages, next, npath, sitemap) in + let next = match next with [] -> [] + | <page name=n>[ <title>t; _ ] -> + [ <a href=(url_of_name n)>[ + <img width="16" height="16" class="icon" alt="Next page" + src="img/right.gif">[] + ' ' !t + ] ] in + let prev = match prev with [] -> [] + | <page name=n>[ <title>t; _ ] -> + [ <a href=(url_of_name n)>[ + <img width="16" height="16" class="icon" + alt="Previous page" src="img/left.gif">[] + ' ' !t + ] ] in + let navig = + if prev = [] then [] else + [ (box [ + <p>[ !dpath !title ] + <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 + let main = match (navig @ main @ navig) with + | [] -> raise "Empty page !" + | x -> x in + + let right : Xtd = + <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" + style="border: 1px solid black; background: #fccead">[ + <table width="100%" cellpadding="0" cellspacing="17"> + (map main with x -> <tr>[ <td>[x] ]) + ] ] + ] ] in + + let html : Xhtml = <html>[ <head>[ - <title>title - <meta content="text/html; charset=iso-8859-1"; http-equiv="Content-Type">[] - <meta content="css">[] + <title>[ 'CDuce: ' !title ] + <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">[] + <style type="text/css">style ] - <body>[ - <div class="title">[ <h1>(text banner) ] - <div id="Sidelog">navig - <div id="Content">(transform main with b -> main2html b) + <body style="margin: 0; padding : 0; background: #fcb333">[ + <table cellspacing="10" cellpadding="0" width="100%" border="0">[ + <tr>[ left right ] + ] ] - ];; - -type P = (String,<title>String);; -let fun make_plan (l : [ P+ ]) : Page = -<page>[ <title>"CDuce site" - <banner>"CDuce site" - <navig>[ <box>[ <a href="/">"Home" ] ] - <main>[ - <box title="Pages"; link="pages">[ - <ul>(map l with (file,<title>t) -> <li>[<a href=file>t]) ] - <meta>[ - 'This page was automatically generated by a CDuce program.' - ] - ] - ];; + ] + in + let txt : Latin1 = + [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' + ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' + !(print_xml html) ] in + let fn = "www/" @ name @ ".html" in + let [] = dump_to_file fn txt in + last + + +let gen_page_seq + (prev : Page|[], pages : [Page*], next : Page|[], + path : Path, sitemap : Tree) : (Page|[], Page|[]) = + match pages with + | [ p1 p2 ; _ ] & [ _; rest ] -> + let last = gen_page (prev,p1,p2, path, sitemap) in + let (_,last) = gen_page_seq (last, rest, next, path, sitemap) in + (p1,last) + | [ p ] -> + let last = gen_page (prev,p,next, path, sitemap) in (p,last) + | [] -> (next,prev) + + +;; + +match load_include input with + | [ Page & p ] -> let _ = gen_page ([],p,[], [], compute_sitemap p) in [] + | _ -> raise ("Invalid input document " @ input) -let fun do_page((Page,String) -> []) - (page,outf) -> - let _ = print [ 'Generating html ... ' ] in - let html : String = - [ (* '<?xml version="1.0" encoding="iso-8859-1"?>' *) - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' - ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' - !(patch_css (print_xml (page2html page))) ] in - let _ = print [ 'Saving to ' !outf '...\n' ] in - dump_to_file outf html;; - -let fun do_file((String,String) -> P) - (inf,outf) -> - let _ = print [ 'Loading ' !inf '... ' ] in - let page = match load_xml inf with - | Page & p -> p - | _ -> raise ("Invalid input document: " @ inf) in - let _ = do_page (page,outf) in - let tit = match [page]/<title>_ with [t] -> t in - (outf, tit);; - - -let site = - let _ = print [ 'Loading site.xml ...\n' ] in - match load_xml "site.xml" with - | Site & <site>s -> - let ts = map s with - | <page input=inf; output=outf>_ -> do_file(inf,outf) - | <external href=url; title=t>_ -> (url,<title>t) in - let _ = print [ 'Create plan... ' ] in - let plan = make_plan (ts @ [("plan.php", <title>"CDuce site")]) in - do_page(plan,"plan.php") - | _ -> raise "Invalid site.xml";;