1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DuplicateRecordFields #-}
3 {-# LANGUAGE ExistentialQuantification #-}
4 {-# LANGUAGE FlexibleInstances #-}
5 {-# LANGUAGE FlexibleContexts #-}
6 {-# LANGUAGE MultiParamTypeClasses #-}
7 {-# LANGUAGE OverloadedStrings #-}
8 {-# LANGUAGE ScopedTypeVariables #-}
9 {-# LANGUAGE TypeApplications #-}
10 {-# LANGUAGE ViewPatterns #-}
11 {-# OPTIONS_GHC -fno-warn-orphans #-}
12 module Hdoc.DTC.Write.HTML5 where
14 import Control.Applicative (Applicative(..))
15 import Control.Category as Cat
18 import Data.Char (Char)
19 import Data.Default.Class (Default(..))
20 import Data.Either (Either(..))
21 import Data.Eq (Eq(..))
22 import Data.Foldable (Foldable(..), concat, any)
23 import Data.Function (($), const, on)
24 import Data.Functor ((<$>), (<$))
25 import Data.Functor.Compose (Compose(..))
27 import Data.Map.Strict (Map)
28 import Data.Maybe (Maybe(..), maybe, mapMaybe, fromJust, maybeToList, listToMaybe, fromMaybe, isJust)
29 import Data.Monoid (Monoid(..))
30 import Data.Ord (Ord(..))
31 import Data.Semigroup (Semigroup(..))
32 import Data.String (String, IsString(..))
33 import Data.Text (Text)
34 import Data.TreeSeq.Strict (Tree(..), tree0)
35 import Data.Tuple (snd)
36 import Prelude (mod, (*), Fractional(..), Double, toRational, RealFrac(..), error)
37 import System.FilePath (FilePath)
38 import Text.Blaze ((!))
39 import Text.Blaze.Html (Html)
40 import Text.Show (Show(..))
41 import qualified Control.Monad.Trans.State as S
42 import qualified Data.ByteString.Lazy as BS
43 import qualified Data.Char as Char
44 import qualified Data.HashMap.Strict as HM
45 import qualified Data.HashSet as HS
46 import qualified Data.List as List
47 import qualified Data.Map.Strict as Map
48 import qualified Data.Sequence as Seq
49 import qualified Data.Set as Set
50 import qualified Data.Strict.Maybe as Strict
51 import qualified Data.Text as Text
52 import qualified Data.Text.Lazy as TL
53 import qualified Data.Text.Lazy.Builder as TL.Builder
54 import qualified Data.Text.Lazy.Builder.Int as TL.Builder
55 import qualified Data.Text.Lazy.Encoding as TL
56 import qualified Data.TreeMap.Strict as TreeMap
57 import qualified Data.TreeSeq.Strict as TreeSeq
58 import qualified Data.TreeSeq.Strict.Zipper as Tree
59 import qualified Hjugement as MJ
60 -- import qualified Text.Blaze.Internal as B
61 import qualified Text.Blaze.Html5 as H
62 import qualified Text.Blaze.Html5.Attributes as HA
63 import qualified Text.Blaze.Internal as H
64 import qualified Data.Tree as Tree
66 import Text.Blaze.Utils
67 import Data.Locale hiding (Index)
70 import Hdoc.DTC.Document as DTC
71 import Hdoc.DTC.Write.Plain (Plainify(..))
72 import Hdoc.DTC.Write.XML ()
73 import qualified Hdoc.DTC.Index as Index
74 import qualified Hdoc.DTC.Anchor as Anchor
75 import qualified Hdoc.DTC.Write.Plain as Plain
78 debug :: Show a => String -> a -> a
79 debug msg a = trace (msg<>": "<>show a) a
80 debugOn :: Show b => String -> (a -> b) -> a -> a
81 debugOn msg get a = trace (msg<>": "<>show (get a)) a
82 debugWith :: String -> (a -> String) -> a -> a
83 debugWith msg get a = trace (msg<>": "<>get a) a
85 showJudgments :: HM.HashMap (Ident,Ident,Maybe Title) [Tree.Tree [Choice]] -> String
89 -- Tree.Node (Left ("","",Nothing)) $
90 (<$> HM.toList js) $ \((j,g,q),ts) ->
92 (Left (unIdent j,unIdent g,Plain.text def <$> q))
95 writeHTML5 :: Config -> DTC.Document -> Html
96 writeHTML5 conf@Config{..} doc@DTC.Document{..} = do
97 let state_mapping@Mapping{..} :: Mapping = mappingOf doc
98 let (body',state_rrefs,state_notes,state_indexs) =
99 let irefs = foldMap Index.irefsOfTerms mapping_index in
100 let (body0, Anchor.State{state_irefs, state_rrefs=rrefs, state_notes=notes}) =
101 Anchor.anchorify body `S.runState`
102 def{Anchor.state_irefs=irefs} in
103 (body0,rrefs,notes,) $
104 (<$> mapping_index) $ \terms ->
106 TreeMap.intersection const state_irefs $
107 Index.irefsOfTerms terms
108 let state_plainify = def{Plain.state_l10n = loqualize config_locale}
109 let (html5Body, endState) =
116 , state_l10n = loqualize config_locale
119 html5DocumentHead head
122 H.html ! HA.lang (attrify $ countryCode config_locale) $ do
123 html5Head conf endState head body
126 html5Head :: Config -> State -> Head -> Body -> Html
127 html5Head Config{..} State{..} Head{DTC.about=About{..}} body = do
129 H.meta ! HA.httpEquiv "Content-Type"
130 ! HA.content "text/html; charset=UTF-8"
131 unless (null titles) $ do
133 H.toMarkup $ Plain.text state_plainify $ List.head titles
134 forM_ links $ \Link{..} ->
136 "stylesheet" | URL "" <- href ->
137 H.style ! HA.type_ "text/css" $
138 H.toMarkup $ Plain.text def plain
140 H.link ! HA.rel (attrify rel)
141 ! HA.href (attrify href)
143 H.link ! HA.rel "self"
144 ! HA.href (attrify href)
145 unless (TL.null config_generator) $ do
146 H.meta ! HA.name "generator"
147 ! HA.content (attrify config_generator)
149 H.meta ! HA.name "keywords"
150 ! HA.content (attrify $ TL.intercalate ", " tags)
152 (`mapMaybe` toList body) $ \case
153 Tree k@BodySection{} _ -> Just k
155 forM_ chapters $ \case
157 H.link ! HA.rel "Chapter"
158 ! HA.title (attrify $ plainify title)
159 ! HA.href (refIdent $ identify pos)
161 unless (any (\DTC.Link{..} -> rel == "stylesheet" && href /= URL "") links) $ do
165 H.link ! HA.rel "stylesheet"
166 ! HA.type_ "text/css"
167 ! HA.href (attrify css)
169 H.style ! HA.type_ "text/css" $
170 -- NOTE: as a special case, H.style wraps its content into an External,
171 -- so it does not HTML-escape its content.
173 forM_ state_styles $ \style ->
174 H.style ! HA.type_ "text/css" $
176 unless (any (\DTC.Link{rel} -> rel == "script") links) $ do
177 forM_ state_scripts $ \script ->
178 H.script ! HA.type_ "application/javascript" $
181 html5DocumentHead :: Head -> Html5
182 html5DocumentHead Head{DTC.about=About{..}, judgments} = do
183 unless (null authors) $ do
184 H.div ! HA.class_ "document-head" $$
188 H.td ! HA.class_ "left" $$ docHeaders
189 H.td ! HA.class_ "right" $$ docAuthors
190 unless (null titles) $
191 H.div ! HA.class_ "title" $$ do
192 forM_ titles $ \title ->
193 H.h1 $$ html5ify title
194 st <- liftStateMarkup S.get
196 let sectionJudgments = HS.fromList judgments
197 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
198 liftStateMarkup $ S.modify' $ \s ->
199 s{ state_judgments = sectionJudgments
201 -- NOTE: drop current opinions of the judgments of this section
202 HM.unionWith (const List.tail)
204 opinsBySectionByJudgment
206 unless (null opinsBySectionByJudgment) $ do
207 let choicesJ = choicesByJudgment judgments
208 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
209 H.div ! HA.class_ "judgment section-judgment document-judgment" $$ do
210 let choices = maybe [] snd $ HM.lookup judgment choicesJ
211 let opins = List.head opinsBySection
212 html5Judgment question choices opins
215 H.table ! HA.class_ "document-headers" $$
217 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
218 forM_ series $ \s@Serie{id=id_, name} ->
222 headerName $ html5ify name
223 headerValue $ html5ify id_
225 headerName $ html5ify name
227 H.a ! HA.href (attrify href) $$
229 forM_ links $ \Link{..} ->
230 unless (TL.null $ unName name) $
232 headerName $ html5ify name
233 headerValue $ html5ify $ Tree PlainEref{href} plain
236 headerName $ l10n_Header_Date loc
237 headerValue $ html5ify d
240 headerName $ l10n_Header_Address loc
241 headerValue $ html5ify $ tree0 $ PlainEref{href}
242 forM_ headers $ \Header{..} ->
244 headerName $ html5ify name
245 headerValue $ html5ify value
247 H.table ! HA.class_ "document-authors" $$
249 forM_ authors $ \a ->
251 H.td ! HA.class_ "author" $$
253 header :: Html5 -> Html5
254 header hdr = H.tr ! HA.class_ "header" $$ hdr
255 headerName :: Html5 -> Html5
257 H.td ! HA.class_ "header-name" $$ do
259 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
261 headerValue :: Html5 -> Html5
263 H.td ! HA.class_ "header-value" $$ do
270 , Loqualize locales (L10n Html5)
271 , Loqualize locales (Plain.L10n Plain.Plain)
274 { config_css :: Either FilePath TL.Text
275 , config_locale :: LocaleIn locales
276 , config_generator :: TL.Text
278 instance Default Config where
280 { config_css = Right "style/dtc-html5.css"
281 , config_locale = LocaleIn @'[EN] en_US
282 , config_generator = "https://hackage.haskell.org/package/hdoc"
286 type Html5 = StateMarkup State ()
287 instance IsString Html5 where
288 fromString = html5ify
293 { state_styles :: Map FilePath TL.Text
294 , state_scripts :: Map FilePath TL.Text
295 , state_notes :: Anchor.Notes -- TODO: could be a list
296 , state_judgments :: HS.HashSet Judgment
297 , state_opinions :: HM.HashMap Judgment [MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade)]
299 , state_mapping :: Mapping
300 , state_indexs :: Map Pos (Terms, Index.Irefs) -- TODO: could be a list
301 , state_rrefs :: Anchor.Rrefs
302 , state_plainify :: Plain.State
303 , state_l10n :: Loqualization (L10n Html5)
305 instance Default State where
308 , state_scripts = def
309 , state_mapping = def
313 , state_plainify = def
314 , state_l10n = Loqualization EN_US
315 , state_judgments = HS.empty
316 , state_opinions = def
320 -- | Collect 'Block's by mapping them by their 'Pos' or 'Ident'.
321 data Mapping = Mapping
322 { mapping_index :: Map Pos Terms
323 , mapping_figure :: Map TL.Text (Map Pos (Maybe Title))
324 , mapping_reference :: Map Ident About
325 , mapping_judges :: HM.HashMap Ident [Judge]
326 , mapping_grades :: HM.HashMap Ident [Grade]
327 , mapping_judgments :: HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])]
329 instance Default Mapping where
331 { mapping_index = def
332 , mapping_figure = def
333 , mapping_reference = def
334 , mapping_judges = def
335 , mapping_grades = def
336 , mapping_judgments = def
338 instance Semigroup Mapping where
340 { mapping_index = Map.union (mapping_index x) (mapping_index y)
341 , mapping_figure = Map.unionWith (<>) (mapping_figure x) (mapping_figure y)
342 , mapping_reference = Map.union (mapping_reference x) (mapping_reference y)
343 , mapping_judges = HM.union (mapping_judges x) (mapping_judges y)
344 , mapping_grades = HM.union (mapping_grades x) (mapping_grades y)
345 , mapping_judgments = HM.unionWith (<>) (mapping_judgments x) (mapping_judgments y)
347 instance Monoid Mapping where
351 -- *** Class 'MappingOf'
352 class MappingOf a where
353 mappingOf :: a -> Mapping
354 instance MappingOf Document where
355 mappingOf Document{head=Head{judgments=js}, body} =
356 (foldMap mappingOf body)
357 { mapping_judgments =
358 choicesBySectionByJudgment HM.empty $
359 TreeSeq.Tree (choicesByJudgment js) $
360 choicesByJudgmentBySection body
362 choicesByJudgment :: [Judgment] -> HM.HashMap Judgment (Maybe MJ.Share, [Choice])
363 choicesByJudgment js =
364 HM.fromList $ (<$> js) $ \j@Judgment{..} ->
365 (j,(importance, choices))
366 choicesByJudgmentBySection :: Body -> TreeSeq.Trees (HM.HashMap Judgment (Maybe MJ.Share, [Choice]))
367 choicesByJudgmentBySection bod = bod >>= \(Tree b bs) ->
369 BodyBlock{} -> mempty
370 BodySection{judgments} ->
372 let choicesJ = choicesByJudgment judgments in
374 -- NOTE: if the 'BodySection' has a child which
375 -- is not a 'BodySection' itself, then add "phantom" 'Judgment's
376 -- which will inherit from this 'BodySection'.
377 -- This enables judges to express something on material not in a sub 'BodySection'.
378 let childrenBlocksJudgments =
380 Tree BodyBlock{} _ -> True
382 then Seq.singleton $ Tree ((Nothing,[]) <$ choicesJ) Seq.empty
384 childrenBlocksJudgments <>
385 choicesByJudgmentBySection bs
386 choicesBySectionByJudgment ::
387 HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])] ->
388 TreeSeq.Tree (HM.HashMap Judgment (Maybe MJ.Share, [Choice])) ->
389 HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])]
390 choicesBySectionByJudgment inh (TreeSeq.Tree selfJ childrenJS) =
393 (<$> selfS) $ \(Tree.Node choices old) ->
394 Tree.Node choices (old<>childrenS))
398 selfSJ = (\cs -> [Tree.Node cs []]) <$> selfJ
402 HM.unionWith (<>) accJ $
403 choicesBySectionByJudgment
404 (([Tree.Node (Nothing,[]) []] <$ selfJ) <> inh)
409 instance MappingOf (Tree BodyNode) where
410 mappingOf (Tree n ts) =
412 BodyBlock b -> mappingOf b
413 BodySection{} -> foldMap mappingOf ts
414 instance MappingOf DTC.Block where
416 BlockPara _p -> def -- mappingOf p
420 BlockAside{..} -> foldMap mappingOf blocks
421 BlockIndex{..} -> def{mapping_index = Map.singleton pos terms}
424 Map.singleton type_ (Map.singleton pos mayTitle)}
425 -- <> foldMap mappingOf paras
426 BlockReferences{..} ->
427 def{mapping_reference=
428 Map.fromList $ (<$> refs) $ \DTC.Reference{id=id', ..} -> (id', about)
430 BlockGrades{attrs=CommonAttrs{id=i}, ..} ->
431 def{mapping_grades = HM.singleton (fromMaybe "" i) scale}
432 BlockJudges{attrs=CommonAttrs{id=i}, ..} ->
433 def{mapping_judges = HM.singleton (fromMaybe "" i) jury}
435 instance MappingOf Judgment where
436 mappingOf Judgment{..} = def
437 def{mapping_judgments =
439 (judges,grades,question)
440 (Tree.Node choices [])
442 -- <> foldMap mappingOf choices
443 instance MappingOf Para where
445 ParaItem item -> mappingOf item
446 ParaItems{..} -> foldMap mappingOf items
447 instance MappingOf ParaItem where
451 ParaQuote{..} -> foldMap mappingOf paras
453 ParaOL items -> foldMap mappingOf items
454 ParaUL items -> foldMap (foldMap mappingOf) items
455 ParaJudgment{} -> def
456 instance MappingOf ListItem where
457 mappingOf ListItem{..} = foldMap mappingOf paras
458 instance MappingOf Choice where
459 mappingOf Choice{..} =
460 foldMap mappingOf title <>
461 foldMap mappingOf opinions
462 instance MappingOf Opinion where
463 mappingOf Opinion{..} =
464 foldMap mappingOf comment
465 instance MappingOf Title where
466 mappingOf (Title t) = mappingOf t
467 instance MappingOf Plain where
468 mappingOf = foldMap mappingOf
469 instance MappingOf (Tree PlainNode) where
470 mappingOf (Tree n ts) =
474 PlainGroup -> mappingOf ts
475 PlainB -> mappingOf ts
476 PlainCode -> mappingOf ts
477 PlainDel -> mappingOf ts
478 PlainI -> mappingOf ts
479 PlainSpan{} -> mappingOf ts
480 PlainSub -> mappingOf ts
481 PlainSup -> mappingOf ts
482 PlainSC -> mappingOf ts
483 PlainU -> mappingOf ts
484 PlainNote{..} -> foldMap mappingOf note
485 PlainQ -> mappingOf ts
486 PlainEref{} -> mappingOf ts
487 PlainIref{} -> mappingOf ts
488 PlainRef{} -> mappingOf ts
489 PlainRref{..} -> mappingOf ts
492 -- * Class 'Html5ify'
493 class Html5ify a where
494 html5ify :: a -> Html5
495 instance Html5ify H.Markup where
496 html5ify = Compose . return
497 instance Html5ify Char where
498 html5ify = html5ify . H.toMarkup
499 instance Html5ify Text where
500 html5ify = html5ify . H.toMarkup
501 instance Html5ify TL.Text where
502 html5ify = html5ify . H.toMarkup
503 instance Html5ify String where
504 html5ify = html5ify . H.toMarkup
505 instance Html5ify Title where
506 html5ify (Title t) = html5ify t
507 instance Html5ify Ident where
508 html5ify (Ident i) = html5ify i
509 instance Html5ify Int where
510 html5ify = html5ify . show
511 instance Html5ify Name where
512 html5ify (Name i) = html5ify i
513 instance Html5ify Nat where
514 html5ify (Nat n) = html5ify n
515 instance Html5ify Nat1 where
516 html5ify (Nat1 n) = html5ify n
517 instance Html5ify a => Html5ify (Maybe a) where
518 html5ify = foldMap html5ify
520 -- * Type 'BodyCursor'
521 -- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
522 type BodyCursor = Tree.Zipper BodyNode
523 instance Html5ify Body where
525 forM_ (Tree.zippers body) $ \z ->
526 forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
528 instance Html5ify BodyCursor
530 let Tree b bs = Tree.current z in
532 BodyBlock BlockToC{..} -> do
533 H.nav ! HA.class_ "toc"
534 ! HA.id (attrify $ identify pos) $$ do
535 H.span ! HA.class_ "toc-name" $$
536 H.a ! HA.href (refIdent $ identify pos) $$ do
537 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
538 Plain.l10n_Table_of_Contents loc
540 forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
542 BodyBlock blk -> html5ify blk
543 BodySection{..} -> do
544 st <- liftStateMarkup S.get
547 p <- posParent $ pos_Ancestors pos
548 let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p $ state_notes st
552 Just (secNotes, state_notes) -> do
553 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
555 html5CommonAttrs attrs{classes="section":classes attrs} $
556 H.section ! HA.id (attrify $ identify pos) $$ do
557 forM_ aliases html5ify
559 let sectionJudgments = state_judgments st `HS.union` HS.fromList judgments
560 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
561 let dropChildrenBlocksJudgments =
562 -- NOTE: drop the "phantom" judgments concerning the 'BodyBlock's
563 -- directly children of this 'BodySection'.
565 Tree BodyBlock{} _ -> True
569 liftStateMarkup $ S.modify' $ \s ->
570 s{ state_judgments = sectionJudgments
572 -- NOTE: drop current opinions of the judgments of this section
573 HM.unionWith (const $ List.tail . dropChildrenBlocksJudgments)
575 opinsBySectionByJudgment
577 unless (null opinsBySectionByJudgment) $ do
578 H.aside ! HA.class_ "aside" $$ do
579 let choicesJ = choicesByJudgment judgments
580 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
581 H.div ! HA.class_ "judgment section-judgment" $$ do
582 let choices = maybe [] snd $ HM.lookup judgment choicesJ
583 let opins = List.head opinsBySection
584 html5Judgment question choices opins
586 ! HA.id (attrify $ escapeIdent $ identify title)
587 ! HA.class_ "section-header" $$
590 H.td ! HA.class_ "section-number" $$ do
591 html5SectionNumber $ pos_Ancestors pos
592 H.td ! HA.class_ "section-title" $$ do
593 (case List.length $ pos_Ancestors pos of
602 forM_ (Tree.axis_child `Tree.runAxis` z) $
605 liftStateMarkup $ S.modify' $ \s ->
606 s{ state_judgments = state_judgments st }
608 notes <- liftStateMarkup $ S.gets state_notes
609 html5ify $ Map.lookup (pos_Ancestors pos) notes
610 instance Html5ify [Anchor.Note] where
612 H.aside ! HA.class_ "notes" $$ do
616 forM_ (List.reverse notes) $ \Anchor.Note{..} ->
618 H.td ! HA.class_ "note-ref" $$ do
619 H.a ! HA.class_ "note-number"
620 ! HA.id ("note."<>attrify note_number)
621 ! HA.href ("#note."<>attrify note_number) $$ do
624 H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
627 html5ify note_content
628 instance Html5ify Block where
630 BlockPara para -> html5ify para
632 html5CommonAttrs attrs
633 { classes = "page-break":"print-only":classes attrs } $
635 H.p $$ " " -- NOTE: force page break
636 BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
638 H.nav ! HA.class_ "tof"
639 ! HA.id (attrify $ identify pos) $$
640 H.table ! HA.class_ "tof" $$
644 html5CommonAttrs attrs $
645 H.aside ! HA.class_ "aside" $$ do
646 forM_ blocks html5ify
648 html5CommonAttrs attrs
649 { classes = "figure":("figure-"<>type_):classes attrs
650 , DTC.id = Just $ Ident $ Plain.text def $ pos_AncestorsWithFigureNames pos
653 H.table ! HA.class_ "figure-caption" $$
657 then H.a ! HA.href (refIdent $ identify pos) $$ mempty
659 H.td ! HA.class_ "figure-number" $$ do
660 H.a ! HA.href (refIdent $ identify $ pos_AncestorsWithFigureNames pos) $$ do
662 html5ify $ pos_AncestorsWithFigureNames pos
663 forM_ mayTitle $ \title -> do
664 H.td ! HA.class_ "figure-colon" $$ do
665 unless (TL.null type_) $ do
666 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
668 H.td ! HA.class_ "figure-title" $$ do
670 H.div ! HA.class_ "figure-content" $$ do
672 BlockIndex{pos} -> do
673 (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
674 let chars = Index.termsByChar allTerms
675 H.div ! HA.class_ "index"
676 ! HA.id (attrify $ identify pos) $$ do
677 H.nav ! HA.class_ "index-nav" $$ do
678 forM_ (Map.keys chars) $ \char ->
679 H.a ! HA.href (refIdent (identify pos <> "." <> identify char)) $$
681 H.dl ! HA.class_ "index-chars" $$
682 forM_ (Map.toList chars) $ \(char,terms) -> do
684 let i = identify pos <> "." <> identify char
685 H.a ! HA.id (attrify i)
686 ! HA.href (refIdent i) $$
689 H.dl ! HA.class_ "index-term" $$ do
690 forM_ terms $ \aliases -> do
692 H.ul ! HA.class_ "index-aliases" $$
693 forM_ (List.take 1 aliases) $ \term -> do
694 H.li ! HA.id (attrify $ identifyIref term) $$
698 List.sortBy (compare `on` DTC.section . snd) $
699 (`foldMap` aliases) $ \words ->
701 path <- Index.pathFromWords words
702 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
703 TreeMap.lookup path refsByTerm in
705 (<$> anchs) $ \(term,DTC.Anchor{..}) ->
706 H.a ! HA.class_ "index-iref"
707 ! HA.href (refIdent $ identifyIrefCount term count) $$
708 html5ify $ pos_Ancestors section
709 BlockReferences{..} ->
710 html5CommonAttrs attrs
711 { classes = "references":classes attrs
712 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
718 html5CommonAttrs attrs
719 { classes = "grades":classes attrs
720 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
723 -- let dg = List.head $ List.filter default_ scale
724 -- let sc = MJ.Scale (Set.fromList scale) dg
725 -- o :: Map choice grade
726 -- os :: Opinions (Map judge (Opinion choice grade))
730 html5CommonAttrs attrs
731 { classes = "judges":classes attrs
732 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
737 html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
738 html5ifyToC depth z =
739 let Tree n _ts = Tree.current z in
741 BodySection{..} -> do
743 H.table ! HA.class_ "toc-entry" $$
746 H.td ! HA.class_ "section-number" $$
747 html5SectionRef $ pos_Ancestors pos
748 H.td ! HA.class_ "section-title" $$
749 html5ify $ cleanPlain $ unTitle title
750 when (maybe True (> Nat 1) depth && not (null sections)) $
753 html5ifyToC (depth >>= predNat)
759 `Tree.axis_filter_current` \case
760 Tree BodySection{} _ -> True
763 html5ifyToF :: [TL.Text] -> Html5
764 html5ifyToF types = do
765 figuresByType <- liftStateMarkup $ S.gets $ mapping_figure . state_mapping
767 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
771 Map.intersection figuresByType $
772 Map.fromList [(ty,()) | ty <- types]
773 forM_ (Map.toList figures) $ \(pos, (type_, title)) ->
775 H.td ! HA.class_ "figure-number" $$
776 H.a ! HA.href (refIdent $ identify pos) $$ do
778 html5ify $ pos_Ancestors pos
780 H.td ! HA.class_ "figure-title" $$
781 html5ify $ cleanPlain $ unTitle ti
783 cleanPlain :: Plain -> Plain
786 Tree PlainIref{} ls -> cleanPlain ls
787 Tree PlainNote{} _ -> mempty
788 Tree n ts -> pure $ Tree n $ cleanPlain ts
790 instance Html5ify Para where
794 { classes="para":cls item
798 html5CommonAttrs attrs
799 { classes = "para":classes attrs
803 forM_ items $ \item ->
804 html5AttrClass (cls item) $
807 id_ = Just . Ident . Plain.text def . pos_Ancestors
810 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
811 ParaQuote{..} -> ["quote", "quote-"<>type_]
815 ParaJudgment{} -> ["judgment"]
816 instance Html5ify ParaItem where
818 ParaPlain p -> H.p $$ html5ify p
819 ParaArtwork{..} -> H.pre $$ do html5ify text
820 ParaQuote{..} -> H.div $$ do html5ify paras
821 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
825 forM_ items $ \ListItem{..} -> do
827 H.td ! HA.class_ "name" $$ do
830 H.td ! HA.class_ "value" $$
834 forM_ items $ \item -> do
836 H.dd $$ html5ify item
837 ParaJudgment j -> html5ify j
838 instance Html5ify Judgment where
839 html5ify Judgment{..} = do
840 st <- liftStateMarkup S.get
843 maybe (error $ show grades) MJ.grades $ -- unknown grades
844 HM.lookup grades (mapping_grades $ state_mapping st)
846 fromMaybe (error $ show judges) $ -- unknown judges
847 HM.lookup judges (mapping_judges $ state_mapping st)
848 let defaultGradeByJudge =
851 [ g | g <- Set.toList judgmentGrades
852 , isDefault $ MJ.unRank g
855 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
856 | DTC.Judge{name,defaultGrades} <- judgmentJudges
857 , let judgeDefaultGrade = do
858 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
860 [ g | g <- Set.toList judgmentGrades
861 , let DTC.Grade{name=n} = MJ.unRank g
865 judgmentChoices <- forM choices $ \c@DTC.Choice{opinions} -> do
866 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade} -> do
868 fromMaybe (error $ show grade) $ -- unknown grade
870 [ MJ.singleGrade g | g <- Set.toList judgmentGrades
871 , let Grade{name} = MJ.unRank g
875 case MJ.opinions defaultGradeByJudge $ HM.fromList gradeByJudge of
876 (ok,ko) | null ko -> return (c, ok)
877 | otherwise -> error $ show ko -- unknown judge
879 html5Judgment question choices $ HM.fromList judgmentChoices
884 MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade) ->
886 html5Judgment question choices distByJudgeByChoice = do
887 let commentJGC = HM.fromList
888 [ (choice_, HM.fromListWith (<>)
889 [ (grade, HM.singleton judge comment)
890 | Opinion{..} <- opinions ])
891 | choice_@Choice{opinions} <- choices ]
894 Just title -> H.div ! HA.class_ "question" $$ html5ify title
895 H.dl ! HA.class_ "choices" $$ do
896 let meritByChoice@(MJ.MeritByChoice meritC) = MJ.meritByChoice distByJudgeByChoice
897 let ranking = MJ.majorityRanking meritByChoice
898 forM_ ranking $ \(choice_@DTC.Choice{title}, majorityValue) -> do
899 H.dt ! HA.class_ "choice-title" $$ do
901 H.dd ! HA.class_ "choice-merit" $$ do
902 let distByJudge = distByJudgeByChoice HM.!choice_
903 let numJudges = HM.size distByJudge
904 html5MeritHistogram majorityValue numJudges
905 let grades = Map.keys $ MJ.unMerit $ meritC HM.!choice_
906 let commentJG = HM.lookup choice_ commentJGC
907 html5MeritComments distByJudge grades commentJG
909 html5MeritComments ::
910 MJ.Opinions Name (MJ.Ranked Grade) ->
912 Maybe (HM.HashMap Name (HM.HashMap Name (Maybe Title))) ->
914 html5MeritComments distJ grades commentJG = do
915 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
916 H.ul ! HA.class_ "merit-comments" $$ do
917 forM_ grades $ \grade@(MJ.unRank -> DTC.Grade{name=grade_name, color}) -> do
918 let commentJ = commentJG >>= HM.lookup grade_name
919 let judgesWithComment =
920 -- FIXME: sort accents better: « e é f » not « e f é »
921 List.sortOn (TL.map Char.toLower . unName . (\(j,_,_) -> j))
922 [ (judge, importance, commentJ >>= HM.lookupDefault Nothing judge)
923 | (judge, dist) <- HM.toList distJ
924 , importance <- maybeToList $ Map.lookup grade dist ]
925 forM_ judgesWithComment $ \(judge, importance, comment) ->
926 H.li ! HA.class_ ("merit-comment" <> if isJust comment then " judge-comment" else "") $$ do
928 ! HA.class_ ("judge" <> if judge`HM.member`fromMaybe HM.empty commentJ then "" else " inactive")
929 ! HA.style ("color:"<>attrify color<>";") $$ do
930 unless (importance == 1) $ do
931 H.span ! HA.class_ "section-importance" $$ do
933 (round::Double -> Int) $
934 fromRational $ importance * 100
935 html5ify $ show percent
941 Plain.l10n_Colon loc :: Html5
944 html5MeritHistogram :: MJ.MajorityValue (MJ.Ranked Grade) -> Int -> Html5
945 html5MeritHistogram (MJ.MajorityValue majVal) numJudges = do
946 H.div ! HA.class_ "merit-histogram" $$ do
947 forM_ majVal $ \(MJ.unRank -> DTC.Grade{name=grade_name, title=grade_title, color},count) -> do
948 let percent :: Double =
949 fromRational $ (toRational $ (ceiling::Double -> Int) $ fromRational $
950 (count / toRational numJudges) * 100 * 1000) / 1000
951 let bcolor = "background-color:"<>attrify color<>";"
952 let width = "width:"<>attrify percent<>"%;"
953 let display = if percent == 0 then "display:none;" else ""
955 ! HA.class_ "merit-grade"
956 ! HA.alt (attrify grade_name) -- FIXME: do not work
957 ! HA.style (bcolor<>display<>width) $$ do
959 ! HA.class_ "grade-name" $$ do
961 Nothing -> html5ify grade_name
964 html5Judgments :: Html5
966 Mapping{..} :: Mapping <- liftStateMarkup $ S.gets state_mapping
967 opinionsByChoiceByNodeBySectionByJudgment <-
968 forM (HM.toList mapping_judgments) $ \(judgment@Judgment{judges,grades}, choicesBySection) -> do
969 -- WARNING: only the fields of 'Judgment' used in its 'Hashable' instance
970 -- can safely be used here: 'judges' and 'grades' are ok
972 maybe (error $ show grades) MJ.grades $ -- unknown grades
973 HM.lookup grades mapping_grades
975 fromMaybe (error $ show judges) $ -- unknown judges
976 HM.lookup judges mapping_judges
977 let defaultGradeByJudge =
980 [ g | g <- Set.toList judgmentGrades
981 , isDefault $ MJ.unRank g
984 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
985 | DTC.Judge{name,defaultGrades} <- judgmentJudges
986 , let judgeDefaultGrade = do
987 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
989 [ g | g <- Set.toList judgmentGrades
990 , let DTC.Grade{name=n} = MJ.unRank g
994 opinionsByChoiceByNodeBySection <-
995 forM choicesBySection $ \choicesTree -> do
996 judgmentTree <- forM choicesTree $ \(section_importance, choices) -> do
997 judgmentOpinions <- forM choices $ \choice_@DTC.Choice{opinions} -> do
998 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade,importance} -> do
1000 [ g | g <- Set.toList judgmentGrades
1001 , let Grade{name} = MJ.unRank g
1004 Just grd -> return (judge, MJ.Section importance (Just grd))
1005 Nothing -> error $ show grade -- unknown grade
1006 return (choice_, HM.fromList gradeByJudge)
1007 return $ MJ.SectionNode section_importance $ HM.fromList judgmentOpinions
1008 let judgmentChoices = HS.fromList $ snd $ Tree.rootLabel choicesTree
1009 -- NOTE: choices are determined by those at the root Tree.Node.
1010 -- NOTE: core Majority Judgment calculus handled here by MJ
1011 case MJ.opinionsBySection judgmentChoices defaultGradeByJudge judgmentTree of
1012 Right opinionsByChoiceByNode -> return opinionsByChoiceByNode
1013 Left err -> error $ show err -- unknown choice, unknown judge, invalid shares
1014 -- NOTE: 'toList' returns a self-then-descending-then-following traversal of a 'Tree',
1015 -- this will match perfectly withw the 'html5ify' traversal:
1016 -- 'BodySection' by 'BodySection'.
1017 return (judgment, join $ toList <$> opinionsByChoiceByNodeBySection)
1018 liftStateMarkup $ S.modify' $ \st ->
1019 st{state_opinions = HM.fromList opinionsByChoiceByNodeBySectionByJudgment}
1021 instance Html5ify [Para] where
1022 html5ify = mapM_ html5ify
1023 instance Html5ify Plain where
1025 case Seq.viewl ps of
1026 Seq.EmptyL -> mempty
1029 -- NOTE: gather adjacent PlainNotes
1031 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
1032 H.sup ! HA.class_ "note-numbers" $$ do
1034 forM_ notes $ \note -> do
1043 instance Html5ify (Tree PlainNode)
1044 where html5ify (Tree n ls) =
1046 PlainBreak -> html5ify H.br
1047 PlainText t -> html5ify t
1048 PlainGroup -> html5ify ls
1049 PlainB -> H.strong $$ html5ify ls
1050 PlainCode -> H.code $$ html5ify ls
1051 PlainDel -> H.del $$ html5ify ls
1053 i <- liftStateMarkup $ do
1054 i <- S.gets $ Plain.state_italic . state_plainify
1057 (state_plainify s){Plain.state_italic=
1060 H.em ! HA.class_ (if i then "even" else "odd") $$
1065 (state_plainify s){Plain.state_italic=i}}
1067 html5CommonAttrs attrs $
1068 H.span $$ html5ify ls
1069 PlainSub -> H.sub $$ html5ify ls
1070 PlainSup -> H.sup $$ html5ify ls
1071 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
1072 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
1077 H.a ! HA.class_ "note-ref"
1078 ! HA.id ("note-ref."<>attrify num)
1079 ! HA.href ("#note."<>attrify num) $$
1082 H.span ! HA.class_ "q" $$ do
1083 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1084 Plain.l10n_Quote (html5ify $ Tree PlainI ls) loc
1086 H.a ! HA.class_ "eref"
1087 ! HA.href (attrify href) $$
1089 then html5ify $ unURL href
1093 Nothing -> html5ify ls
1095 H.span ! HA.class_ "iref"
1096 ! HA.id (attrify $ identifyIrefCount term count) $$
1099 H.a ! HA.class_ "ref"
1100 ! HA.href (refIdent $ escapeIdent to) $$
1102 then html5ify $ unIdent to
1105 refs <- liftStateMarkup $ S.gets $ mapping_reference . state_mapping
1106 case Map.lookup to refs of
1109 H.span ! HA.class_ "rref-broken" $$
1112 Just About{..} -> do
1114 forM_ (List.take 1 titles) $ \(Title title) -> do
1115 html5ify $ Tree PlainQ $
1118 Just u -> pure $ Tree (PlainEref u) title
1121 H.a ! HA.class_ "rref"
1122 ! HA.href ("#rref."<>attrify to)
1123 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
1126 instance Html5ify [Title] where
1128 html5ify . fold . List.intersperse sep . toList
1129 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
1130 instance Html5ify About where
1131 html5ify About{..} = do
1133 [ html5CommasDot $ concat $
1134 [ html5Titles titles
1135 , html5ify <$> authors
1136 , html5ify <$> maybeToList date
1137 , html5ify <$> maybeToList editor
1138 , html5ify <$> series
1141 H.span ! HA.class_ "print-only" $$ do
1147 html5Titles :: [Title] -> [Html5]
1148 html5Titles ts | null ts = []
1149 html5Titles ts = [html5Title $ joinTitles ts]
1151 joinTitles = fold . List.intersperse sep . toList
1152 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
1153 html5Title (Title title) =
1154 html5ify $ Tree PlainQ $
1157 Just u -> pure $ Tree (PlainEref u) title
1158 instance Html5ify Serie where
1159 html5ify s@Serie{id=id_, name} = do
1160 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1164 Plain.l10n_Colon loc :: Html5
1168 Tree PlainEref{href} $
1170 [ tree0 $ PlainText $ unName name
1171 , tree0 $ PlainText $ Plain.l10n_Colon loc
1172 , tree0 $ PlainText id_
1174 instance Html5ify Entity where
1175 html5ify Entity{..} = do
1177 _ | not (TL.null email) -> do
1178 H.span ! HA.class_ "no-print" $$
1180 Tree (PlainEref $ URL $ "mailto:"<>email) $
1181 pure $ tree0 $ PlainText name
1182 H.span ! HA.class_ "print-only" $$
1184 Tree PlainGroup $ Seq.fromList
1185 [ tree0 $ PlainText name
1186 , tree0 $ PlainText " <"
1187 , Tree (PlainEref $ URL $ "mailto:"<>email) $
1188 pure $ tree0 $ PlainText email
1189 , tree0 $ PlainText ">"
1191 _ | Just u <- url ->
1193 Tree (PlainEref u) $
1194 pure $ tree0 $ PlainText name
1197 tree0 $ PlainText name
1198 forM_ org $ \o -> do
1202 instance Html5ify Words where
1203 html5ify = html5ify . Index.plainifyWords
1204 instance Html5ify Alias where
1205 html5ify Alias{id=id_, ..} = do
1206 H.a ! HA.class_ "alias"
1207 ! HA.id (attrify $ identify id_) $$
1209 instance Html5ify URL where
1210 html5ify (URL url) =
1211 H.a ! HA.class_ "eref"
1212 ! HA.href (attrify url) $$
1214 instance Html5ify Date where
1216 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1217 Plain.l10n_Date date loc
1218 instance Html5ify Reference where
1219 html5ify Reference{id=id_, ..} =
1221 H.td ! HA.class_ "reference-key" $$
1222 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
1223 H.td ! HA.class_ "reference-content" $$ do
1225 rrefs <- liftStateMarkup $ S.gets state_rrefs
1226 case Map.lookup id_ rrefs of
1229 H.span ! HA.class_ "reference-rrefs" $$
1231 (<$> List.reverse anchs) $ \Anchor{..} ->
1232 H.a ! HA.class_ "reference-rref"
1233 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
1234 html5ify $ pos_Ancestors section
1235 instance Html5ify PosPath where
1243 Text.intercalate "." $
1244 Text.pack . show . snd <$> as
1245 instance Html5ify Plain.Plain where
1247 sp <- liftStateMarkup $ S.gets state_plainify
1248 let (t,sp') = Plain.runPlain p sp
1250 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
1252 instance Html5ify SVG.Element where
1255 B.preEscapedLazyText $
1257 instance Semigroup SVG.Element where
1261 html5CommasDot :: [Html5] -> Html5
1262 html5CommasDot [] = pure ()
1263 html5CommasDot hs = do
1264 sequence_ $ List.intersperse ", " hs
1267 html5Lines :: [Html5] -> Html5
1268 html5Lines hs = sequence_ $ List.intersperse (html5ify H.br) hs
1270 html5Words :: [Html5] -> Html5
1271 html5Words hs = sequence_ $ List.intersperse " " hs
1273 html5AttrClass :: [TL.Text] -> Html5 -> Html5
1274 html5AttrClass = \case
1278 (H.AddCustomAttribute "class"
1279 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
1282 html5AttrId :: Ident -> Html5 -> Html5
1283 html5AttrId (Ident id_) =
1285 (H.AddCustomAttribute "id"
1286 (H.String $ TL.unpack id_) <$>) .
1289 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
1290 html5CommonAttrs CommonAttrs{id=id_, ..} =
1291 html5AttrClass classes .
1292 maybe Cat.id html5AttrId id_
1294 html5SectionNumber :: PosPath -> Html5
1295 html5SectionNumber = go mempty
1297 go :: PosPath -> PosPath -> Html5
1299 case Seq.viewl next of
1300 Seq.EmptyL -> pure ()
1301 a@(_n,rank) Seq.:< as -> do
1302 H.a ! HA.href (refIdent $ identify $ prev Seq.|> a) $$
1303 html5ify $ show rank
1304 when (not (null as) || null prev) $ do
1306 go (prev Seq.|>a) as
1308 html5SectionRef :: PosPath -> Html5
1309 html5SectionRef as =
1310 H.a ! HA.href (refIdent $ identify as) $$
1313 -- * Class 'Identify'
1314 class Identify a where
1315 identify :: a -> Ident
1316 instance Identify Char where
1317 identify = Ident . TL.singleton
1318 instance Identify String where
1319 identify = Ident . TL.pack
1320 instance Identify TL.Text where
1322 instance Identify (Tree PlainNode) where
1323 identify (Tree n ls) =
1325 PlainBreak -> identify '\n'
1326 PlainText t -> identify t
1327 PlainGroup -> identify ls
1328 PlainB -> identify ls
1329 PlainCode -> identify ls
1330 PlainDel -> identify ls
1331 PlainI -> identify ls
1332 PlainSpan{} -> identify ls
1333 PlainSub -> identify ls
1334 PlainSup -> identify ls
1335 PlainSC -> identify ls
1336 PlainU -> identify ls
1338 PlainQ -> identify ls
1339 PlainEref{} -> identify ls
1340 PlainIref{} -> identify ls
1341 PlainRef{} -> identify ls
1342 PlainRref{..} -> identify to
1343 instance Identify Ident where
1344 identify (Ident p) = identify p
1345 instance Identify Plain where
1346 identify = foldMap identify
1347 instance Identify Title where
1348 identify (Title p) = identify p
1349 instance Identify PosPath where
1352 snd . foldl' (\(nameParent,acc) (name,rank) ->
1354 (if TL.null $ unIdent acc then acc else acc <> ".") <>
1355 (if name == nameParent
1356 then identify (show rank)
1357 else escapeIdentTail $ identify (show name)<>identify (show rank))
1361 instance Identify Pos where
1362 identify = identify . pos_Ancestors
1363 instance Identify Path where
1364 identify (Path a) = identify a
1365 instance Identify Int where
1366 identify = fromString . show
1367 instance Identify Nat where
1368 identify (Nat a) = identify a
1369 instance Identify Nat1 where
1370 identify (Nat1 a) = identify a
1371 instance Identify Anchor where
1372 identify Anchor{..} = identify section <> "." <> identify count
1374 refIdent :: Ident -> H.AttributeValue
1375 refIdent i = "#"<>attrify i
1377 escapeIdent :: Ident -> Ident
1378 escapeIdent = escapeIdentHead . escapeIdentTail
1379 escapeIdentHead :: Ident -> Ident
1380 escapeIdentHead (Ident i) = Ident i
1381 escapeIdentTail :: Ident -> Ident
1382 escapeIdentTail (Ident i) =
1385 (\c accum -> (<> accum) $ case c of
1387 _ | Char.isAlphaNum c
1392 enc = TL.encodeUtf8 $ TL.singleton c
1393 bytes = BS.foldr (\b acc -> escape b<>acc) "" enc
1394 escape = TL.Builder.toLazyText . TL.Builder.hexadecimal
1397 identifyIref :: Words -> Ident
1399 "iref" <> "." <> identify (Index.plainifyWords term)
1400 identifyIrefCount :: Words -> Nat1 -> Ident
1401 identifyIrefCount term count =
1403 <> "." <> identify (Index.plainifyWords term)
1404 <> "." <> identify count
1407 instance Attrify Plain.Plain where
1408 attrify p = attrify t
1409 where (t,_) = Plain.runPlain p def
1413 ( Plain.L10n msg lang
1414 , Plain.L10n TL.Text lang
1415 ) => L10n msg lang where
1416 l10n_Header_Address :: FullLocale lang -> msg
1417 l10n_Header_Date :: FullLocale lang -> msg
1418 l10n_Header_Version :: FullLocale lang -> msg
1419 l10n_Header_Origin :: FullLocale lang -> msg
1420 l10n_Header_Source :: FullLocale lang -> msg
1421 instance L10n Html5 EN where
1422 l10n_Header_Address _loc = "Address"
1423 l10n_Header_Date _loc = "Date"
1424 l10n_Header_Origin _loc = "Origin"
1425 l10n_Header_Source _loc = "Source"
1426 l10n_Header_Version _loc = "Version"
1427 instance L10n Html5 FR where
1428 l10n_Header_Address _loc = "Adresse"
1429 l10n_Header_Date _loc = "Date"
1430 l10n_Header_Origin _loc = "Origine"
1431 l10n_Header_Source _loc = "Source"
1432 l10n_Header_Version _loc = "Version"
1434 instance Plain.L10n Html5 EN where
1435 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
1436 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
1437 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
1438 l10n_Quote msg _loc = do
1439 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1440 let (o,c) :: (Html5, Html5) =
1441 case unNat depth `mod` 3 of
1446 setDepth $ succNat depth
1452 liftStateMarkup $ S.modify' $ \s ->
1453 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
1454 instance Plain.L10n Html5 FR where
1455 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
1456 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
1457 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
1458 l10n_Quote msg _loc = do
1459 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1460 let (o,c) :: (Html5, Html5) =
1461 case unNat depth `mod` 3 of
1466 setDepth $ succNat depth
1472 liftStateMarkup $ S.modify' $ \s ->
1473 s{state_plainify=(state_plainify s){Plain.state_quote=d}}