Changeset 52 in code
- Timestamp:
- Oct 21, 2023, 12:34:31 AM (18 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cli/html.ml
r50 r52 7 7 8 8 let init kv = 9 10 11 12 13 14 15 16 | Some s -> Printf.sprintf "<style>%s</style>\n" s | None -> "" in17 9 let open Logarion in 10 let to_string key kv = match Store.KV.find key kv with 11 | fname -> Some (File_store.to_string fname) 12 | exception Not_found -> None in 13 let header = to_string "HTM-header" kv in 14 let footer = to_string "HTM-footer" kv in 15 let style = match to_string "HTM-style" kv with 16 | Some s -> Printf.sprintf "<style type=\"text/css\">%s</style>\n" s | None -> "" in 17 { templates = { header; footer}; style } 18 18 19 19 let wrap conv htm text_title body = 20 let site_title = try Logarion.Store.KV.find "Title" conv.Conversion.kv with Not_found -> "" in 21 let replace x = let open Str in 22 global_replace (regexp "{{archive-title}}") site_title x 23 |> global_replace (regexp "{{text-title}}") text_title 24 in 25 let feed = try Logarion.Store.KV.find "HTM-feed" conv.Conversion.kv 26 with Not_found -> if Sys.file_exists (Filename.concat conv.Conversion.dir "feed.atom") 27 then "feed.atom" else "" in 28 let header = match htm.templates.header with 29 | Some x -> replace x 30 | None -> Printf.(sprintf "<a href='.'>%s</a>%s" site_title 31 (if feed <> "" then sprintf "<a href='%s' id='feed'>feed</a>" feed else "")) 32 in 33 let footer = match htm.templates.footer with None -> "" | Some x -> replace x in 34 Printf.sprintf "<!DOCTYPE HTML PUBLIC \"//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<link rel=\"icon\" href=\"/favicon.png\">\n<title>%s%s</title>\n%s\n%s\ 35 <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n%s%s%s</body>\n</html>" 36 text_title (if site_title <> "" then (" • " ^ site_title) else "") 37 htm.style 38 (if feed <> "" then Printf.sprintf "<link rel='alternate' href='%s' type='application/atom+xml'>" feed else "") 39 header body footer 20 let site_title = try Logarion.Store.KV.find "Title" conv.Conversion.kv with Not_found -> "" in 21 let replace x = let open Str in 22 global_replace (regexp "{{archive-title}}") site_title x 23 |> global_replace (regexp "{{text-title}}") text_title 24 in 25 let feed = try Logarion.Store.KV.find "HTM-feed" conv.Conversion.kv 26 with Not_found -> if Sys.file_exists (Filename.concat conv.Conversion.dir "feed.atom") 27 then "feed.atom" else "" in 28 let header = match htm.templates.header with 29 | Some x -> replace x 30 | None -> Printf.(sprintf "<a href='.'>%s</a>%s" site_title 31 (if feed <> "" then sprintf "<a href='%s' id='feed'>feed</a>" feed else "")) 32 in 33 let footer = match htm.templates.footer with None -> "" | Some x -> replace x in 34 Printf.sprintf "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<link rel=\"icon\" href=\"/favicon.png\">\n<title>%s%s</title>\n%s\n%s\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n%s%s%s</body>\n</html>" 35 text_title (if site_title <> "" then (" • " ^ site_title) else "") 36 htm.style 37 (if feed <> "" then Printf.sprintf "<link rel='alternate' href='%s' type='application/atom+xml'>" feed else "") 38 header body footer 40 39 41 40 let topic_link root topic = 42 43 44 41 let replaced_space = String.map (function ' '->'+' | x->x) in 42 "<a href='index." ^ root ^ ".htm#" ^ replaced_space topic ^ "'>" 43 ^ String.capitalize_ascii topic ^ "</a>" 45 44 46 45 module HtmlConverter = struct 47 48 49 50 51 46 include Converter.Html 47 let uid_uri u a = Printf.sprintf "%s<a href='%s%s'><%s></a>" a u ext u 48 let angled_uri u a = 49 if try String.sub u 0 10 = "urn:txtid:" with Invalid_argument _ -> false 50 then angled_uri (String.(sub u 10 (length u - 10)) ^ ext) a else angled_uri u a 52 51 end 53 52 54 53 let page htm conversion text = 55 let open Logarion in 56 let open Text in 57 let module T = Parsers.Plain_text.Make (HtmlConverter) in 58 let sep_append ?(sep=", ") a x = match a,x with "",_ -> x | _, "" -> a | _ -> a ^ sep ^ x in 59 let opt_kv key value = if String.length value > 0 60 then "<dt>" ^ key ^ "<dd>" ^ value else "" in 61 (* let author acc auth = sep_append acc Person.(auth.name ^ " ") in*) 62 let authors = Person.Set.to_string text.authors in 63 let header = 64 let time x = Printf.sprintf {|<span class="%s">%s</span>|} 65 (Date.rfc_string x) (Date.pretty_date x) in 66 let topic_links x = 67 let to_linked t a = 68 let ts = Topic_set.of_string t in 69 sep_append a (List.fold_left (fun a t -> sep_append ~sep:" > " a (topic_link (List.hd ts) t)) "" ts) in 70 String_set.fold to_linked x "" in 71 let ref_links x = 72 let link l = HtmlConverter.uid_uri l "" in 73 String_set.fold (fun r a -> sep_append a (link r)) x "" 74 in 75 let references, replies = let open Conversion in 76 let Rel.{ref_set; rep_set; _} = 77 try Rel.Id_map.find text.id conversion.relations 78 with Not_found -> Rel.empty in 79 ref_links ref_set, ref_links rep_set 80 in 81 "<dl>" 82 ^ opt_kv "Title:" text.title 83 ^ opt_kv "Authors:" authors 84 ^ opt_kv "Date:" (time (Date.listing text.date)) 85 ^ opt_kv "Series:" (str_set "series" text) 86 ^ opt_kv "Topics:" (topic_links (set "topics" text)) 87 ^ opt_kv "Id:" text.id 88 ^ opt_kv "Refers:" (ref_links (set "references" text)) 89 ^ opt_kv "In reply to:" (ref_links (set "in-reply-to" text)) 90 ^ opt_kv "Referred by:" references 91 ^ opt_kv "Replies:" replies 92 ^ {|</dl><pre style="white-space:pre-wrap">|} in 93 wrap conversion htm text.title ((T.of_string text.body header) ^ "</pre>") 54 let open Logarion in 55 let open Text in 56 let module T = Parsers.Plain_text.Make (HtmlConverter) in 57 let sep_append ?(sep=", ") a x = match a,x with "",_ -> x | _, "" -> a | _ -> a ^ sep ^ x in 58 let opt_kv key value = if String.length value > 0 59 then "<dt>" ^ key ^ "<dd>" ^ value else "" in 60 let authors = Person.Set.to_string text.authors in 61 let header = 62 let time x = Printf.sprintf {|<span class="%s">%s</span>|} 63 (Date.rfc_string x) (Date.pretty_date x) in 64 let topic_links x = 65 let to_linked t a = 66 let ts = Topic_set.of_string t in 67 sep_append a (List.fold_left (fun a t -> sep_append ~sep:" > " a (topic_link (List.hd ts) t)) "" ts) in 68 String_set.fold to_linked x "" in 69 let ref_links x = 70 let link l = HtmlConverter.uid_uri l "" in 71 String_set.fold (fun r a -> sep_append a (link r)) x "" in 72 let references, replies = let open Conversion in 73 let Rel.{ref_set; rep_set; _} = try Rel.Id_map.find text.id conversion.relations with Not_found -> Rel.empty in 74 ref_links ref_set, ref_links rep_set in 75 "<dl>" 76 ^ opt_kv "Title:" text.title 77 ^ opt_kv "Authors:" authors 78 ^ opt_kv "Date:" (time (Date.listing text.date)) 79 ^ opt_kv "Series:" (str_set "series" text) 80 ^ opt_kv "Topics:" (topic_links (set "topics" text)) 81 ^ opt_kv "Id:" text.id 82 ^ opt_kv "Refers:" (ref_links (set "references" text)) 83 ^ opt_kv "In reply to:" (ref_links (set "in-reply-to" text)) 84 ^ opt_kv "Referred by:" references 85 ^ opt_kv "Replies:" replies 86 ^ {|</dl><pre style="white-space:pre-wrap">|} in 87 wrap conversion htm text.title ((T.of_string text.body header) ^ "</pre>") 94 88 95 89 let to_dated_links ?(limit) meta_list = 96 let meta_list = match limit with 97 | None -> meta_list 98 | Some limit-> 99 let rec reduced acc i = function 100 | [] -> acc 101 | h::t -> if i < limit then reduced (h::acc) (i+1) t else acc in 102 List.rev @@ reduced [] 0 meta_list 103 in 104 List.fold_left 105 (fun a m -> Printf.sprintf "%s<li> %s <a href=\"%s.htm\">%s</a>" a 106 Logarion.(Date.(pretty_date (listing m.Text.date))) 107 (Logarion.Text.short_id m) m.Logarion.Text.title) 108 "" meta_list 90 let meta_list = match limit with 91 | None -> meta_list 92 | Some limit-> 93 let rec reduced acc i = function 94 | [] -> acc 95 | h::t -> if i < limit then reduced (h::acc) (i+1) t else acc in 96 List.rev @@ reduced [] 0 meta_list in 97 List.fold_left 98 (fun a m -> Printf.sprintf "%s<li>%s <a href=\"%s.htm\">%s</a></li>" a Logarion.(Date.(pretty_date (listing m.Text.date))) 99 (Logarion.Text.short_id m) m.Logarion.Text.title) 100 "" meta_list 109 101 110 102 let date_index ?(limit) conv htm meta_list = 111 112 113 103 match limit with 104 | Some limit -> wrap conv htm "Index" (to_dated_links ~limit meta_list) 105 | None -> wrap conv htm "Index" (to_dated_links meta_list) 114 106 115 107 let fold_topic_roots topic_roots = 116 117 118 119 108 let list_item root t = "<li>" ^ topic_link root t in 109 "<h2>Main topics</h2>" 110 ^ List.fold_left (fun a x -> a ^ list_item x x) "<ul>" (List.rev topic_roots) 111 ^ "</ul>" 120 112 121 113 let fold_topics topic_map topic_roots metas = 122 let open Logarion in 123 let rec unordered_list root topic = 124 List.fold_left (fun a x -> a ^ list_item root x) "<ul>" topic 125 ^ "</ul>" 126 and sub_items root topic = match Topic_set.Map.find_opt topic topic_map with 127 | None -> "" 128 | Some (_, subtopics) -> unordered_list root (String_set.elements subtopics) 129 and list_item root t = 130 let item = 131 if List.exists (fun x -> String_set.mem t (String_set.map Topic_set.topic (Text.set "topics" x))) metas 132 then topic_link root t else String.capitalize_ascii t 133 in 134 "<li>" ^ item ^ sub_items root t 135 in 136 "<h2>Topics</h2>" 137 ^ List.fold_left (fun a x -> a ^ list_item x x) "<ul>" (List.rev topic_roots) 138 ^ "</ul>" 114 let open Logarion in 115 let rec unordered_list root topic = 116 List.fold_left (fun a x -> a ^ list_item root x) "<ul>" topic 117 ^ "</ul>" 118 and sub_items root topic = match Topic_set.Map.find_opt topic topic_map with 119 | None -> "" 120 | Some (_, subtopics) -> unordered_list root (String_set.elements subtopics) 121 and list_item root t = 122 let item = 123 if List.exists (fun x -> String_set.mem t (String_set.map Topic_set.topic (Text.set "topics" x))) metas 124 then topic_link root t else String.capitalize_ascii t in 125 "<ul><li>" ^ item ^ sub_items root t ^ "</ul>" in 126 "<h2>Topics</h2>" 127 ^ List.fold_left (fun a x -> a ^ list_item x x) "<ul>" (List.rev topic_roots) 128 ^ "</ul>" 139 129 140 130 let text_item path meta = 141 142 "<span>" ^ Date.(pretty_date (listing meta.Text.date))143 ^ {|</span><a href="|} ^ path ^ Text.short_id meta ^ {|.htm">|} ^ meta.Text.title144 ^ "</a><br>"131 let open Logarion in 132 "<p>" ^ Date.(pretty_date (listing meta.Text.date)) 133 ^ {|<a href="|} ^ path ^ Text.short_id meta ^ {|.htm">|} ^ meta.Text.title 134 ^ "</a></p><br>" 145 135 146 136 let listing_index topic_map topic_roots path metas = 147 let rec item_group topics = 148 List.fold_left (fun acc topic -> acc ^ sub_groups topic ^ items topic) "" topics 149 and sub_groups topic = match Logarion.Topic_set.Map.find_opt topic topic_map with 150 | None -> "" 151 | Some (_, subtopics) -> item_group (Logarion.String_set.elements subtopics) 152 and items topic = 153 let items = 154 let open Logarion in 155 List.fold_left 156 (fun a e -> 157 if String_set.mem topic (String_set.map (Logarion.Topic_set.topic) (Text.set "Topics" e)) 158 then text_item path e ^ a else a) "" metas in 159 match items with 160 | "" -> "" 161 | x -> {|<h2 id="|} ^ topic ^ {|">|} ^ String.capitalize_ascii topic ^ "</h2>" ^ x 162 in 163 "<h1>Texts</h1>" ^ item_group topic_roots ^ "" 137 let rec item_group topics = 138 List.fold_left (fun acc topic -> acc ^ sub_groups topic ^ items topic) "" topics 139 and sub_groups topic = match Logarion.Topic_set.Map.find_opt topic topic_map with 140 | None -> "" 141 | Some (_, subtopics) -> item_group (Logarion.String_set.elements subtopics) 142 and items topic = 143 let items = 144 let open Logarion in 145 List.fold_left 146 (fun a e -> 147 if String_set.mem topic (String_set.map (Logarion.Topic_set.topic) (Text.set "Topics" e)) 148 then text_item path e ^ a else a) "" metas in 149 match items with 150 | "" -> "" 151 | x -> {|<h2 id="|} ^ topic ^ {|">|} ^ String.capitalize_ascii topic ^ "</h2>" ^ x in 152 "<h1>Texts</h1>" ^ item_group topic_roots ^ "" 164 153 165 154 let topic_main_index conv htm topic_roots metas = 166 167 168 ^ "<h1>Latest</h1><ul>" ^ to_dated_links ~limit:8metas169 ^ {|</ul><a href="index.date.htm">More by date</a>|}170 171 172 173 174 155 wrap conv htm "Topics" 156 (fold_topic_roots topic_roots 157 ^ "<h1>Latest</h1><ul>" ^ to_dated_links ~limit:10 metas 158 ^ {|<p><a href="index.date.htm">More by date</a></p>|} 159 ^ let peers = try Logarion.Store.KV.find "Peers" conv.kv with Not_found -> "" in 160 (if peers = "" then "" else 161 List.fold_left (fun a s -> Printf.sprintf {|%s<li><a href="%s">%s</a>|} a s s) "<h1>Peers</h1><ul>" 162 (Str.split (Str.regexp ";\n") (Logarion.Store.KV.find "Peers" conv.kv)) 163 ^ "</ul>")) 175 164 176 165 let topic_sub_index conv htm topic_map topic_root metas = 177 wrap conv htm topic_root 178 (fold_topics topic_map [topic_root] metas 179 (* ^ {|<a href=".atom" id="feed">|}^ String.capitalize_ascii topic_root ^{| feed </a>|}*) 180 ^ listing_index topic_map [topic_root] "" metas) 166 wrap conv htm topic_root 167 (fold_topics topic_map [topic_root] metas 168 ^ listing_index topic_map [topic_root] "" metas) 181 169 182 170 let indices htm c = 183 184 185 186 187 188 189 171 let file name = Logarion.File_store.file (Filename.concat c.Conversion.dir name) in 172 let index_name = try Logarion.Store.KV.find "HTM-index" c.Conversion.kv with Not_found -> "index.html" in 173 if index_name <> "" then file index_name (topic_main_index c htm c.topic_roots c.texts); 174 file "index.date.htm" (date_index c htm c.texts); 175 List.iter 176 (fun root -> file ("index." ^ root ^ ".htm") (topic_sub_index c htm c.topics root c.texts)) 177 c.topic_roots 190 178 191 let converter kv = 192 193 179 let converter kv = 180 let htm = init kv in 181 Conversion.{ ext; page = Some (page htm); indices = Some (indices htm) }
Note:
See TracChangeset
for help on using the changeset viewer.