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.Anchor as Anchor
74 import qualified Hdoc.DTC.Write.Plain as Plain
77 debug :: Show a => String -> a -> a
78 debug msg a = trace (msg<>": "<>show a) a
79 debugOn :: Show b => String -> (a -> b) -> a -> a
80 debugOn msg get a = trace (msg<>": "<>show (get a)) a
81 debugWith :: String -> (a -> String) -> a -> a
82 debugWith msg get a = trace (msg<>": "<>get a) a
84 showJudgments :: HM.HashMap (Ident,Ident,Maybe Title) [Tree.Tree [Choice]] -> String
88 -- Tree.Node (Left ("","",Nothing)) $
89 (<$> HM.toList js) $ \((j,g,q),ts) ->
91 (Left (unIdent j,unIdent g,Plain.text def <$> q))
94 writeHTML5 :: Config -> DTC.Document -> Html
95 writeHTML5 conf@Config{..} doc@DTC.Document{..} = do
96 let state_mapping@Mapping{..} :: Mapping = mappingOf doc
97 let (body',state_rrefs,state_notes,state_indexs) =
98 let irefs = foldMap Anchor.irefsOfTerms mapping_index in
99 let (body0, Anchor.State{state_irefs, state_rrefs=rrefs, state_notes=notes}) =
100 Anchor.anchorify body `S.runState`
101 def{Anchor.state_irefs=irefs} in
102 (body0,rrefs,notes,) $
103 (<$> mapping_index) $ \terms ->
105 TreeMap.intersection const state_irefs $
106 Anchor.irefsOfTerms terms
107 let state_plainify = def{Plain.state_l10n = loqualize config_locale}
108 let (html5Body, endState) =
115 , state_l10n = loqualize config_locale
118 html5DocumentHead head
121 H.html ! HA.lang (attrify $ countryCode config_locale) $ do
122 html5Head conf endState head body
125 html5Head :: Config -> State -> Head -> Body -> Html
126 html5Head Config{..} State{..} Head{DTC.about=About{..}} body = do
128 H.meta ! HA.httpEquiv "Content-Type"
129 ! HA.content "text/html; charset=UTF-8"
130 unless (null titles) $ do
132 H.toMarkup $ Plain.text state_plainify $ List.head titles
133 forM_ links $ \Link{..} ->
135 "stylesheet" | URL "" <- href ->
136 H.style ! HA.type_ "text/css" $
137 H.toMarkup $ Plain.text def plain
139 H.link ! HA.rel (attrify rel)
140 ! HA.href (attrify href)
142 H.link ! HA.rel "self"
143 ! HA.href (attrify href)
144 unless (TL.null config_generator) $ do
145 H.meta ! HA.name "generator"
146 ! HA.content (attrify config_generator)
148 H.meta ! HA.name "keywords"
149 ! HA.content (attrify $ TL.intercalate ", " tags)
151 (`mapMaybe` toList body) $ \case
152 Tree k@BodySection{} _ -> Just k
154 forM_ chapters $ \case
156 H.link ! HA.rel "Chapter"
157 ! HA.title (attrify $ plainify title)
158 ! HA.href (refIdent $ identify pos)
160 unless (any (\DTC.Link{..} -> rel == "stylesheet" && href /= URL "") links) $ do
164 H.link ! HA.rel "stylesheet"
165 ! HA.type_ "text/css"
166 ! HA.href (attrify css)
168 H.style ! HA.type_ "text/css" $
169 -- NOTE: as a special case, H.style wraps its content into an External,
170 -- so it does not HTML-escape its content.
172 forM_ state_styles $ \style ->
173 H.style ! HA.type_ "text/css" $
175 unless (any (\DTC.Link{rel} -> rel == "script") links) $ do
176 forM_ state_scripts $ \script ->
177 H.script ! HA.type_ "application/javascript" $
180 html5DocumentHead :: Head -> Html5
181 html5DocumentHead Head{DTC.about=About{..}, judgments} = do
182 unless (null authors) $ do
183 H.div ! HA.class_ "document-head" $$
187 H.td ! HA.class_ "left" $$ docHeaders
188 H.td ! HA.class_ "right" $$ docAuthors
189 unless (null titles) $
190 H.div ! HA.class_ "title" $$ do
191 forM_ titles $ \title ->
192 H.h1 $$ html5ify title
193 st <- liftStateMarkup S.get
195 let sectionJudgments = HS.fromList judgments
196 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
197 liftStateMarkup $ S.modify' $ \s ->
198 s{ state_judgments = sectionJudgments
200 -- NOTE: drop current opinions of the judgments of this section
201 HM.unionWith (const List.tail)
203 opinsBySectionByJudgment
205 unless (null opinsBySectionByJudgment) $ do
206 let choicesJ = choicesByJudgment judgments
207 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
208 H.div ! HA.class_ "judgment section-judgment document-judgment" $$ do
209 let choices = maybe [] snd $ HM.lookup judgment choicesJ
210 let opins = List.head opinsBySection
211 html5Judgment question choices opins
214 H.table ! HA.class_ "document-headers" $$
216 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
217 forM_ series $ \s@Serie{id=id_, name} ->
221 headerName $ html5ify name
222 headerValue $ html5ify id_
224 headerName $ html5ify name
226 H.a ! HA.href (attrify href) $$
228 forM_ links $ \Link{..} ->
229 unless (TL.null $ unName name) $
231 headerName $ html5ify name
232 headerValue $ html5ify $ Tree PlainEref{href} plain
235 headerName $ l10n_Header_Date loc
236 headerValue $ html5ify d
239 headerName $ l10n_Header_Address loc
240 headerValue $ html5ify $ tree0 $ PlainEref{href}
241 forM_ headers $ \Header{..} ->
243 headerName $ html5ify name
244 headerValue $ html5ify value
246 H.table ! HA.class_ "document-authors" $$
248 forM_ authors $ \a ->
250 H.td ! HA.class_ "author" $$
252 header :: Html5 -> Html5
253 header hdr = H.tr ! HA.class_ "header" $$ hdr
254 headerName :: Html5 -> Html5
256 H.td ! HA.class_ "header-name" $$ do
258 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
260 headerValue :: Html5 -> Html5
262 H.td ! HA.class_ "header-value" $$ do
269 , Loqualize locales (L10n Html5)
270 , Loqualize locales (Plain.L10n Plain.Plain)
273 { config_css :: Either FilePath TL.Text
274 , config_locale :: LocaleIn locales
275 , config_generator :: TL.Text
277 instance Default Config where
279 { config_css = Right "style/dtc-html5.css"
280 , config_locale = LocaleIn @'[EN] en_US
281 , config_generator = "https://hackage.haskell.org/package/hdoc"
285 type Html5 = StateMarkup State ()
286 instance IsString Html5 where
287 fromString = html5ify
292 { state_styles :: Map FilePath TL.Text
293 , state_scripts :: Map FilePath TL.Text
294 , state_notes :: Anchor.Notes -- TODO: could be a list
295 , state_judgments :: HS.HashSet Judgment
296 , state_opinions :: HM.HashMap Judgment [MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade)]
298 , state_mapping :: Mapping
299 , state_indexs :: Map Pos (Terms, Anchor.Irefs) -- TODO: could be a list
300 , state_rrefs :: Anchor.Rrefs
301 , state_plainify :: Plain.State
302 , state_l10n :: Loqualization (L10n Html5)
304 instance Default State where
307 , state_scripts = def
308 , state_mapping = def
312 , state_plainify = def
313 , state_l10n = Loqualization EN_US
314 , state_judgments = HS.empty
315 , state_opinions = def
319 -- | Collect 'Block's by mapping them by their 'Pos' or 'Ident'.
320 data Mapping = Mapping
321 { mapping_index :: Map Pos Terms
322 , mapping_figure :: Map TL.Text (Map Pos (Maybe Title))
323 , mapping_reference :: Map Ident About
324 , mapping_judges :: HM.HashMap Ident [Judge]
325 , mapping_grades :: HM.HashMap Ident [Grade]
326 , mapping_judgments :: HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])]
328 instance Default Mapping where
330 { mapping_index = def
331 , mapping_figure = def
332 , mapping_reference = def
333 , mapping_judges = def
334 , mapping_grades = def
335 , mapping_judgments = def
337 instance Semigroup Mapping where
339 { mapping_index = Map.union (mapping_index x) (mapping_index y)
340 , mapping_figure = Map.unionWith (<>) (mapping_figure x) (mapping_figure y)
341 , mapping_reference = Map.union (mapping_reference x) (mapping_reference y)
342 , mapping_judges = HM.union (mapping_judges x) (mapping_judges y)
343 , mapping_grades = HM.union (mapping_grades x) (mapping_grades y)
344 , mapping_judgments = HM.unionWith (<>) (mapping_judgments x) (mapping_judgments y)
346 instance Monoid Mapping where
350 -- *** Class 'MappingOf'
351 class MappingOf a where
352 mappingOf :: a -> Mapping
353 instance MappingOf Document where
354 mappingOf Document{head=Head{judgments=js}, body} =
355 (foldMap mappingOf body)
356 { mapping_judgments =
357 choicesBySectionByJudgment HM.empty $
358 TreeSeq.Tree (choicesByJudgment js) $
359 choicesByJudgmentBySection body
361 choicesByJudgment :: [Judgment] -> HM.HashMap Judgment (Maybe MJ.Share, [Choice])
362 choicesByJudgment js =
363 HM.fromList $ (<$> js) $ \j@Judgment{..} ->
364 (j,(importance, choices))
365 choicesByJudgmentBySection :: Body -> TreeSeq.Trees (HM.HashMap Judgment (Maybe MJ.Share, [Choice]))
366 choicesByJudgmentBySection bod = bod >>= \(Tree b bs) ->
368 BodyBlock{} -> mempty
369 BodySection{judgments} ->
371 let choicesJ = choicesByJudgment judgments in
373 -- NOTE: if the 'BodySection' has a child which
374 -- is not a 'BodySection' itself, then add "phantom" 'Judgment's
375 -- which will inherit from this 'BodySection'.
376 -- This enables judges to express something on material not in a sub 'BodySection'.
377 let childrenBlocksJudgments =
379 Tree BodyBlock{} _ -> True
381 then Seq.singleton $ Tree ((Nothing,[]) <$ choicesJ) Seq.empty
383 childrenBlocksJudgments <>
384 choicesByJudgmentBySection bs
385 choicesBySectionByJudgment ::
386 HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])] ->
387 TreeSeq.Tree (HM.HashMap Judgment (Maybe MJ.Share, [Choice])) ->
388 HM.HashMap Judgment [Tree.Tree (Maybe MJ.Share, [Choice])]
389 choicesBySectionByJudgment inh (TreeSeq.Tree selfJ childrenJS) =
392 (<$> selfS) $ \(Tree.Node choices old) ->
393 Tree.Node choices (old<>childrenS))
397 selfSJ = (\cs -> [Tree.Node cs []]) <$> selfJ
401 HM.unionWith (<>) accJ $
402 choicesBySectionByJudgment
403 (([Tree.Node (Nothing,[]) []] <$ selfJ) <> inh)
408 instance MappingOf (Tree BodyNode) where
409 mappingOf (Tree n ts) =
411 BodyBlock b -> mappingOf b
412 BodySection{} -> foldMap mappingOf ts
413 instance MappingOf DTC.Block where
415 BlockPara _p -> def -- mappingOf p
419 BlockAside{..} -> foldMap mappingOf blocks
420 BlockIndex{..} -> def{mapping_index = Map.singleton pos terms}
423 Map.singleton type_ (Map.singleton pos mayTitle)}
424 -- <> foldMap mappingOf paras
425 BlockReferences{..} ->
426 def{mapping_reference=
427 Map.fromList $ (<$> refs) $ \DTC.Reference{id=id', ..} -> (id', about)
429 BlockGrades{attrs=CommonAttrs{id=i}, ..} ->
430 def{mapping_grades = HM.singleton (fromMaybe "" i) scale}
431 BlockJudges{attrs=CommonAttrs{id=i}, ..} ->
432 def{mapping_judges = HM.singleton (fromMaybe "" i) jury}
434 instance MappingOf Judgment where
435 mappingOf Judgment{..} = def
436 def{mapping_judgments =
438 (judges,grades,question)
439 (Tree.Node choices [])
441 -- <> foldMap mappingOf choices
442 instance MappingOf Para where
444 ParaItem item -> mappingOf item
445 ParaItems{..} -> foldMap mappingOf items
446 instance MappingOf ParaItem where
450 ParaQuote{..} -> foldMap mappingOf paras
452 ParaOL items -> foldMap mappingOf items
453 ParaUL items -> foldMap (foldMap mappingOf) items
454 ParaJudgment{} -> def
455 instance MappingOf ListItem where
456 mappingOf ListItem{..} = foldMap mappingOf paras
457 instance MappingOf Choice where
458 mappingOf Choice{..} =
459 foldMap mappingOf title <>
460 foldMap mappingOf opinions
461 instance MappingOf Opinion where
462 mappingOf Opinion{..} =
463 foldMap mappingOf comment
464 instance MappingOf Title where
465 mappingOf (Title t) = mappingOf t
466 instance MappingOf Plain where
467 mappingOf = foldMap mappingOf
468 instance MappingOf (Tree PlainNode) where
469 mappingOf (Tree n ts) =
473 PlainGroup -> mappingOf ts
474 PlainB -> mappingOf ts
475 PlainCode -> mappingOf ts
476 PlainDel -> mappingOf ts
477 PlainI -> mappingOf ts
478 PlainSpan{} -> mappingOf ts
479 PlainSub -> mappingOf ts
480 PlainSup -> mappingOf ts
481 PlainSC -> mappingOf ts
482 PlainU -> mappingOf ts
483 PlainNote{..} -> foldMap mappingOf note
484 PlainQ -> mappingOf ts
485 PlainEref{} -> mappingOf ts
486 PlainIref{} -> mappingOf ts
487 PlainRef{} -> mappingOf ts
488 PlainRref{..} -> mappingOf ts
491 -- * Class 'Html5ify'
492 class Html5ify a where
493 html5ify :: a -> Html5
494 instance Html5ify H.Markup where
495 html5ify = Compose . return
496 instance Html5ify Char where
497 html5ify = html5ify . H.toMarkup
498 instance Html5ify Text where
499 html5ify = html5ify . H.toMarkup
500 instance Html5ify TL.Text where
501 html5ify = html5ify . H.toMarkup
502 instance Html5ify String where
503 html5ify = html5ify . H.toMarkup
504 instance Html5ify Title where
505 html5ify (Title t) = html5ify t
506 instance Html5ify Ident where
507 html5ify (Ident i) = html5ify i
508 instance Html5ify Int where
509 html5ify = html5ify . show
510 instance Html5ify Name where
511 html5ify (Name i) = html5ify i
512 instance Html5ify Nat where
513 html5ify (Nat n) = html5ify n
514 instance Html5ify Nat1 where
515 html5ify (Nat1 n) = html5ify n
516 instance Html5ify a => Html5ify (Maybe a) where
517 html5ify = foldMap html5ify
519 -- * Type 'BodyCursor'
520 -- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
521 type BodyCursor = Tree.Zipper BodyNode
522 instance Html5ify Body where
524 forM_ (Tree.zippers body) $ \z ->
525 forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
527 instance Html5ify BodyCursor
529 let Tree b bs = Tree.current z in
531 BodyBlock BlockToC{..} -> do
532 H.nav ! HA.class_ "toc"
533 ! HA.id (attrify $ identify pos) $$ do
534 H.span ! HA.class_ "toc-name" $$
535 H.a ! HA.href (refIdent $ identify pos) $$ do
536 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
537 Plain.l10n_Table_of_Contents loc
539 forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
541 BodyBlock blk -> html5ify blk
542 BodySection{..} -> do
543 st <- liftStateMarkup S.get
546 p <- posParent $ pos_Ancestors pos
547 let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p $ state_notes st
551 Just (secNotes, state_notes) -> do
552 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
554 html5CommonAttrs attrs{classes="section":classes attrs} $
555 H.section ! HA.id (attrify $ identify pos) $$ do
556 forM_ aliases html5ify
558 let sectionJudgments = state_judgments st `HS.union` HS.fromList judgments
559 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
560 let dropChildrenBlocksJudgments =
561 -- NOTE: drop the "phantom" judgments concerning the 'BodyBlock's
562 -- directly children of this 'BodySection'.
564 Tree BodyBlock{} _ -> True
568 liftStateMarkup $ S.modify' $ \s ->
569 s{ state_judgments = sectionJudgments
571 -- NOTE: drop current opinions of the judgments of this section
572 HM.unionWith (const $ List.tail . dropChildrenBlocksJudgments)
574 opinsBySectionByJudgment
576 unless (null opinsBySectionByJudgment) $ do
577 H.aside ! HA.class_ "aside" $$ do
578 let choicesJ = choicesByJudgment judgments
579 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
580 H.div ! HA.class_ "judgment section-judgment" $$ do
581 let choices = maybe [] snd $ HM.lookup judgment choicesJ
582 let opins = List.head opinsBySection
583 html5Judgment question choices opins
585 ! HA.id (attrify $ escapeIdent $ identify title)
586 ! HA.class_ "section-header" $$
589 H.td ! HA.class_ "section-number" $$ do
590 html5SectionNumber $ pos_Ancestors pos
591 H.td ! HA.class_ "section-title" $$ do
592 (case List.length $ pos_Ancestors pos of
601 forM_ (Tree.axis_child `Tree.runAxis` z) $
604 liftStateMarkup $ S.modify' $ \s ->
605 s{ state_judgments = state_judgments st }
607 notes <- liftStateMarkup $ S.gets state_notes
608 html5ify $ Map.lookup (pos_Ancestors pos) notes
609 instance Html5ify [Anchor.Note] where
611 H.aside ! HA.class_ "notes" $$ do
615 forM_ (List.reverse notes) $ \Anchor.Note{..} ->
617 H.td ! HA.class_ "note-ref" $$ do
618 H.a ! HA.class_ "note-number"
619 ! HA.id ("note."<>attrify note_number)
620 ! HA.href ("#note."<>attrify note_number) $$ do
623 H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
626 html5ify note_content
627 instance Html5ify Block where
629 BlockPara para -> html5ify para
631 html5CommonAttrs attrs
632 { classes = "page-break":"print-only":classes attrs } $
634 H.p $$ " " -- NOTE: force page break
635 BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
637 H.nav ! HA.class_ "tof"
638 ! HA.id (attrify $ identify pos) $$
639 H.table ! HA.class_ "tof" $$
643 html5CommonAttrs attrs $
644 H.aside ! HA.class_ "aside" $$ do
645 forM_ blocks html5ify
647 html5CommonAttrs attrs
648 { classes = "figure":("figure-"<>type_):classes attrs
649 , DTC.id = Just $ Ident $ Plain.text def $ pos_AncestorsWithFigureNames pos
652 H.table ! HA.class_ "figure-caption" $$
656 then H.a ! HA.href (refIdent $ identify pos) $$ mempty
658 H.td ! HA.class_ "figure-number" $$ do
659 H.a ! HA.href (refIdent $ identify $ pos_AncestorsWithFigureNames pos) $$ do
661 html5ify $ pos_AncestorsWithFigureNames pos
662 forM_ mayTitle $ \title -> do
663 H.td ! HA.class_ "figure-colon" $$ do
664 unless (TL.null type_) $ do
665 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
667 H.td ! HA.class_ "figure-title" $$ do
669 H.div ! HA.class_ "figure-content" $$ do
671 BlockIndex{pos} -> do
672 (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
673 let chars = Anchor.termsByChar allTerms
674 H.div ! HA.class_ "index"
675 ! HA.id (attrify $ identify pos) $$ do
676 H.nav ! HA.class_ "index-nav" $$ do
677 forM_ (Map.keys chars) $ \char ->
678 H.a ! HA.href (refIdent (identify pos <> "." <> identify char)) $$
680 H.dl ! HA.class_ "index-chars" $$
681 forM_ (Map.toList chars) $ \(char,terms) -> do
683 let i = identify pos <> "." <> identify char
684 H.a ! HA.id (attrify i)
685 ! HA.href (refIdent i) $$
688 H.dl ! HA.class_ "index-term" $$ do
689 forM_ terms $ \aliases -> do
691 H.ul ! HA.class_ "index-aliases" $$
692 forM_ (List.take 1 aliases) $ \term -> do
693 H.li ! HA.id (attrify $ identifyIref term) $$
697 List.sortBy (compare `on` DTC.section . snd) $
698 (`foldMap` aliases) $ \words ->
700 path <- Anchor.pathFromWords words
701 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
702 TreeMap.lookup path refsByTerm in
704 (<$> anchs) $ \(term,DTC.Anchor{..}) ->
705 H.a ! HA.class_ "index-iref"
706 ! HA.href (refIdent $ identifyIrefCount term count) $$
707 html5ify $ pos_Ancestors section
708 BlockReferences{..} ->
709 html5CommonAttrs attrs
710 { classes = "references":classes attrs
711 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
717 html5CommonAttrs attrs
718 { classes = "grades":classes attrs
719 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
722 -- let dg = List.head $ List.filter default_ scale
723 -- let sc = MJ.Scale (Set.fromList scale) dg
724 -- o :: Map choice grade
725 -- os :: Opinions (Map judge (Opinion choice grade))
729 html5CommonAttrs attrs
730 { classes = "judges":classes attrs
731 , DTC.id = Just $ Ident $ Plain.text def $ pos_Ancestors pos
736 html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
737 html5ifyToC depth z =
738 let Tree n _ts = Tree.current z in
740 BodySection{..} -> do
742 H.table ! HA.class_ "toc-entry" $$
745 H.td ! HA.class_ "section-number" $$
746 html5SectionRef $ pos_Ancestors pos
747 H.td ! HA.class_ "section-title" $$
748 html5ify $ cleanPlain $ unTitle title
749 when (maybe True (> Nat 1) depth && not (null sections)) $
752 html5ifyToC (depth >>= predNat)
758 `Tree.axis_filter_current` \case
759 Tree BodySection{} _ -> True
762 html5ifyToF :: [TL.Text] -> Html5
763 html5ifyToF types = do
764 figuresByType <- liftStateMarkup $ S.gets $ mapping_figure . state_mapping
766 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
770 Map.intersection figuresByType $
771 Map.fromList [(ty,()) | ty <- types]
772 forM_ (Map.toList figures) $ \(pos, (type_, title)) ->
774 H.td ! HA.class_ "figure-number" $$
775 H.a ! HA.href (refIdent $ identify pos) $$ do
777 html5ify $ pos_Ancestors pos
779 H.td ! HA.class_ "figure-title" $$
780 html5ify $ cleanPlain $ unTitle ti
782 cleanPlain :: Plain -> Plain
785 Tree PlainIref{} ls -> cleanPlain ls
786 Tree PlainNote{} _ -> mempty
787 Tree n ts -> pure $ Tree n $ cleanPlain ts
789 instance Html5ify Para where
793 { classes="para":cls item
797 html5CommonAttrs attrs
798 { classes = "para":classes attrs
802 forM_ items $ \item ->
803 html5AttrClass (cls item) $
806 id_ = Just . Ident . Plain.text def . pos_Ancestors
809 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
810 ParaQuote{..} -> ["quote", "quote-"<>type_]
814 ParaJudgment{} -> ["judgment"]
815 instance Html5ify ParaItem where
817 ParaPlain p -> H.p $$ html5ify p
818 ParaArtwork{..} -> H.pre $$ do html5ify text
819 ParaQuote{..} -> H.div $$ do html5ify paras
820 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
824 forM_ items $ \ListItem{..} -> do
826 H.td ! HA.class_ "name" $$ do
829 H.td ! HA.class_ "value" $$
833 forM_ items $ \item -> do
835 H.dd $$ html5ify item
836 ParaJudgment j -> html5ify j
837 instance Html5ify Judgment where
838 html5ify Judgment{..} = do
839 st <- liftStateMarkup S.get
842 maybe (error $ show grades) MJ.grades $ -- unknown grades
843 HM.lookup grades (mapping_grades $ state_mapping st)
845 fromMaybe (error $ show judges) $ -- unknown judges
846 HM.lookup judges (mapping_judges $ state_mapping st)
847 let defaultGradeByJudge =
850 [ g | g <- Set.toList judgmentGrades
851 , isDefault $ MJ.unRank g
854 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
855 | DTC.Judge{name,defaultGrades} <- judgmentJudges
856 , let judgeDefaultGrade = do
857 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
859 [ g | g <- Set.toList judgmentGrades
860 , let DTC.Grade{name=n} = MJ.unRank g
864 judgmentChoices <- forM choices $ \c@DTC.Choice{opinions} -> do
865 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade} -> do
867 fromMaybe (error $ show grade) $ -- unknown grade
869 [ MJ.singleGrade g | g <- Set.toList judgmentGrades
870 , let Grade{name} = MJ.unRank g
874 case MJ.opinions defaultGradeByJudge $ HM.fromList gradeByJudge of
875 (ok,ko) | null ko -> return (c, ok)
876 | otherwise -> error $ show ko -- unknown judge
878 html5Judgment question choices $ HM.fromList judgmentChoices
883 MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade) ->
885 html5Judgment question choices distByJudgeByChoice = do
886 let commentJGC = HM.fromList
887 [ (choice_, HM.fromListWith (<>)
888 [ (grade, HM.singleton judge comment)
889 | Opinion{..} <- opinions ])
890 | choice_@Choice{opinions} <- choices ]
893 Just title -> H.div ! HA.class_ "question" $$ html5ify title
894 H.dl ! HA.class_ "choices" $$ do
895 let meritByChoice@(MJ.MeritByChoice meritC) = MJ.meritByChoice distByJudgeByChoice
896 let ranking = MJ.majorityRanking meritByChoice
897 forM_ ranking $ \(choice_@DTC.Choice{title}, majorityValue) -> do
898 H.dt ! HA.class_ "choice-title" $$ do
900 H.dd ! HA.class_ "choice-merit" $$ do
901 let distByJudge = distByJudgeByChoice HM.!choice_
902 let numJudges = HM.size distByJudge
903 html5MeritHistogram majorityValue numJudges
904 let grades = Map.keys $ MJ.unMerit $ meritC HM.!choice_
905 let commentJG = HM.lookup choice_ commentJGC
906 html5MeritComments distByJudge grades commentJG
908 html5MeritComments ::
909 MJ.Opinions Name (MJ.Ranked Grade) ->
911 Maybe (HM.HashMap Name (HM.HashMap Name (Maybe Title))) ->
913 html5MeritComments distJ grades commentJG = do
914 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
915 H.ul ! HA.class_ "merit-comments" $$ do
916 forM_ grades $ \grade@(MJ.unRank -> DTC.Grade{name=grade_name, color}) -> do
917 let commentJ = commentJG >>= HM.lookup grade_name
918 let judgesWithComment =
919 -- FIXME: sort accents better: « e é f » not « e f é »
920 List.sortOn (TL.map Char.toLower . unName . (\(j,_,_) -> j))
921 [ (judge, importance, commentJ >>= HM.lookupDefault Nothing judge)
922 | (judge, dist) <- HM.toList distJ
923 , importance <- maybeToList $ Map.lookup grade dist ]
924 forM_ judgesWithComment $ \(judge, importance, comment) ->
925 H.li ! HA.class_ ("merit-comment" <> if isJust comment then " judge-comment" else "") $$ do
927 ! HA.class_ ("judge" <> if judge`HM.member`fromMaybe HM.empty commentJ then "" else " inactive")
928 ! HA.style ("color:"<>attrify color<>";") $$ do
929 unless (importance == 1) $ do
930 H.span ! HA.class_ "section-importance" $$ do
932 (round::Double -> Int) $
933 fromRational $ importance * 100
934 html5ify $ show percent
940 Plain.l10n_Colon loc :: Html5
943 html5MeritHistogram :: MJ.MajorityValue (MJ.Ranked Grade) -> Int -> Html5
944 html5MeritHistogram (MJ.MajorityValue majVal) numJudges = do
945 H.div ! HA.class_ "merit-histogram" $$ do
946 forM_ majVal $ \(MJ.unRank -> DTC.Grade{name=grade_name, title=grade_title, color},count) -> do
947 let percent :: Double =
948 fromRational $ (toRational $ (ceiling::Double -> Int) $ fromRational $
949 (count / toRational numJudges) * 100 * 1000) / 1000
950 let bcolor = "background-color:"<>attrify color<>";"
951 let width = "width:"<>attrify percent<>"%;"
952 let display = if percent == 0 then "display:none;" else ""
954 ! HA.class_ "merit-grade"
955 ! HA.alt (attrify grade_name) -- FIXME: do not work
956 ! HA.style (bcolor<>display<>width) $$ do
958 ! HA.class_ "grade-name" $$ do
960 Nothing -> html5ify grade_name
963 html5Judgments :: Html5
965 Mapping{..} :: Mapping <- liftStateMarkup $ S.gets state_mapping
966 opinionsByChoiceByNodeBySectionByJudgment <-
967 forM (HM.toList mapping_judgments) $ \(judgment@Judgment{judges,grades}, choicesBySection) -> do
968 -- WARNING: only the fields of 'Judgment' used in its 'Hashable' instance
969 -- can safely be used here: 'judges' and 'grades' are ok
971 maybe (error $ show grades) MJ.grades $ -- unknown grades
972 HM.lookup grades mapping_grades
974 fromMaybe (error $ show judges) $ -- unknown judges
975 HM.lookup judges mapping_judges
976 let defaultGradeByJudge =
979 [ g | g <- Set.toList judgmentGrades
980 , isDefault $ MJ.unRank g
983 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
984 | DTC.Judge{name,defaultGrades} <- judgmentJudges
985 , let judgeDefaultGrade = do
986 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
988 [ g | g <- Set.toList judgmentGrades
989 , let DTC.Grade{name=n} = MJ.unRank g
993 opinionsByChoiceByNodeBySection <-
994 forM choicesBySection $ \choicesTree -> do
995 judgmentTree <- forM choicesTree $ \(section_importance, choices) -> do
996 judgmentOpinions <- forM choices $ \choice_@DTC.Choice{opinions} -> do
997 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade,importance} -> do
999 [ g | g <- Set.toList judgmentGrades
1000 , let Grade{name} = MJ.unRank g
1003 Just grd -> return (judge, MJ.Section importance (Just grd))
1004 Nothing -> error $ show grade -- unknown grade
1005 return (choice_, HM.fromList gradeByJudge)
1006 return $ MJ.SectionNode section_importance $ HM.fromList judgmentOpinions
1007 let judgmentChoices = HS.fromList $ snd $ Tree.rootLabel choicesTree
1008 -- NOTE: choices are determined by those at the root Tree.Node.
1009 -- NOTE: core Majority Judgment calculus handled here by MJ
1010 case MJ.opinionsBySection judgmentChoices defaultGradeByJudge judgmentTree of
1011 Right opinionsByChoiceByNode -> return opinionsByChoiceByNode
1012 Left err -> error $ show err -- unknown choice, unknown judge, invalid shares
1013 -- NOTE: 'toList' returns a self-then-descending-then-following traversal of a 'Tree',
1014 -- this will match perfectly withw the 'html5ify' traversal:
1015 -- 'BodySection' by 'BodySection'.
1016 return (judgment, join $ toList <$> opinionsByChoiceByNodeBySection)
1017 liftStateMarkup $ S.modify' $ \st ->
1018 st{state_opinions = HM.fromList opinionsByChoiceByNodeBySectionByJudgment}
1020 instance Html5ify [Para] where
1021 html5ify = mapM_ html5ify
1022 instance Html5ify Plain where
1024 case Seq.viewl ps of
1025 Seq.EmptyL -> mempty
1028 -- NOTE: gather adjacent PlainNotes
1030 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
1031 H.sup ! HA.class_ "note-numbers" $$ do
1033 forM_ notes $ \note -> do
1042 instance Html5ify (Tree PlainNode)
1043 where html5ify (Tree n ls) =
1045 PlainBreak -> html5ify H.br
1046 PlainText t -> html5ify t
1047 PlainGroup -> html5ify ls
1048 PlainB -> H.strong $$ html5ify ls
1049 PlainCode -> H.code $$ html5ify ls
1050 PlainDel -> H.del $$ html5ify ls
1052 i <- liftStateMarkup $ do
1053 i <- S.gets $ Plain.state_italic . state_plainify
1056 (state_plainify s){Plain.state_italic=
1059 H.em ! HA.class_ (if i then "even" else "odd") $$
1064 (state_plainify s){Plain.state_italic=i}}
1066 html5CommonAttrs attrs $
1067 H.span $$ html5ify ls
1068 PlainSub -> H.sub $$ html5ify ls
1069 PlainSup -> H.sup $$ html5ify ls
1070 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
1071 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
1076 H.a ! HA.class_ "note-ref"
1077 ! HA.id ("note-ref."<>attrify num)
1078 ! HA.href ("#note."<>attrify num) $$
1081 H.span ! HA.class_ "q" $$ do
1082 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1083 Plain.l10n_Quote (html5ify $ Tree PlainI ls) loc
1085 H.a ! HA.class_ "eref"
1086 ! HA.href (attrify href) $$
1088 then html5ify $ unURL href
1092 Nothing -> html5ify ls
1094 H.span ! HA.class_ "iref"
1095 ! HA.id (attrify $ identifyIrefCount term count) $$
1098 H.a ! HA.class_ "ref"
1099 ! HA.href (refIdent $ escapeIdent to) $$
1101 then html5ify $ unIdent to
1104 refs <- liftStateMarkup $ S.gets $ mapping_reference . state_mapping
1105 case Map.lookup to refs of
1108 H.span ! HA.class_ "rref-broken" $$
1111 Just About{..} -> do
1113 forM_ (List.take 1 titles) $ \(Title title) -> do
1114 html5ify $ Tree PlainQ $
1117 Just u -> pure $ Tree (PlainEref u) title
1120 H.a ! HA.class_ "rref"
1121 ! HA.href ("#rref."<>attrify to)
1122 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
1125 instance Html5ify [Title] where
1127 html5ify . fold . List.intersperse sep . toList
1128 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
1129 instance Html5ify About where
1130 html5ify About{..} = do
1132 [ html5CommasDot $ concat $
1133 [ html5Titles titles
1134 , html5ify <$> authors
1135 , html5ify <$> maybeToList date
1136 , html5ify <$> maybeToList editor
1137 , html5ify <$> series
1140 H.span ! HA.class_ "print-only" $$ do
1146 html5Titles :: [Title] -> [Html5]
1147 html5Titles ts | null ts = []
1148 html5Titles ts = [html5Title $ joinTitles ts]
1150 joinTitles = fold . List.intersperse sep . toList
1151 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
1152 html5Title (Title title) =
1153 html5ify $ Tree PlainQ $
1156 Just u -> pure $ Tree (PlainEref u) title
1157 instance Html5ify Serie where
1158 html5ify s@Serie{id=id_, name} = do
1159 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1163 Plain.l10n_Colon loc :: Html5
1167 Tree PlainEref{href} $
1169 [ tree0 $ PlainText $ unName name
1170 , tree0 $ PlainText $ Plain.l10n_Colon loc
1171 , tree0 $ PlainText id_
1173 instance Html5ify Entity where
1174 html5ify Entity{..} = do
1176 _ | not (TL.null email) -> do
1177 H.span ! HA.class_ "no-print" $$
1179 Tree (PlainEref $ URL $ "mailto:"<>email) $
1180 pure $ tree0 $ PlainText name
1181 H.span ! HA.class_ "print-only" $$
1183 Tree PlainGroup $ Seq.fromList
1184 [ tree0 $ PlainText name
1185 , tree0 $ PlainText " <"
1186 , Tree (PlainEref $ URL $ "mailto:"<>email) $
1187 pure $ tree0 $ PlainText email
1188 , tree0 $ PlainText ">"
1190 _ | Just u <- url ->
1192 Tree (PlainEref u) $
1193 pure $ tree0 $ PlainText name
1196 tree0 $ PlainText name
1197 forM_ org $ \o -> do
1201 instance Html5ify Words where
1202 html5ify = html5ify . Anchor.plainifyWords
1203 instance Html5ify Alias where
1204 html5ify Alias{id=id_, ..} = do
1205 H.a ! HA.class_ "alias"
1206 ! HA.id (attrify $ identify id_) $$
1208 instance Html5ify URL where
1209 html5ify (URL url) =
1210 H.a ! HA.class_ "eref"
1211 ! HA.href (attrify url) $$
1213 instance Html5ify Date where
1215 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
1216 Plain.l10n_Date date loc
1217 instance Html5ify Reference where
1218 html5ify Reference{id=id_, ..} =
1220 H.td ! HA.class_ "reference-key" $$
1221 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
1222 H.td ! HA.class_ "reference-content" $$ do
1224 rrefs <- liftStateMarkup $ S.gets state_rrefs
1225 case Map.lookup id_ rrefs of
1228 H.span ! HA.class_ "reference-rrefs" $$
1230 (<$> List.reverse anchs) $ \Anchor{..} ->
1231 H.a ! HA.class_ "reference-rref"
1232 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
1233 html5ify $ pos_Ancestors section
1234 instance Html5ify PosPath where
1242 Text.intercalate "." $
1243 Text.pack . show . snd <$> as
1244 instance Html5ify Plain.Plain where
1246 sp <- liftStateMarkup $ S.gets state_plainify
1247 let (t,sp') = Plain.runPlain p sp
1249 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
1251 instance Html5ify SVG.Element where
1254 B.preEscapedLazyText $
1256 instance Semigroup SVG.Element where
1260 html5CommasDot :: [Html5] -> Html5
1261 html5CommasDot [] = pure ()
1262 html5CommasDot hs = do
1263 sequence_ $ List.intersperse ", " hs
1266 html5Lines :: [Html5] -> Html5
1267 html5Lines hs = sequence_ $ List.intersperse (html5ify H.br) hs
1269 html5Words :: [Html5] -> Html5
1270 html5Words hs = sequence_ $ List.intersperse " " hs
1272 html5AttrClass :: [TL.Text] -> Html5 -> Html5
1273 html5AttrClass = \case
1277 (H.AddCustomAttribute "class"
1278 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
1281 html5AttrId :: Ident -> Html5 -> Html5
1282 html5AttrId (Ident id_) =
1284 (H.AddCustomAttribute "id"
1285 (H.String $ TL.unpack id_) <$>) .
1288 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
1289 html5CommonAttrs CommonAttrs{id=id_, ..} =
1290 html5AttrClass classes .
1291 maybe Cat.id html5AttrId id_
1293 html5SectionNumber :: PosPath -> Html5
1294 html5SectionNumber = go mempty
1296 go :: PosPath -> PosPath -> Html5
1298 case Seq.viewl next of
1299 Seq.EmptyL -> pure ()
1300 a@(_n,rank) Seq.:< as -> do
1301 H.a ! HA.href (refIdent $ identify $ prev Seq.|> a) $$
1302 html5ify $ show rank
1303 when (not (null as) || null prev) $ do
1305 go (prev Seq.|>a) as
1307 html5SectionRef :: PosPath -> Html5
1308 html5SectionRef as =
1309 H.a ! HA.href (refIdent $ identify as) $$
1312 -- * Class 'Identify'
1313 class Identify a where
1314 identify :: a -> Ident
1315 instance Identify Char where
1316 identify = Ident . TL.singleton
1317 instance Identify String where
1318 identify = Ident . TL.pack
1319 instance Identify TL.Text where
1321 instance Identify (Tree PlainNode) where
1322 identify (Tree n ls) =
1324 PlainBreak -> identify '\n'
1325 PlainText t -> identify t
1326 PlainGroup -> identify ls
1327 PlainB -> identify ls
1328 PlainCode -> identify ls
1329 PlainDel -> identify ls
1330 PlainI -> identify ls
1331 PlainSpan{} -> identify ls
1332 PlainSub -> identify ls
1333 PlainSup -> identify ls
1334 PlainSC -> identify ls
1335 PlainU -> identify ls
1337 PlainQ -> identify ls
1338 PlainEref{} -> identify ls
1339 PlainIref{} -> identify ls
1340 PlainRef{} -> identify ls
1341 PlainRref{..} -> identify to
1342 instance Identify Ident where
1343 identify (Ident p) = identify p
1344 instance Identify Plain where
1345 identify = foldMap identify
1346 instance Identify Title where
1347 identify (Title p) = identify p
1348 instance Identify PosPath where
1351 snd . foldl' (\(nameParent,acc) (name,rank) ->
1353 (if TL.null $ unIdent acc then acc else acc <> ".") <>
1354 (if name == nameParent
1355 then identify (show rank)
1356 else escapeIdentTail $ identify (show name)<>identify (show rank))
1360 instance Identify Pos where
1361 identify = identify . pos_Ancestors
1362 instance Identify Path where
1363 identify (Path a) = identify a
1364 instance Identify Int where
1365 identify = fromString . show
1366 instance Identify Nat where
1367 identify (Nat a) = identify a
1368 instance Identify Nat1 where
1369 identify (Nat1 a) = identify a
1370 instance Identify Anchor where
1371 identify Anchor{..} = identify section <> "." <> identify count
1373 refIdent :: Ident -> H.AttributeValue
1374 refIdent i = "#"<>attrify i
1376 escapeIdent :: Ident -> Ident
1377 escapeIdent = escapeIdentHead . escapeIdentTail
1378 escapeIdentHead :: Ident -> Ident
1379 escapeIdentHead (Ident i) = Ident i
1380 escapeIdentTail :: Ident -> Ident
1381 escapeIdentTail (Ident i) =
1384 (\c accum -> (<> accum) $ case c of
1386 _ | Char.isAlphaNum c
1391 enc = TL.encodeUtf8 $ TL.singleton c
1392 bytes = BS.foldr (\b acc -> escape b<>acc) "" enc
1393 escape = TL.Builder.toLazyText . TL.Builder.hexadecimal
1396 identifyIref :: Words -> Ident
1398 "iref" <> "." <> identify (Anchor.plainifyWords term)
1399 identifyIrefCount :: Words -> Nat1 -> Ident
1400 identifyIrefCount term count =
1402 <> "." <> identify (Anchor.plainifyWords term)
1403 <> "." <> identify count
1406 instance Attrify Plain.Plain where
1407 attrify p = attrify t
1408 where (t,_) = Plain.runPlain p def
1412 ( Plain.L10n msg lang
1413 , Plain.L10n TL.Text lang
1414 ) => L10n msg lang where
1415 l10n_Header_Address :: FullLocale lang -> msg
1416 l10n_Header_Date :: FullLocale lang -> msg
1417 l10n_Header_Version :: FullLocale lang -> msg
1418 l10n_Header_Origin :: FullLocale lang -> msg
1419 l10n_Header_Source :: FullLocale lang -> msg
1420 instance L10n Html5 EN where
1421 l10n_Header_Address _loc = "Address"
1422 l10n_Header_Date _loc = "Date"
1423 l10n_Header_Origin _loc = "Origin"
1424 l10n_Header_Source _loc = "Source"
1425 l10n_Header_Version _loc = "Version"
1426 instance L10n Html5 FR where
1427 l10n_Header_Address _loc = "Adresse"
1428 l10n_Header_Date _loc = "Date"
1429 l10n_Header_Origin _loc = "Origine"
1430 l10n_Header_Source _loc = "Source"
1431 l10n_Header_Version _loc = "Version"
1433 instance Plain.L10n Html5 EN where
1434 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
1435 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
1436 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
1437 l10n_Quote msg _loc = do
1438 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1439 let (o,c) :: (Html5, Html5) =
1440 case unNat depth `mod` 3 of
1445 setDepth $ succNat depth
1451 liftStateMarkup $ S.modify' $ \s ->
1452 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
1453 instance Plain.L10n Html5 FR where
1454 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
1455 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
1456 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
1457 l10n_Quote msg _loc = do
1458 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1459 let (o,c) :: (Html5, Html5) =
1460 case unNat depth `mod` 3 of
1465 setDepth $ succNat depth
1471 liftStateMarkup $ S.modify' $ \s ->
1472 s{state_plainify=(state_plainify s){Plain.state_quote=d}}