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.Monad (Monad(..), join, (=<<), forM, forM_, mapM_, sequence_)
17 import Data.Char (Char)
18 import Data.Default.Class (Default(..))
19 import Data.Either (Either(..))
20 import Data.Eq (Eq(..))
21 import Data.Foldable (Foldable(..), concat, any)
22 import Data.Function (($), (.), const, on)
23 import Data.Functor ((<$>))
24 import Data.Functor.Compose (Compose(..))
26 import Data.IntMap.Strict (IntMap)
27 import Data.List.NonEmpty (NonEmpty(..))
28 import Data.Locale hiding (Index)
29 import Data.Map.Strict (Map)
30 import Data.Maybe (Maybe(..), maybe, mapMaybe, fromJust, maybeToList, listToMaybe, fromMaybe, isJust)
31 import Data.Monoid (Monoid(..))
32 import Data.Ord (Ord(..))
33 import Data.Semigroup (Semigroup(..))
34 import Data.Sequence (Seq(..))
35 import Data.String (String, IsString(..))
36 import Data.Text (Text)
37 import Data.TreeSeq.Strict (Tree(..), tree0)
38 import Data.Tuple (fst, snd)
39 import Prelude (mod, (*), Fractional(..), Double, toRational, RealFrac(..))
40 import System.FilePath (FilePath, (</>))
42 import Text.Blaze ((!))
43 import Text.Blaze.Html (Html)
44 import Text.Show (Show(..))
45 import qualified Control.Category as Cat
46 import qualified Control.Monad.Trans.State as S
47 import qualified Data.Char as Char
48 import qualified Data.HashMap.Strict as HM
49 import qualified Data.HashSet as HS
50 import qualified Data.IntMap.Strict as IntMap
51 import qualified Data.List as List
52 import qualified Data.Map.Strict as Map
53 import qualified Data.Sequence as Seq
54 import qualified Data.Set as Set
55 import qualified Data.Strict.Maybe as Strict
56 import qualified Data.Text as Text
57 import qualified Data.Text.Lazy as TL
58 import qualified Data.Tree as Tree
59 import qualified Data.TreeMap.Strict as TreeMap
60 import qualified Data.TreeSeq.Strict as TreeSeq
61 import qualified Hjugement as MJ
62 import qualified Prelude (error)
63 import qualified Text.Blaze.Html5 as H
64 import qualified Text.Blaze.Html5.Attributes as HA
65 import qualified Text.Blaze.Internal as H
67 import Hdoc.DTC.Document as DTC
68 import Hdoc.DTC.Write.HTML5.Ident
69 import Hdoc.DTC.Write.Plain (Plainify(..))
70 import Hdoc.DTC.Write.XML ()
72 import Text.Blaze.Utils
73 import qualified Hdoc.DTC.Check as Check
74 import qualified Hdoc.DTC.Collect as Collect
75 import qualified Hdoc.DTC.Index as Index
76 import qualified Hdoc.DTC.Write.Plain as Plain
77 import qualified Hdoc.TCT.Cell as TCT
78 import qualified Hdoc.Utils as FS
79 import qualified Hdoc.XML as XML
80 import qualified Paths_hdoc as Hdoc
83 debug :: Show a => String -> a -> a
84 debug msg a = trace (msg<>": "<>show a) a
85 debugOn :: Show b => String -> (a -> b) -> a -> a
86 debugOn msg get a = trace (msg<>": "<>show (get a)) a
87 debugWith :: String -> (a -> String) -> a -> a
88 debugWith msg get a = trace (msg<>": "<>get a) a
90 showJudgments :: HM.HashMap (Ident,Ident,Maybe Title) [Tree.Tree [Choice]] -> String
94 -- Tree.Node (Left ("","",Nothing)) $
95 (<$> HM.toList js) $ \((j,g,q),ts) ->
97 (Left (unIdent j,unIdent g,Plain.text def <$> q))
101 type HTML5 = StateMarkup State ()
102 instance IsString HTML5 where
103 fromString = html5ify
109 , Loqualize locales (L10n HTML5)
110 , Loqualize locales (Plain.L10n Plain.Plain)
113 { config_css :: Either FilePath TL.Text
114 , config_js :: Either FilePath TL.Text
115 , config_locale :: LocaleIn locales
116 , config_generator :: TL.Text
118 instance Default Config where
120 { config_css = Right "style/dtc-html5.css"
121 , config_js = Right "style/dtc-html5.js"
122 , config_locale = LocaleIn @'[EN] en_US
123 , config_generator = "https://hackage.haskell.org/package/hdoc"
129 { state_styles :: HS.HashSet (Either FilePath TL.Text)
130 , state_scripts :: HS.HashSet FilePath
131 , state_notes :: Check.NotesBySection
132 , state_judgments :: HS.HashSet Judgment
133 , state_opinions :: HM.HashMap Judgment [MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade)]
135 , state_section :: TreeSeq.Trees BodyNode
136 , state_collect :: Collect.All
137 , state_indexs :: Map XML.Pos (Terms, Index.Irefs) -- TODO: could be a list
138 , state_rrefs :: HM.HashMap Ident [(Maybe Section,Nat1)]
139 , state_plainify :: Plain.State
140 , state_l10n :: Loqualization (L10n HTML5)
142 instance Default State where
144 { state_styles = HS.fromList [Left "dtc-html5.css"]
145 , state_scripts = def
146 , state_section = def
147 , state_collect = def
151 , state_plainify = def
152 , state_l10n = Loqualization EN_US
153 , state_judgments = HS.empty
154 , state_opinions = def
157 writeHTML5 :: Config -> DTC.Document -> IO Html
158 writeHTML5 conf@Config{..} doc@DTC.Document{..} = do
159 let collect@Collect.All{..} = Collect.collect doc
160 let (checkedBody,checkState) =
161 Check.check body `S.runState` def
162 { Check.state_irefs = foldMap Index.irefsOfTerms all_index
163 , Check.state_collect = collect
165 let (html5Body, endState) =
166 let Check.State{..} = checkState in
170 (<$> all_index) $ \terms ->
172 TreeMap.intersection const state_irefs $
173 Index.irefsOfTerms terms
176 , state_section = body
177 , state_l10n = loqualize config_locale
178 , state_plainify = def{Plain.state_l10n = loqualize config_locale}
181 html5ify state_errors
182 html5DocumentHead head
184 html5Head <- writeHTML5Head conf endState head
186 let State{..} = endState
188 H.html ! HA.lang (attrify $ countryCode config_locale) $ do
192 unless (null state_scripts) $ do
193 -- NOTE: indicate that JavaScript is active.
194 H.script ! HA.type_ "application/javascript" $
195 "document.body.className = \"script\";"
199 writeHTML5Head :: Config -> State -> Head -> IO Html
200 writeHTML5Head Config{..} State{..} Head{DTC.about=About{..}} = do
202 -- unless (any (\DTC.Link{..} -> rel == "stylesheet" && href /= URL "") links) $ do
203 (`foldMap` state_styles) $ \case
205 content <- FS.readFile =<< Hdoc.getDataFileName ("style"</>css)
206 return $ H.style ! HA.type_ "text/css" $
209 return $ H.style ! HA.type_ "text/css" $
210 -- NOTE: as a special case, H.style wraps its content into an External,
211 -- so it does not HTML-escape its content.
217 H.link ! HA.rel "stylesheet"
218 ! HA.type_ "text/css"
219 ! HA.href (attrify css)
221 H.style ! HA.type_ "text/css" $
225 (`foldMap` state_scripts) $ \script -> do
226 content <- FS.readFile =<< Hdoc.getDataFileName ("style"</>script)
227 return $ H.script ! HA.type_ "application/javascript" $
230 if not (any (\DTC.Link{rel} -> rel == "script") links)
236 Left js -> H.script ! HA.src (attrify js)
237 ! HA.type_ "application/javascript"
239 Right js -> H.script ! HA.type_ "application/javascript"
244 H.meta ! HA.httpEquiv "Content-Type"
245 ! HA.content "text/html; charset=UTF-8"
246 unless (null titles) $ do
248 H.toMarkup $ Plain.text state_plainify $ List.head titles
249 forM_ links $ \Link{..} ->
251 "stylesheet" | URL "" <- href ->
252 H.style ! HA.type_ "text/css" $
253 H.toMarkup $ Plain.text def plain
255 H.link ! HA.rel (attrify rel)
256 ! HA.href (attrify href)
258 H.link ! HA.rel "self"
259 ! HA.href (attrify href)
260 unless (TL.null config_generator) $ do
261 H.meta ! HA.name "generator"
262 ! HA.content (attrify config_generator)
264 H.meta ! HA.name "keywords"
265 ! HA.content (attrify $ TL.intercalate ", " tags)
267 (`mapMaybe` toList state_section) $ \case
268 Tree (BodySection s) _ -> Just s
270 forM_ chapters $ \Section{..} ->
271 H.link ! HA.rel "Chapter"
272 ! HA.title (attrify $ plainify title)
273 ! HA.href (refIdent $ identify xmlPos)
277 html5DocumentHead :: Head -> HTML5
278 html5DocumentHead Head{DTC.about=About{..}, judgments} = do
279 st <- liftStateMarkup S.get
280 unless (null authors) $ do
281 H.div ! HA.class_ "document-head" $$
285 H.td ! HA.class_ "left" $$ docHeaders
286 H.td ! HA.class_ "right" $$ docAuthors
287 unless (null titles) $ do
288 H.div ! HA.class_ "title"
289 ! HA.id "document-title." $$ do
290 forM_ titles $ \title ->
291 H.h1 ! HA.id (attrify $ identifyTitle (Plain.state_l10n $ state_plainify st) title) $$
294 let sectionJudgments = HS.fromList judgments
295 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
296 liftStateMarkup $ S.modify' $ \s ->
297 s{ state_judgments = sectionJudgments
299 -- NOTE: drop current opinions of the judgments of this section
300 HM.unionWith (const List.tail)
302 opinsBySectionByJudgment
304 unless (null opinsBySectionByJudgment) $ do
305 let choicesJ = Collect.choicesByJudgment judgments
306 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
307 H.div ! HA.class_ "judgment section-judgment document-judgment" $$ do
308 let choices = maybe [] snd $ HM.lookup judgment choicesJ
309 let opins = List.head opinsBySection
310 html5Judgment question choices opins
313 H.table ! HA.class_ "document-headers" $$
315 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
316 forM_ series $ \s@Serie{id=id_, name} ->
320 headerName $ html5ify name
321 headerValue $ html5ify id_
323 headerName $ html5ify name
325 H.a ! HA.href (attrify href) $$
327 forM_ links $ \Link{..} ->
328 unless (TL.null $ unName name) $
330 headerName $ html5ify name
331 headerValue $ html5ify $ Tree PlainEref{href} plain
334 headerName $ l10n_Header_Date l10n
335 headerValue $ html5ify d
338 headerName $ l10n_Header_Address l10n
339 headerValue $ html5ify $ tree0 $ PlainEref{href}
340 forM_ headers $ \Header{..} ->
342 headerName $ html5ify name
343 headerValue $ html5ify value
345 H.table ! HA.class_ "document-authors" $$
347 forM_ authors $ \a ->
349 H.td ! HA.class_ "author" $$
351 header :: HTML5 -> HTML5
352 header hdr = H.tr ! HA.class_ "header" $$ hdr
353 headerName :: HTML5 -> HTML5
355 H.td ! HA.class_ "header-name" $$ do
357 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
358 Plain.l10n_Colon l10n
359 headerValue :: HTML5 -> HTML5
361 H.td ! HA.class_ "header-value" $$ do
364 -- * Class 'Html5ify'
365 class Html5ify a where
366 html5ify :: a -> HTML5
367 instance Html5ify H.Markup where
368 html5ify = Compose . return
369 instance Html5ify Char where
370 html5ify = html5ify . H.toMarkup
371 instance Html5ify Text where
372 html5ify = html5ify . H.toMarkup
373 instance Html5ify TL.Text where
374 html5ify = html5ify . H.toMarkup
375 instance Html5ify String where
376 html5ify = html5ify . H.toMarkup
377 instance Html5ify Title where
378 html5ify (Title t) = html5ify t
379 instance Html5ify Ident where
380 html5ify (Ident i) = html5ify i
381 instance Html5ify Int where
382 html5ify = html5ify . show
383 instance Html5ify Name where
384 html5ify (Name i) = html5ify i
385 instance Html5ify Nat where
386 html5ify (Nat n) = html5ify n
387 instance Html5ify Nat1 where
388 html5ify (Nat1 n) = html5ify n
389 instance Html5ify a => Html5ify (Maybe a) where
390 html5ify = foldMap html5ify
391 instance Html5ify TCT.Location where
394 H.span ! HA.class_ "tct-location" $$
397 H.ul ! HA.class_ "tct-location" $$
401 instance Html5ify Check.Errors where
402 html5ify Check.Errors{..} = do
404 { state_collect = Collect.All{..}
405 , state_l10n = Loqualization (l10n::FullLocale lang)
407 } <- liftStateMarkup S.get
408 let errors :: [ ( Int{-errKind-}
409 , HTML5{-errKindDescr-}
410 , [(Plain{-errTypeKey-}, [(TCT.Location{-errPos-}, Ident{-errId-})])]
413 (\errKind (errKindDescr, errByPosByKey) ->
414 (errKind, errKindDescr l10n, errByPosByKey))
416 [ (l10n_Error_Tag_unknown , errorTag st "-unknown" errors_tag_unknown)
417 , (l10n_Error_Tag_ambiguous , errorTag st "-ambiguous" errors_tag_ambiguous)
418 , (l10n_Error_Rref_unknown , errorReference "-unknown" errors_rref_unknown)
419 , (l10n_Error_Reference_ambiguous, errorReference "-ambiguous" errors_reference_ambiguous)
421 let numErrors = Nat $ sum $ (<$> errors) $ \(_typ, _descr, errByPosByKey) ->
422 sum $ length . snd <$> errByPosByKey
423 when (numErrors > Nat 0) $ do
424 liftStateMarkup $ S.put st
426 HS.insert (Left "dtc-errors.css") $
428 -- NOTE: Implement a CSS-powered show/hide logic, using :target
429 "\n@media screen {" <>
430 "\n\t.error-filter:target .errors-list > li {display:none;}" <>
431 (`foldMap` errors) (\(num, _description, errs) ->
432 if null errs then "" else
433 let err = "error-type"<>TL.pack (show num)<>"\\." in
434 "\n\t.error-filter#"<>err<>":target .errors-list > li."<>err
435 <>" {display:list-item}" <>
436 "\n\t.error-filter#"<>err<>":target .errors-nav > ul > li."<>err
437 <>" {list-style-type:disc;}"
443 filterIds errors $ H.div ! HA.class_ "document-errors" ! HA.id "document-errors." $$ do
444 H.nav ! HA.class_ "errors-nav" $$ do
445 H.p ! HA.class_ "errors-all" $$
446 H.a ! HA.href (refIdent "document-errors.") $$ do
447 l10n_Errors_All l10n numErrors :: HTML5
450 \(errKind, errKindDescr, errs) -> do
451 unless (null errs) $ do
452 H.li ! HA.class_ (attrify $ errorType errKind) $$ do
453 H.a ! HA.href (refIdent $ errorType errKind) $$ do
456 html5ify $ sum $ length . snd <$> errs
458 H.ol ! HA.class_ "errors-list" $$ do
459 let errByPosByKey :: Map TCT.Location{-errPos-} ( Int{-errKind-}
460 , HTML5{-errKindDescr-}
462 , [(TCT.Location{-errPos-}, Ident{-errId-})] ) =
463 (`foldMap`errors) $ \(errKind, errKindDescr, errByKey) ->
464 (`foldMap`errByKey) $ \(errKey, errByPos) ->
466 (fst $ List.head errByPos)
467 -- NOTE: sort using the first position of this errKind with this errKey.
468 (errKind, errKindDescr, errKey, errByPos)
469 forM_ errByPosByKey $
470 \(errKind, errKindDescr, errKey, errByPos) -> do
471 H.li ! HA.class_ (attrify $ errorType errKind) $$ do
472 H.span ! HA.class_ "error-message" $$ do
473 H.span ! HA.class_ "error-kind" $$ do
475 Plain.l10n_Colon l10n :: HTML5
477 H.ol ! HA.class_ "error-position" $$
478 forM_ errByPos $ \(errPos, errId) ->
480 H.a ! HA.href (refIdent errId) $$
483 errorType num = identify $ "error-type"<>show num<>"."
484 -- | Nest error id= to enable showing/hidding errors using :target pseudo-class.
486 filterIds ((num, _description, errs):es) h =
490 H.div ! HA.class_ "error-filter"
491 ! HA.id (attrify $ errorType num) $$
493 errorTag :: State -> Ident -> HM.HashMap Title (Seq TCT.Location) -> [(Plain, [(TCT.Location,Ident)])]
494 errorTag State{state_plainify=Plain.State{state_l10n}} suffix errs =
495 (<$> HM.toList errs) $ \(Title tag, errPositions) ->
498 (\num -> (,identifyTag suffix state_l10n tag (Just $ Nat1 num)))
499 [1::Int ..] (toList errPositions)
501 errorReference :: Ident -> HM.HashMap Ident (Seq TCT.Location) -> [(Plain, [(TCT.Location,Ident)])]
502 errorReference suffix errs =
503 (<$> HM.toList errs) $ \(id, errPositions) ->
504 ( pure $ tree0 $ PlainText $ unIdent id
506 (\num -> (,identifyReference suffix id (Just $ Nat1 num)))
507 [1::Int ..] (toList errPositions)
509 instance Html5ify Body where
511 liftStateMarkup $ S.modify' $ \s -> s{state_section = body}
513 case Seq.viewr body of
514 _ Seq.:> Tree BodyBlock{} _ -> do
515 notes <- liftStateMarkup $ S.gets state_notes
516 maybe mempty html5Notes $
517 Map.lookup mempty notes
519 instance Html5ify (Tree BodyNode) where
520 html5ify (Tree b bs) =
522 BodyBlock blk -> html5ify blk
523 BodySection Section{..} -> do
524 st@State{state_collect=Collect.All{..}} <- liftStateMarkup S.get
525 liftStateMarkup $ S.modify' $ \s -> s{state_section = bs}
528 sectionPosPath <- XML.ancestors $ XML.pos_ancestors xmlPos
529 let (sectionNotes, notes) = Map.updateLookupWithKey (\_ _ -> Nothing) sectionPosPath $ state_notes st
530 (,notes) <$> sectionNotes
533 Just (sectionNotes, state_notes) -> do
534 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
535 html5Notes sectionNotes
536 html5CommonAttrs attrs{classes="section":classes attrs, id=Nothing} $
537 H.section ! HA.id (attrify $ identify xmlPos) $$ do
538 forM_ aliases html5ify
540 let sectionJudgments = state_judgments st `HS.union` HS.fromList judgments
541 let opinsBySectionByJudgment = state_opinions st `HM.intersection` HS.toMap sectionJudgments
542 let dropChildrenBlocksJudgments =
543 -- NOTE: drop the "phantom" judgments concerning the 'BodyBlock's
544 -- directly children of this 'BodySection'.
546 Tree BodyBlock{} _ -> True
550 liftStateMarkup $ S.modify' $ \s ->
551 s{ state_judgments = sectionJudgments
553 -- NOTE: drop current opinions of the judgments of this section
554 HM.unionWith (const $ List.tail . dropChildrenBlocksJudgments)
556 opinsBySectionByJudgment
558 unless (null opinsBySectionByJudgment) $ do
559 liftStateMarkup $ S.modify' $ \s -> s
560 { state_styles = HS.insert (Left "dtc-judgment.css") $ state_styles s }
561 H.aside ! HA.class_ "aside" $$ do
562 let choicesJ = Collect.choicesByJudgment judgments
563 forM_ (HM.toList opinsBySectionByJudgment) $ \(judgment@Judgment{question},opinsBySection) -> do
564 H.div ! HA.class_ "judgment section-judgment" $$ do
565 let choices = maybe [] snd $ HM.lookup judgment choicesJ
566 let opins = List.head opinsBySection
567 html5Judgment question choices opins
569 case toList <$> HM.lookup title all_section of
570 Just [_] -> Just $ identifyTitle (Plain.state_l10n $ state_plainify st) title
573 ! HA.class_ "section-header"
574 !?? mayAttr HA.id mayId $$
577 H.td ! HA.class_ "section-number" $$ do
578 html5SectionNumber $ XML.pos_ancestors xmlPos
579 H.td ! HA.class_ "section-title" $$ do
580 (case List.length $ XML.pos_ancestors xmlPos of
591 liftStateMarkup $ S.modify' $ \s ->
592 s{ state_judgments = state_judgments st }
594 notes <- liftStateMarkup $ S.gets state_notes
595 maybe mempty html5Notes $
596 Map.lookup (XML.pos_ancestors xmlPos) notes
597 liftStateMarkup $ S.modify' $ \s -> s{state_section = state_section st}
598 instance Html5ify Block where
600 BlockPara para -> html5ify para
602 html5CommonAttrs attrs
603 { classes = "page-break":"print-only":classes attrs } $
605 H.p $$ " " -- NOTE: force page break
607 H.nav ! HA.class_ "toc"
608 ! HA.id (attrify $ identify xmlPos) $$ do
609 H.span ! HA.class_ "toc-name" $$
610 H.a ! HA.href (refIdent $ identify xmlPos) $$ do
611 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
612 Plain.l10n_Table_of_Contents l10n
614 State{state_section} <- liftStateMarkup S.get
615 forM_ state_section $ html5ifyToC depth
617 H.nav ! HA.class_ "tof"
618 ! HA.id (attrify $ identify xmlPos) $$
619 H.table ! HA.class_ "tof" $$
623 html5CommonAttrs attrs $
624 H.aside ! HA.class_ "aside" $$ do
625 forM_ blocks html5ify
627 html5CommonAttrs attrs
628 { classes = "figure":("figure-"<>type_):classes attrs
629 , DTC.id = Just $ Ident $ Plain.text def $ XML.pos_ancestorsWithFigureNames xmlPos
632 H.table ! HA.class_ "figure-caption" $$
636 then H.a ! HA.href (refIdent $ identify xmlPos) $$ mempty
638 H.td ! HA.class_ "figure-number" $$ do
639 H.a ! HA.href (refIdent $ identify $ XML.pos_ancestorsWithFigureNames xmlPos) $$ do
641 html5ify $ XML.pos_ancestorsWithFigureNames xmlPos
642 forM_ mayTitle $ \title -> do
643 H.td ! HA.class_ "figure-colon" $$ do
644 unless (TL.null type_) $ do
645 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
646 Plain.l10n_Colon l10n
647 H.td ! HA.class_ "figure-title" $$ do
649 H.div ! HA.class_ "figure-content" $$ do
651 BlockIndex{xmlPos} -> do
652 st@State{..} <- liftStateMarkup S.get
653 liftStateMarkup $ S.put st
654 { state_styles = HS.insert (Left "dtc-index.css") state_styles }
655 let (allTerms,refsByTerm) = state_indexs Map.!xmlPos
656 let chars = Index.termsByChar allTerms
657 H.div ! HA.class_ "index"
658 ! HA.id (attrify $ identify xmlPos) $$ do
659 H.nav ! HA.class_ "index-nav" $$ do
660 forM_ (Map.keys chars) $ \char ->
661 H.a ! HA.href (refIdent (identify xmlPos <> "." <> identify char)) $$
663 H.dl ! HA.class_ "index-chars" $$
664 forM_ (Map.toList chars) $ \(char,terms) -> do
666 let i = identify xmlPos <> "." <> identify char
667 H.a ! HA.id (attrify i)
668 ! HA.href (refIdent i) $$
671 H.dl ! HA.class_ "index-term" $$ do
672 forM_ terms $ \aliases -> do
674 H.ul ! HA.class_ "index-aliases" $$
675 forM_ (List.take 1 aliases) $ \term -> do
676 H.li ! HA.id (attrify $ identifyIref term) $$
680 List.sortBy (compare `on` DTC.section . snd) $
681 (`foldMap` aliases) $ \words ->
683 path <- Index.pathFromWords words
684 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
685 TreeMap.lookup path refsByTerm in
687 (<$> anchs) $ \(term,Anchor{..}) ->
688 H.a ! HA.class_ "index-iref"
689 ! HA.href (refIdent $ identifyIrefCount term count) $$
690 html5ify $ XML.pos_ancestors section
691 BlockReferences{..} ->
692 html5CommonAttrs attrs
693 { classes = "references":classes attrs
694 , DTC.id = Just $ Ident $ Plain.text def $ XML.pos_ancestors xmlPos
700 html5CommonAttrs attrs
701 { classes = "grades":classes attrs
702 , DTC.id = Just $ Ident $ Plain.text def $ XML.pos_ancestors xmlPos
705 -- let dg = List.head $ List.filter default_ scale
706 -- let sc = MJ.Scale (Set.fromList scale) dg
707 -- o :: Map choice grade
708 -- os :: Opinions (Map judge (Opinion choice grade))
712 html5CommonAttrs attrs
713 { classes = "judges":classes attrs
714 , DTC.id = Just $ Ident $ Plain.text def $ XML.pos_ancestors xmlPos
718 instance Html5ify Para where
722 { classes="para":cls item
726 html5CommonAttrs attrs
727 { classes = "para":classes attrs
728 , DTC.id = id_ xmlPos
731 forM_ items $ \item ->
732 html5AttrClass (cls item) $
735 id_ = Just . Ident . Plain.text def . XML.pos_ancestors
738 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
739 ParaQuote{..} -> ["quote", "quote-"<>type_]
743 ParaJudgment{} -> ["judgment"]
744 instance Html5ify ParaItem where
746 ParaPlain p -> H.p $$ html5ify p
747 ParaArtwork{..} -> H.pre $$ do html5ify text
748 ParaQuote{..} -> H.div $$ do html5ify paras
749 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
753 forM_ items $ \ListItem{..} -> do
755 H.td ! HA.class_ "name" $$ do
758 H.td ! HA.class_ "value" $$
762 forM_ items $ \item -> do
764 H.dd $$ html5ify item
765 ParaJudgment j -> html5ify j
766 instance Html5ify Judgment where
767 html5ify Judgment{..} = do
768 st <- liftStateMarkup S.get
771 maybe (Prelude.error $ show grades) MJ.grades $ -- unknown grades
772 HM.lookup grades (Collect.all_grades $ state_collect st)
774 fromMaybe (Prelude.error $ show judges) $ -- unknown judges
775 HM.lookup judges (Collect.all_judges $ state_collect st)
776 let defaultGradeByJudge =
779 [ g | g <- Set.toList judgmentGrades
780 , isDefault $ MJ.unRank g
783 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
784 | DTC.Judge{name,defaultGrades} <- judgmentJudges
785 , let judgeDefaultGrade = do
786 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
788 [ g | g <- Set.toList judgmentGrades
789 , let DTC.Grade{name=n} = MJ.unRank g
793 judgmentChoices <- forM choices $ \c@DTC.Choice{opinions} -> do
794 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade} -> do
796 fromMaybe (Prelude.error $ show grade) $ -- unknown grade
798 [ MJ.singleGrade g | g <- Set.toList judgmentGrades
799 , let Grade{name} = MJ.unRank g
803 case MJ.opinions defaultGradeByJudge $ HM.fromList gradeByJudge of
804 (ok,ko) | null ko -> return (c, ok)
805 | otherwise -> Prelude.error $ show ko -- unknown judge
807 html5Judgment question choices $ HM.fromList judgmentChoices
808 instance Html5ify [Para] where
809 html5ify = mapM_ html5ify
810 instance Html5ify Plain where
816 -- NOTE: gather adjacent PlainNotes
818 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
819 H.sup ! HA.class_ "note-numbers" $$ do
821 forM_ notes $ \note -> do
830 instance Html5ify (Tree PlainNode)
831 where html5ify (Tree n ls) =
833 PlainBreak -> html5ify H.br
834 PlainText t -> html5ify t
835 PlainGroup -> html5ify ls
836 PlainB -> H.strong $$ html5ify ls
837 PlainCode -> H.code $$ html5ify ls
838 PlainDel -> H.del $$ html5ify ls
840 i <- liftStateMarkup $ do
841 i <- S.gets $ Plain.state_italic . state_plainify
844 (state_plainify s){Plain.state_italic=
847 H.em ! HA.class_ (if i then "even" else "odd") $$
852 (state_plainify s){Plain.state_italic=i}}
854 html5CommonAttrs attrs $
855 H.span $$ html5ify ls
856 PlainSub -> H.sub $$ html5ify ls
857 PlainSup -> H.sup $$ html5ify ls
858 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
859 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
862 Nothing -> Prelude.error "[BUG] PlainNote has no number."
864 H.a ! HA.class_ "note-ref"
865 ! HA.id ("note-ref."<>attrify num)
866 ! HA.href ("#note."<>attrify num) $$
869 H.span ! HA.class_ "q" $$ do
870 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
871 Plain.l10n_Quote (html5ify $ Tree PlainI ls) l10n
873 H.a ! HA.class_ "eref"
874 ! HA.href (attrify href) $$
876 then html5ify $ unURL href
880 Nothing -> html5ify ls
881 Just Anchor{count} ->
882 H.span ! HA.class_ "iref"
883 ! HA.id (attrify $ identifyIrefCount term count) $$
885 PlainTag{error} -> do
886 st <- liftStateMarkup S.get
887 let l10n = Plain.state_l10n $ state_plainify st
890 H.a ! HA.class_ "tag"
891 ! HA.href (refIdent $ identifyTitle l10n $ Title ls) $$
893 Just (ErrorTarget_Unknown num) ->
894 H.span ! HA.class_ "tag tag-unknown"
895 ! HA.id (attrify $ identifyTag "-unknown" l10n ls (Just num)) $$
897 Just (ErrorTarget_Ambiguous num) ->
898 H.span ! HA.class_ "tag tag-ambiguous"
899 ! HA.id (attrify $ identifyTag "-ambiguous" l10n ls num) $$
906 H.a ! HA.class_ "reference"
907 ! HA.href (refIdent $ identifyReference "" to Nothing)
908 ! HA.id (attrify $ identifyReference "" to number) $$
913 [Tree (PlainText "") _] -> do
914 refs <- liftStateMarkup $ S.gets $ Collect.all_reference . state_collect
915 case toList <$> HM.lookup to refs of
916 Just [Reference{about=About{..}}] -> do
917 forM_ (List.take 1 titles) $ \(Title title) -> do
918 html5ify $ Tree PlainQ $
921 Just u -> pure $ Tree (PlainEref u) title
926 H.a ! HA.class_ "reference"
927 ! HA.href (refIdent $ identifyReference "" to Nothing)
928 ! HA.id (attrify $ identifyReference "" to number) $$
930 H.span ! HA.class_ "print-only" $$ do
933 Just (ErrorTarget_Unknown num) -> do
935 H.span ! HA.class_ "reference reference-unknown"
936 ! HA.id (attrify $ identifyReference "-unknown" to $ Just num) $$
939 Just (ErrorTarget_Ambiguous num) -> do
942 [Tree (PlainText "") _] -> mempty
947 H.span ! HA.class_ "reference reference-ambiguous"
948 !?? mayAttr HA.id (attrify . identifyReference "-ambiguous" to . Just <$> num) $$
951 instance Html5ify [Title] where
953 html5ify . fold . List.intersperse sep . toList
954 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
955 instance Html5ify About where
956 html5ify About{..} = do
958 [ html5CommasDot $ concat $
960 , html5ify <$> authors
961 , html5ify <$> maybeToList date
962 , html5ify <$> maybeToList editor
963 , html5ify <$> series
966 H.span ! HA.class_ "print-only" $$ do
972 html5Titles :: [Title] -> [HTML5]
973 html5Titles ts | null ts = []
974 html5Titles ts = [html5Title $ joinTitles ts]
976 joinTitles = fold . List.intersperse sep . toList
977 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
978 html5Title (Title title) =
979 html5ify $ Tree PlainQ $
982 Just u -> pure $ Tree (PlainEref u) title
983 instance Html5ify Serie where
984 html5ify s@Serie{id=id_, name} = do
985 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
989 Plain.l10n_Colon l10n :: HTML5
993 Tree PlainEref{href} $
995 [ tree0 $ PlainText $ unName name
996 , tree0 $ PlainText $ Plain.l10n_Colon l10n
997 , tree0 $ PlainText id_
999 instance Html5ify Entity where
1000 html5ify Entity{..} = do
1002 _ | not (TL.null email) -> do
1003 H.span ! HA.class_ "no-print" $$
1005 Tree (PlainEref $ URL $ "mailto:"<>email) $
1006 pure $ tree0 $ PlainText name
1007 H.span ! HA.class_ "print-only" $$
1009 Tree PlainGroup $ Seq.fromList
1010 [ tree0 $ PlainText name
1011 , tree0 $ PlainText " <"
1012 , Tree (PlainEref $ URL $ "mailto:"<>email) $
1013 pure $ tree0 $ PlainText email
1014 , tree0 $ PlainText ">"
1016 _ | Just u <- url ->
1018 Tree (PlainEref u) $
1019 pure $ tree0 $ PlainText name
1022 tree0 $ PlainText name
1023 forM_ org $ \o -> do
1027 instance Html5ify Words where
1028 html5ify = html5ify . Index.plainifyWords
1029 instance Html5ify Alias where
1030 html5ify Alias{..} = do
1031 st@State{state_collect=Collect.All{..}} <- liftStateMarkup S.get
1032 let l10n = Plain.state_l10n $ state_plainify st
1033 case toList <$> HM.lookup title all_section of
1035 H.a ! HA.class_ "alias"
1036 ! HA.id (attrify $ identifyTitle l10n title) $$
1039 instance Html5ify URL where
1040 html5ify (URL url) =
1041 H.a ! HA.class_ "eref"
1042 ! HA.href (attrify url) $$
1044 instance Html5ify Date where
1046 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
1047 Plain.l10n_Date date l10n
1048 instance Html5ify Reference where
1049 html5ify Reference{..} =
1051 H.td ! HA.class_ "reference-key" $$
1052 html5ify $ tree0 PlainRref
1056 , error = (<$> error) $ \case
1057 ErrorAnchor_Ambiguous num -> ErrorTarget_Ambiguous (Just num)
1059 H.td ! HA.class_ "reference-content" $$ do
1061 rrefs <- liftStateMarkup $ S.gets state_rrefs
1062 case HM.lookup id rrefs of
1065 H.span ! HA.class_ "reference-rrefs" $$
1067 (<$> List.reverse anchs) $ \(maySection,num) ->
1068 H.a ! HA.class_ "reference-rref"
1069 ! HA.href (refIdent $ identifyReference "" id $ Just num) $$
1071 Nothing -> "0"::HTML5
1072 Just Section{xmlPos=posSection} -> html5ify $ XML.pos_ancestors posSection
1073 instance Html5ify XML.Ancestors where
1081 Text.intercalate "." $
1082 Text.pack . show . snd <$> as
1083 instance Html5ify Plain.Plain where
1085 sp <- liftStateMarkup $ S.gets state_plainify
1086 let (t,sp') = Plain.runPlain p sp
1088 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
1090 instance Html5ify SVG.Element where
1093 B.preEscapedLazyText $
1095 instance Semigroup SVG.Element where
1099 html5CommasDot :: [HTML5] -> HTML5
1100 html5CommasDot [] = pure ()
1101 html5CommasDot hs = do
1102 sequence_ $ List.intersperse ", " hs
1105 html5Lines :: [HTML5] -> HTML5
1106 html5Lines hs = sequence_ $ List.intersperse (html5ify H.br) hs
1108 html5Words :: [HTML5] -> HTML5
1109 html5Words hs = sequence_ $ List.intersperse " " hs
1111 html5AttrClass :: [TL.Text] -> HTML5 -> HTML5
1112 html5AttrClass = \case
1116 (H.AddCustomAttribute "class"
1117 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
1120 html5AttrId :: Ident -> HTML5 -> HTML5
1121 html5AttrId (Ident id_) =
1123 (H.AddCustomAttribute "id"
1124 (H.String $ TL.unpack id_) <$>) .
1127 html5CommonAttrs :: CommonAttrs -> HTML5 -> HTML5
1128 html5CommonAttrs CommonAttrs{id=id_, ..} =
1129 html5AttrClass classes .
1130 maybe Cat.id html5AttrId id_
1132 html5SectionNumber :: XML.Ancestors -> HTML5
1133 html5SectionNumber = go mempty
1135 go :: XML.Ancestors -> XML.Ancestors -> HTML5
1137 case Seq.viewl next of
1138 Seq.EmptyL -> pure ()
1139 a@(_n,rank) Seq.:< as -> do
1140 H.a ! HA.href (refIdent $ identify $ prev Seq.|> a) $$
1141 html5ify $ show rank
1142 when (not (null as) || null prev) $ do
1144 go (prev Seq.|>a) as
1146 html5SectionRef :: XML.Ancestors -> HTML5
1147 html5SectionRef as =
1148 H.a ! HA.href (refIdent $ identify as) $$
1151 html5Notes :: IntMap [Para] -> HTML5
1153 H.aside ! HA.class_ "notes" $$ do
1157 forM_ (IntMap.toList notes) $ \(number,content) ->
1159 H.td ! HA.class_ "note-ref" $$ do
1160 H.a ! HA.class_ "note-number"
1161 ! HA.id ("note."<>attrify number)
1162 ! HA.href ("#note."<>attrify number) $$ do
1165 H.a ! HA.href ("#note-ref."<>attrify number) $$ do
1170 html5ifyToC :: Maybe DTC.Nat -> Tree BodyNode -> HTML5
1171 html5ifyToC depth (Tree b bs) =
1173 BodySection Section{..} -> do
1175 H.table ! HA.class_ "toc-entry" $$
1178 H.td ! HA.class_ "section-number" $$
1179 html5SectionRef $ XML.pos_ancestors xmlPos
1180 H.td ! HA.class_ "section-title" $$
1181 html5ify $ cleanPlain $ unTitle title
1182 when (maybe True (> Nat 1) depth && not (null sections)) $
1185 html5ifyToC (depth >>= predNat)
1189 (`Seq.filter` bs) $ \case
1190 Tree BodySection{} _ -> True
1193 html5ifyToF :: [TL.Text] -> HTML5
1194 html5ifyToF types = do
1195 figuresByType <- liftStateMarkup $ S.gets $ Collect.all_figure . state_collect
1197 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
1201 Map.intersection figuresByType $
1202 Map.fromList [(ty,()) | ty <- types]
1203 forM_ (Map.toList figures) $ \(xmlPos, (type_, title)) ->
1205 H.td ! HA.class_ "figure-number" $$
1206 H.a ! HA.href (refIdent $ identify xmlPos) $$ do
1208 html5ify $ XML.pos_ancestors xmlPos
1209 forM_ title $ \ti ->
1210 H.td ! HA.class_ "figure-title" $$
1211 html5ify $ cleanPlain $ unTitle ti
1216 MJ.OpinionsByChoice Choice Name (MJ.Ranked Grade) ->
1218 html5Judgment question choices distByJudgeByChoice = do
1219 let commentJGC = HM.fromList
1220 [ (choice_, HM.fromListWith (<>)
1221 [ (grade, HM.singleton judge comment)
1222 | Opinion{..} <- opinions ])
1223 | choice_@Choice{opinions} <- choices ]
1226 Just title -> H.div ! HA.class_ "question" $$ html5ify title
1227 H.dl ! HA.class_ "choices" $$ do
1228 let meritByChoice@(MJ.MeritByChoice meritC) = MJ.meritByChoice distByJudgeByChoice
1229 let ranking = MJ.majorityRanking meritByChoice
1230 forM_ ranking $ \(choice_@DTC.Choice{title}, majorityValue) -> do
1231 H.dt ! HA.class_ "choice-title" $$ do
1233 H.dd ! HA.class_ "choice-merit" $$ do
1234 let distByJudge = distByJudgeByChoice HM.!choice_
1235 let numJudges = HM.size distByJudge
1236 html5MeritHistogram majorityValue numJudges
1237 let grades = Map.keys $ MJ.unMerit $ meritC HM.!choice_
1238 let commentJG = HM.lookup choice_ commentJGC
1239 html5MeritComments distByJudge grades commentJG
1241 html5MeritComments ::
1242 MJ.Opinions Name (MJ.Ranked Grade) ->
1243 [MJ.Ranked Grade] ->
1244 Maybe (HM.HashMap Name (HM.HashMap Name (Maybe Title))) ->
1246 html5MeritComments distJ grades commentJG = do
1247 Loqualization l10n <- liftStateMarkup $ S.gets state_l10n
1248 H.ul ! HA.class_ "merit-comments" $$ do
1249 forM_ grades $ \grade@(MJ.unRank -> DTC.Grade{name=grade_name, color}) -> do
1250 let commentJ = commentJG >>= HM.lookup grade_name
1251 let judgesWithComment =
1252 -- FIXME: sort accents better: « e é f » not « e f é »
1253 List.sortOn (TL.map Char.toLower . unName . (\(j,_,_) -> j))
1254 [ (judge, importance, commentJ >>= HM.lookupDefault Nothing judge)
1255 | (judge, dist) <- HM.toList distJ
1256 , importance <- maybeToList $ Map.lookup grade dist ]
1257 forM_ judgesWithComment $ \(judge, importance, comment) ->
1258 H.li ! HA.class_ ("merit-comment" <> if isJust comment then " judge-comment" else "") $$ do
1260 ! HA.class_ ("judge" <> if judge`HM.member`fromMaybe HM.empty commentJ then "" else " inactive")
1261 ! HA.style ("color:"<>attrify color<>";") $$ do
1262 unless (importance == 1) $ do
1263 H.span ! HA.class_ "section-importance" $$ do
1265 (round::Double -> Int) $
1266 fromRational $ importance * 100
1267 html5ify $ show percent
1273 Plain.l10n_Colon l10n :: HTML5
1276 html5MeritHistogram :: MJ.MajorityValue (MJ.Ranked Grade) -> Int -> HTML5
1277 html5MeritHistogram (MJ.MajorityValue majVal) numJudges = do
1278 H.div ! HA.class_ "merit-histogram" $$ do
1279 forM_ majVal $ \(MJ.unRank -> DTC.Grade{name=grade_name, title=grade_title, color},count) -> do
1280 let percent :: Double =
1281 fromRational $ (toRational $ (ceiling::Double -> Int) $ fromRational $
1282 (count / toRational numJudges) * 100 * 1000) / 1000
1283 let bcolor = "background-color:"<>attrify color<>";"
1284 let width = "width:"<>attrify percent<>"%;"
1285 let display = if percent == 0 then "display:none;" else ""
1287 ! HA.class_ "merit-grade"
1288 ! HA.alt (attrify grade_name) -- FIXME: do not work
1289 ! HA.style (bcolor<>display<>width) $$ do
1291 ! HA.class_ "grade-name" $$ do
1293 Nothing -> html5ify grade_name
1294 Just t -> html5ify t
1296 html5Judgments :: HTML5
1298 Collect.All{..} <- liftStateMarkup $ S.gets state_collect
1299 opinionsByChoiceByNodeBySectionByJudgment <-
1300 forM (HM.toList all_judgments) $ \(judgment@Judgment{judges,grades}, choicesBySection) -> do
1301 -- WARNING: only the fields of 'Judgment' used in its 'Hashable' instance
1302 -- can safely be used here: 'judges' and 'grades' are ok
1303 let judgmentGrades =
1304 maybe (Prelude.error $ show grades) MJ.grades $ -- unknown grades
1305 HM.lookup grades all_grades
1306 let judgmentJudges =
1307 fromMaybe (Prelude.error $ show judges) $ -- unknown judges
1308 HM.lookup judges all_judges
1309 let defaultGradeByJudge =
1312 [ g | g <- Set.toList judgmentGrades
1313 , isDefault $ MJ.unRank g
1316 [ (name, defaultGrade`fromMaybe`judgeDefaultGrade)
1317 | DTC.Judge{name,defaultGrades} <- judgmentJudges
1318 , let judgeDefaultGrade = do
1319 jdg <- listToMaybe [g | (n,g) <- defaultGrades, n == grades]
1321 [ g | g <- Set.toList judgmentGrades
1322 , let DTC.Grade{name=n} = MJ.unRank g
1326 opinionsByChoiceByNodeBySection <-
1327 forM choicesBySection $ \choicesTree -> do
1328 judgmentTree <- forM choicesTree $ \(section_importance, choices) -> do
1329 judgmentOpinions <- forM choices $ \choice_@DTC.Choice{opinions} -> do
1330 gradeByJudge <- forM opinions $ \DTC.Opinion{judge,grade,importance} -> do
1332 [ g | g <- Set.toList judgmentGrades
1333 , let Grade{name} = MJ.unRank g
1336 Just grd -> return (judge, MJ.Section importance (Just grd))
1337 Nothing -> Prelude.error $ show grade -- unknown grade
1338 return (choice_, HM.fromList gradeByJudge)
1339 return $ MJ.SectionNode section_importance $ HM.fromList judgmentOpinions
1340 let judgmentChoices = HS.fromList $ snd $ Tree.rootLabel choicesTree
1341 -- NOTE: choices are determined by those at the root Tree.Node.
1342 -- NOTE: core Majority Judgment calculus handled here by MJ
1343 case MJ.opinionsBySection judgmentChoices defaultGradeByJudge judgmentTree of
1344 Right opinionsByChoiceByNode -> return opinionsByChoiceByNode
1345 Left err -> Prelude.error $ show err -- unknown choice, unknown judge, invalid shares
1346 -- NOTE: 'toList' returns a self-then-descending-then-following traversal of a 'Tree',
1347 -- this will match perfectly withw the 'html5ify' traversal:
1348 -- 'BodySection' by 'BodySection'.
1349 return (judgment, join $ toList <$> opinionsByChoiceByNodeBySection)
1350 liftStateMarkup $ S.modify' $ \st ->
1351 st{state_opinions = HM.fromList opinionsByChoiceByNodeBySectionByJudgment}
1354 instance Attrify Plain.Plain where
1355 attrify p = attrify t
1356 where (t,_) = Plain.runPlain p def
1360 ( Plain.L10n msg lang
1361 , Plain.L10n TL.Text lang
1362 ) => L10n msg lang where
1363 l10n_Header_Address :: FullLocale lang -> msg
1364 l10n_Header_Date :: FullLocale lang -> msg
1365 l10n_Header_Version :: FullLocale lang -> msg
1366 l10n_Header_Origin :: FullLocale lang -> msg
1367 l10n_Header_Source :: FullLocale lang -> msg
1368 l10n_Errors_All :: FullLocale lang -> Nat -> msg
1369 l10n_Error_Tag_unknown :: FullLocale lang -> msg
1370 l10n_Error_Tag_ambiguous :: FullLocale lang -> msg
1371 l10n_Error_Rref_unknown :: FullLocale lang -> msg
1372 l10n_Error_Reference_ambiguous :: FullLocale lang -> msg
1373 instance L10n HTML5 EN where
1374 l10n_Header_Address _l10n = "Address"
1375 l10n_Header_Date _l10n = "Date"
1376 l10n_Header_Origin _l10n = "Origin"
1377 l10n_Header_Source _l10n = "Source"
1378 l10n_Header_Version _l10n = "Version"
1379 l10n_Errors_All _l10n n = "All errors ("<>html5ify n<>")"
1380 l10n_Error_Tag_unknown _l10n = "Unknown tag"
1381 l10n_Error_Tag_ambiguous _l10n = "Ambiguous tag"
1382 l10n_Error_Rref_unknown _l10n = "Unknown reference"
1383 l10n_Error_Reference_ambiguous _l10n = "Ambiguous reference"
1384 instance L10n HTML5 FR where
1385 l10n_Header_Address _l10n = "Adresse"
1386 l10n_Header_Date _l10n = "Date"
1387 l10n_Header_Origin _l10n = "Origine"
1388 l10n_Header_Source _l10n = "Source"
1389 l10n_Header_Version _l10n = "Version"
1390 l10n_Errors_All _l10n n = "Toutes les erreurs ("<>html5ify n<>")"
1391 l10n_Error_Tag_unknown _l10n = "Tag inconnu"
1392 l10n_Error_Tag_ambiguous _l10n = "Tag ambigu"
1393 l10n_Error_Rref_unknown _l10n = "Référence inconnue"
1394 l10n_Error_Reference_ambiguous _l10n = "Référence ambiguë"
1396 instance Plain.L10n HTML5 EN where
1397 l10n_Colon l10n = html5ify (Plain.l10n_Colon l10n :: TL.Text)
1398 l10n_Table_of_Contents l10n = html5ify (Plain.l10n_Table_of_Contents l10n :: TL.Text)
1399 l10n_Date date l10n = html5ify (Plain.l10n_Date date l10n :: TL.Text)
1400 l10n_Quote msg _l10n = do
1401 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1402 let (o,c) :: (HTML5, HTML5) =
1403 case unNat depth `mod` 3 of
1408 setDepth $ succNat depth
1414 liftStateMarkup $ S.modify' $ \s ->
1415 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
1416 instance Plain.L10n HTML5 FR where
1417 l10n_Colon l10n = html5ify (Plain.l10n_Colon l10n :: TL.Text)
1418 l10n_Table_of_Contents l10n = html5ify (Plain.l10n_Table_of_Contents l10n :: TL.Text)
1419 l10n_Date date l10n = html5ify (Plain.l10n_Date date l10n :: TL.Text)
1420 l10n_Quote msg _l10n = do
1421 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
1422 let (o,c) :: (HTML5, HTML5) =
1423 case unNat depth `mod` 3 of
1428 setDepth $ succNat depth
1434 liftStateMarkup $ S.modify' $ \s ->
1435 s{state_plainify=(state_plainify s){Plain.state_quote=d}}