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 {-# OPTIONS_GHC -fno-warn-orphans #-}
11 module Language.DTC.Write.HTML5 where
13 import Control.Applicative (Applicative(..))
14 import Control.Category as Cat
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.Map.Strict (Map)
27 import Data.Maybe (Maybe(..), maybe, mapMaybe, fromJust, maybeToList)
28 import Data.Monoid (Monoid(..))
29 import Data.Ord (Ord(..))
30 import Data.Semigroup (Semigroup(..))
31 import Data.String (String, IsString(..))
32 import Data.Text (Text)
33 import Data.TreeSeq.Strict (Tree(..), tree0)
34 import Data.Tuple (snd)
36 import System.FilePath (FilePath)
37 import Text.Blaze ((!))
38 import Text.Blaze.Html (Html)
39 import Text.Show (Show(..))
40 import qualified Control.Monad.Trans.State as S
41 import qualified Data.List as List
42 import qualified Data.Map.Strict as Map
43 import qualified Data.Sequence as Seq
44 import qualified Data.Strict.Maybe as Strict
45 import qualified Data.Text as Text
46 import qualified Data.Text.Lazy as TL
47 import qualified Data.TreeMap.Strict as TreeMap
48 import qualified Data.TreeSeq.Strict.Zipper as Tree
49 import qualified Text.Blaze.Html5 as H
50 import qualified Text.Blaze.Html5.Attributes as HA
51 import qualified Text.Blaze.Internal as H
53 import Text.Blaze.Utils
54 import Data.Locale hiding (Index)
56 import Language.DTC.Document as DTC
57 import Language.DTC.Write.Plain (Plainify(..))
58 import Language.DTC.Write.XML ()
59 import qualified Language.DTC.Anchor as Anchor
60 import qualified Language.DTC.Write.Plain as Plain
62 writeHTML5 :: Config -> DTC.Document -> Html
63 writeHTML5 conf@Config{..} DTC.Document{..} = do
64 let Keys{..} = keys body `S.execState` def
65 let (body',state_rrefs,state_notes,state_indexs) =
66 let irefs = foldMap Anchor.irefsOfTerms keys_index in
67 let (body0, Anchor.State{state_irefs, state_rrefs=rrefs, state_notes=notes}) =
68 Anchor.anchorify body `S.runState`
69 def{Anchor.state_irefs=irefs} in
70 (body0,rrefs,notes,) $
71 (<$> keys_index) $ \terms ->
73 TreeMap.intersection const state_irefs $
74 Anchor.irefsOfTerms terms
75 let state_plainify = def{ Plain.state_l10n = loqualize config_locale}
76 let (html5Body, endState) =
81 , state_figures = keys_figure
82 , state_references = keys_reference
84 , state_l10n = loqualize config_locale
86 html5DocumentHead head
89 H.html ! HA.lang (attrify $ countryCode config_locale) $ do
90 html5Head conf endState head body
93 html5Head :: Config -> State -> Head -> Body -> Html
94 html5Head Config{..} State{..} Head{DTC.about=About{..}} body = do
96 H.meta ! HA.httpEquiv "Content-Type"
97 ! HA.content "text/html; charset=UTF-8"
98 unless (null titles) $ do
100 H.toMarkup $ Plain.text state_plainify $ List.head titles
101 forM_ links $ \Link{..} ->
103 "stylesheet" | URL "" <- href ->
104 H.style ! HA.type_ "text/css" $
105 H.toMarkup $ Plain.text def plain
107 H.link ! HA.rel (attrify rel)
108 ! HA.href (attrify href)
110 H.link ! HA.rel "self"
111 ! HA.href (attrify href)
112 unless (TL.null config_generator) $ do
113 H.meta ! HA.name "generator"
114 ! HA.content (attrify config_generator)
116 H.meta ! HA.name "keywords"
117 ! HA.content (attrify $ TL.intercalate ", " tags)
119 (`mapMaybe` toList body) $ \case
120 Tree k@BodySection{} _ -> Just k
122 forM_ chapters $ \case
124 H.link ! HA.rel "Chapter"
125 ! HA.title (attrify $ plainify title)
126 ! HA.href ("#"<>attrify pos)
128 unless (any (\DTC.Link{..} -> rel == "stylesheet" && href /= URL "") links) $ do
132 H.link ! HA.rel "stylesheet"
133 ! HA.type_ "text/css"
134 ! HA.href (attrify css)
136 H.style ! HA.type_ "text/css" $
137 -- NOTE: as a special case, H.style wraps its content into an External,
138 -- so it does not HTML-escape its content.
140 forM_ state_styles $ \style ->
141 H.style ! HA.type_ "text/css" $
143 unless (any (\DTC.Link{rel} -> rel == "script") links) $ do
144 forM_ state_scripts $ \script ->
145 H.script ! HA.type_ "application/javascript" $
148 html5DocumentHead :: Head -> Html5
149 html5DocumentHead Head{DTC.about=About{..}} = do
150 H.div ! HA.class_ "document-head" $$
154 H.td ! HA.class_ "left" $$ docHeaders
155 H.td ! HA.class_ "right" $$ docAuthors
156 unless (null titles) $
157 H.div ! HA.class_ "title" $$ do
158 forM_ titles $ \title ->
159 H.h1 $$ html5ify title
162 H.table ! HA.class_ "document-headers" $$
164 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
165 forM_ series $ \s@Serie{id=id_, name} ->
169 headerName $ html5ify name
170 headerValue $ html5ify id_
172 headerName $ html5ify name
174 H.a ! HA.href (attrify href) $$
176 forM_ links $ \Link{..} ->
177 unless (TL.null name) $
179 headerName $ html5ify name
180 headerValue $ html5ify $ Tree PlainEref{href} plain
183 headerName $ l10n_Header_Date loc
184 headerValue $ html5ify d
187 headerName $ l10n_Header_Address loc
188 headerValue $ html5ify $ tree0 $ PlainEref{href}
189 forM_ headers $ \Header{..} ->
191 headerName $ html5ify name
192 headerValue $ html5ify value
194 H.table ! HA.class_ "document-authors" $$
196 forM_ authors $ \a ->
198 H.td ! HA.class_ "author" $$
200 header :: Html5 -> Html5
201 header h = H.tr ! HA.class_ "header" $$ h
202 headerName :: Html5 -> Html5
204 H.td ! HA.class_ "header-name" $$ do
206 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
208 headerValue :: Html5 -> Html5
210 H.td ! HA.class_ "header-value" $$ do
217 , Loqualize locales (L10n Html5)
218 , Loqualize locales (Plain.L10n Plain.Plain)
221 { config_css :: Either FilePath TL.Text
222 , config_locale :: LocaleIn locales
223 , config_generator :: TL.Text
225 instance Default Config where
227 { config_css = Right "style/dtc-html5.css"
228 , config_locale = LocaleIn @'[EN] en_US
229 , config_generator = "https://hackage.haskell.org/package/hdoc"
233 type Html5 = StateMarkup State ()
234 instance IsString Html5 where
235 fromString = html5ify
240 { state_styles :: Map FilePath TL.Text
241 , state_scripts :: Map FilePath TL.Text
242 , state_indexs :: Map DTC.Pos (Terms, Anchor.Irefs)
243 , state_rrefs :: Anchor.Rrefs
244 , state_figures :: Map TL.Text (Map DTC.Pos (Maybe Title))
245 , state_references :: Map Ident About
246 , state_notes :: Anchor.Notes
247 , state_plainify :: Plain.State
248 , state_l10n :: Loqualization (L10n Html5)
250 instance Default State where
253 , state_scripts = def
256 , state_figures = def
257 , state_references = def
259 , state_plainify = def
260 , state_l10n = Loqualization EN_US
266 { keys_index :: Map DTC.Pos Terms
267 , keys_figure :: Map TL.Text (Map DTC.Pos (Maybe Title))
268 , keys_reference :: Map Ident About
270 instance Default Keys where
271 def = Keys mempty mempty mempty
275 keys :: a -> S.State Keys ()
276 instance KeysOf Body where
278 instance KeysOf (Tree BodyNode) where
281 BodySection{..} -> keys ts
282 BodyBlock b -> keys b
283 instance KeysOf DTC.Block where
285 BlockPara{} -> return ()
286 BlockBreak{} -> return ()
287 BlockToC{} -> return ()
288 BlockToF{} -> return ()
290 S.modify $ \s -> s{keys_index=
291 Map.insert pos terms $ keys_index s}
293 S.modify $ \s -> s{keys_figure=
295 type_ (Map.singleton pos mayTitle) $
297 BlockReferences{..} ->
298 S.modify $ \s -> s{keys_reference=
301 (DTC.id (r::DTC.Reference))
302 (DTC.about (r::DTC.Reference)))
306 -- * Class 'Html5ify'
307 class Html5ify a where
308 html5ify :: a -> Html5
309 instance Html5ify H.Markup where
310 html5ify = Compose . return
311 instance Html5ify Char where
312 html5ify = html5ify . H.toMarkup
313 instance Html5ify Text where
314 html5ify = html5ify . H.toMarkup
315 instance Html5ify TL.Text where
316 html5ify = html5ify . H.toMarkup
317 instance Html5ify String where
318 html5ify = html5ify . H.toMarkup
319 instance Html5ify Title where
320 html5ify (Title t) = html5ify t
321 instance Html5ify Ident where
322 html5ify (Ident i) = html5ify i
323 instance Html5ify Int where
324 html5ify = html5ify . show
325 instance Html5ify Nat where
326 html5ify (Nat n) = html5ify n
327 instance Html5ify Nat1 where
328 html5ify (Nat1 n) = html5ify n
329 instance Html5ify a => Html5ify (Maybe a) where
330 html5ify = foldMap html5ify
332 -- * Type 'BodyCursor'
333 -- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
334 type BodyCursor = Tree.Zipper BodyNode
335 instance Html5ify Body where
337 forM_ (Tree.zippers body) $ \z ->
338 forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
340 instance Html5ify BodyCursor
342 let Tree n _ts = Tree.current z in
344 BodyBlock BlockToC{..} -> do
345 H.nav ! HA.class_ "toc"
346 ! HA.id (attrify pos) $$ do
347 H.span ! HA.class_ "toc-name" $$
348 H.a ! HA.href ("#"<>attrify pos) $$ do
349 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
350 Plain.l10n_Table_of_Contents loc
352 forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
354 BodyBlock b -> html5ify b
355 BodySection{..} -> do
357 notes <- liftStateMarkup $ S.gets state_notes
359 p <- posParent $ posAncestors pos
360 let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p notes
364 Just (secNotes, state_notes) -> do
365 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
367 html5CommonAttrs attrs{classes="section":classes attrs} $
368 H.section ! HA.id (attrify pos) $$ do
369 forM_ aliases html5ify
370 H.table ! HA.class_ "section-header" $$
373 H.td ! HA.class_ "section-number" $$ do
374 html5SectionNumber $ DTC.posAncestors pos
375 H.td ! HA.class_ "section-title" $$ do
376 (case List.length $ DTC.posAncestors pos of
385 forM_ (Tree.axis_child `Tree.runAxis` z) $
387 notes <- liftStateMarkup $ S.gets state_notes
388 html5ify $ Map.lookup (posAncestors pos) notes
389 instance Html5ify [Anchor.Note] where
391 H.aside ! HA.class_ "notes" $$ do
395 forM_ (List.reverse notes) $ \Anchor.Note{..} ->
397 H.td ! HA.class_ "note-ref" $$ do
398 H.a ! HA.class_ "note-number"
399 ! HA.id ("note."<>attrify note_number)
400 ! HA.href ("#note."<>attrify note_number) $$ do
403 H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
406 html5ify note_content
407 instance Html5ify Block where
409 BlockPara para -> html5ify para
411 html5CommonAttrs attrs
412 { classes = "page-break":"print-only":classes attrs } $
414 H.p $$ " " -- NOTE: force page break
415 BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
417 H.nav ! HA.class_ "tof"
418 ! HA.id (attrify pos) $$
419 H.table ! HA.class_ "tof" $$
423 html5CommonAttrs attrs
424 { classes = "figure":("figure-"<>type_):classes attrs
425 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
428 H.table ! HA.class_ "figure-caption" $$
432 then H.a ! HA.href ("#"<>attrify pos) $$ mempty
434 H.td ! HA.class_ "figure-number" $$ do
435 H.a ! HA.href ("#"<>attrify (DTC.posAncestorsWithFigureNames pos)) $$ do
437 html5ify $ DTC.posAncestorsWithFigureNames pos
438 forM_ mayTitle $ \title -> do
439 H.td ! HA.class_ "figure-colon" $$ do
440 unless (TL.null type_) $ do
441 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
443 H.td ! HA.class_ "figure-title" $$ do
445 H.div ! HA.class_ "figure-content" $$ do
447 BlockIndex{pos} -> do
448 (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
449 let chars = Anchor.termsByChar allTerms
450 H.div ! HA.class_ "index"
451 ! HA.id (attrify pos) $$ do
452 H.nav ! HA.class_ "index-nav" $$ do
453 forM_ (Map.keys chars) $ \char ->
454 H.a ! HA.href ("#"<>(attrify pos <> "." <> attrify char)) $$
456 H.dl ! HA.class_ "index-chars" $$
457 forM_ (Map.toList chars) $ \(char,terms) -> do
459 let i = attrify pos <> "." <> attrify char in
461 ! HA.href ("#"<>i) $$
464 H.dl ! HA.class_ "index-term" $$ do
465 forM_ terms $ \aliases -> do
467 H.ul ! HA.class_ "index-aliases" $$
468 forM_ (List.take 1 aliases) $ \term ->
469 H.li ! HA.id (attrifyIref term) $$
473 List.sortBy (compare `on` DTC.section . snd) $
474 (`foldMap` aliases) $ \words ->
476 path <- Anchor.pathFromWords words
477 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
478 TreeMap.lookup path refsByTerm in
480 (<$> anchs) $ \(term,DTC.Anchor{..}) ->
481 H.a ! HA.class_ "index-iref"
482 ! HA.href ("#"<>attrifyIrefCount term count) $$
483 html5ify $ DTC.posAncestors section
484 BlockReferences{..} ->
485 html5CommonAttrs attrs
486 { classes = "references":classes attrs
487 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
493 html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
494 html5ifyToC depth z =
495 let Tree n _ts = Tree.current z in
497 BodySection{..} -> do
499 H.table ! HA.class_ "toc-entry" $$
502 H.td ! HA.class_ "section-number" $$
503 html5SectionRef $ DTC.posAncestors pos
504 H.td ! HA.class_ "section-title" $$
505 html5ify $ cleanPlain $ unTitle title
506 when (maybe True (> Nat 1) depth && not (null sections)) $
509 html5ifyToC (depth >>= predNat)
515 `Tree.axis_filter_current` \case
516 Tree BodySection{} _ -> True
519 html5ifyToF :: [TL.Text] -> Html5
520 html5ifyToF types = do
521 figsByType <- liftStateMarkup $ S.gets state_figures
523 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
527 Map.intersection figsByType $
528 Map.fromList [(ty,()) | ty <- types]
529 forM_ (Map.toList figs) $ \(pos, (type_, title)) ->
531 H.td ! HA.class_ "figure-number" $$
532 H.a ! HA.href ("#"<>attrify pos) $$ do
534 html5ify $ DTC.posAncestors pos
536 H.td ! HA.class_ "figure-title" $$
537 html5ify $ cleanPlain $ unTitle ti
539 cleanPlain :: Plain -> Plain
542 Tree PlainIref{} ls -> cleanPlain ls
543 Tree PlainNote{} _ -> mempty
544 Tree n ts -> pure $ Tree n $ cleanPlain ts
546 instance Html5ify Para where
550 { classes="para":cls item
554 html5CommonAttrs attrs
555 { classes = "para":classes attrs
559 forM_ items $ \item ->
560 html5AttrClass (cls item) $
563 id_ = Just . Ident . Plain.text def . DTC.posAncestors
566 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
567 ParaQuote{..} -> ["quote", "quote-"<>type_]
571 instance Html5ify ParaItem where
573 ParaPlain p -> H.p $$ html5ify p
574 ParaArtwork{..} -> H.pre $$ do html5ify text
575 ParaQuote{..} -> H.div $$ do html5ify paras
576 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
580 forM_ items $ \ListItem{..} -> do
582 H.td ! HA.class_ "name" $$ do
585 H.td ! HA.class_ "value" $$
589 forM_ items $ \item -> do
591 H.dd $$ html5ify item
592 instance Html5ify [Para] where
593 html5ify = mapM_ html5ify
595 instance Html5ify Plain where
601 -- NOTE: gather adjacent PlainNotes
603 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
604 H.sup ! HA.class_ "note-numbers" $$ do
606 forM_ notes $ \note -> do
615 instance Html5ify (Tree PlainNode)
616 where html5ify (Tree n ls) =
618 PlainBreak -> html5ify H.br
619 PlainText t -> html5ify t
620 PlainGroup -> html5ify ls
621 PlainB -> H.strong $$ html5ify ls
622 PlainCode -> H.code $$ html5ify ls
623 PlainDel -> H.del $$ html5ify ls
625 i <- liftStateMarkup $ do
626 i <- S.gets $ Plain.state_italic . state_plainify
629 (state_plainify s){Plain.state_italic=
632 H.em ! HA.class_ (if i then "even" else "odd") $$
637 (state_plainify s){Plain.state_italic=i}}
638 PlainSub -> H.sub $$ html5ify ls
639 PlainSup -> H.sup $$ html5ify ls
640 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
641 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
646 H.a ! HA.class_ "note-ref"
647 ! HA.id ("note-ref."<>attrify num)
648 ! HA.href ("#note."<>attrify num) $$
651 H.span ! HA.class_ "q" $$ do
652 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
653 Plain.l10n_Quote (html5ify $ Tree PlainI ls) loc
655 H.a ! HA.class_ "eref"
656 ! HA.href (attrify href) $$
658 then html5ify $ unURL href
662 Nothing -> html5ify ls
664 H.span ! HA.class_ "iref"
665 ! HA.id (attrifyIrefCount term count) $$
668 H.a ! HA.class_ "ref"
669 ! HA.href ("#"<>attrify to) $$
674 refs <- liftStateMarkup $ S.gets state_references
675 case Map.lookup to refs of
678 H.span ! HA.class_ "rref-broken" $$
683 forM_ (List.take 1 titles) $ \(Title title) -> do
684 html5ify $ Tree PlainQ $
687 Just u -> pure $ Tree (PlainEref u) title
690 H.a ! HA.class_ "rref"
691 ! HA.href ("#rref."<>attrify to)
692 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
696 instance Html5ify [Title] where
698 html5ify . fold . List.intersperse sep . toList
699 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
700 instance Html5ify About where
702 html5CommasDot $ concat $
704 , html5ify <$> authors
705 , html5ify <$> maybeToList date
706 , html5ify <$> maybeToList editor
707 , html5ify <$> series
710 html5Titles :: [Title] -> [Html5]
711 html5Titles ts | null ts = []
712 html5Titles ts = [html5Title $ joinTitles ts]
714 joinTitles = fold . List.intersperse sep . toList
715 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
716 html5Title (Title title) =
717 html5ify $ Tree PlainQ $
720 Just u -> pure $ Tree (PlainEref u) title
721 instance Html5ify Serie where
722 html5ify s@Serie{id=id_, name} = do
723 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
727 Plain.l10n_Colon loc :: Html5
731 Tree PlainEref{href} $
733 [ tree0 $ PlainText $ name
734 , tree0 $ PlainText $ Plain.l10n_Colon loc
735 , tree0 $ PlainText id_
737 instance Html5ify Entity where
738 html5ify Entity{..} = do
741 _ | not (TL.null email) ->
742 Tree (PlainEref $ URL $ "mailto:"<>email) $
743 pure $ tree0 $ PlainText name
746 pure $ tree0 $ PlainText name
747 _ -> tree0 $ PlainText name
752 instance Html5ify Words where
753 html5ify = html5ify . Anchor.plainifyWords
754 instance Html5ify Alias where
755 html5ify Alias{id=id_, ..} = do
756 H.a ! HA.class_ "alias"
757 ! HA.id (attrify id_) $$
759 instance Html5ify URL where
761 H.a ! HA.class_ "eref"
762 ! HA.href (attrify url) $$
764 instance Html5ify Date where
766 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
767 Plain.l10n_Date date loc
768 instance Html5ify Reference where
769 html5ify Reference{id=id_, ..} =
771 H.td ! HA.class_ "reference-key" $$
772 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
773 H.td ! HA.class_ "reference-content" $$ do
775 rrefs <- liftStateMarkup $ S.gets state_rrefs
776 case Map.lookup id_ rrefs of
779 H.span ! HA.class_ "reference-rrefs" $$
781 (<$> List.reverse anchs) $ \Anchor{..} ->
782 H.a ! HA.class_ "reference-rref"
783 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
784 html5ify $ DTC.posAncestors section
785 instance Html5ify PosPath where
793 Text.intercalate "." $
794 Text.pack . show . snd <$> as
795 instance Html5ify Plain.Plain where
797 sp <- liftStateMarkup $ S.gets state_plainify
798 let (t,sp') = Plain.runPlain p sp
800 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
802 html5CommasDot :: [Html5] -> Html5
803 html5CommasDot [] = pure ()
804 html5CommasDot hs = do
805 sequence_ $ List.intersperse ", " hs
808 html5AttrClass :: [TL.Text] -> Html5 -> Html5
809 html5AttrClass = \case
813 (H.AddCustomAttribute "class"
814 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
817 html5AttrId :: Ident -> Html5 -> Html5
818 html5AttrId (Ident id_) =
820 (H.AddCustomAttribute "id"
821 (H.String $ TL.unpack id_) <$>) .
824 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
825 html5CommonAttrs CommonAttrs{id=id_, ..} =
826 html5AttrClass classes .
827 maybe Cat.id html5AttrId id_
829 html5SectionNumber :: PosPath -> Html5
830 html5SectionNumber = go mempty
832 go :: PosPath -> PosPath -> Html5
834 case Seq.viewl next of
835 Seq.EmptyL -> pure ()
836 a@(_n,rank) Seq.:< as -> do
837 H.a ! HA.href ("#"<>attrify (prev Seq.|>a)) $$
839 when (not (null as) || null prev) $ do
843 html5SectionRef :: PosPath -> Html5
845 H.a ! HA.href ("#"<>attrify as) $$
849 instance Attrify Anchor where
850 attrify Anchor{..} = attrify section <> "." <> attrify count
851 instance Attrify Plain.Plain where
852 attrify p = attrify t
853 where (t,_) = Plain.runPlain p def
854 instance Attrify PosPath where
855 attrify = attrify . plainify
856 instance Attrify DTC.Pos where
857 attrify = attrify . DTC.posAncestors
859 attrifyIref :: Words -> H.AttributeValue
861 "iref" <> "." <> attrify (Anchor.plainifyWords term)
862 attrifyIrefCount :: Words -> Nat1 -> H.AttributeValue
863 attrifyIrefCount term count =
865 <> "." <> attrify (Anchor.plainifyWords term)
866 <> "." <> attrify count
870 ( Plain.L10n msg lang
871 , Plain.L10n TL.Text lang
872 ) => L10n msg lang where
873 l10n_Header_Address :: FullLocale lang -> msg
874 l10n_Header_Date :: FullLocale lang -> msg
875 l10n_Header_Version :: FullLocale lang -> msg
876 l10n_Header_Origin :: FullLocale lang -> msg
877 l10n_Header_Source :: FullLocale lang -> msg
878 instance L10n Html5 EN where
879 l10n_Header_Address _loc = "Address"
880 l10n_Header_Date _loc = "Date"
881 l10n_Header_Origin _loc = "Origin"
882 l10n_Header_Source _loc = "Source"
883 l10n_Header_Version _loc = "Version"
884 instance L10n Html5 FR where
885 l10n_Header_Address _loc = "Adresse"
886 l10n_Header_Date _loc = "Date"
887 l10n_Header_Origin _loc = "Origine"
888 l10n_Header_Source _loc = "Source"
889 l10n_Header_Version _loc = "Version"
891 instance Plain.L10n Html5 EN where
892 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
893 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
894 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
895 l10n_Quote msg _loc = do
896 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
897 let (o,c) :: (Html5, Html5) =
898 case unNat depth `mod` 3 of
903 setDepth $ succNat depth
909 liftStateMarkup $ S.modify' $ \s ->
910 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
911 instance Plain.L10n Html5 FR where
912 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
913 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
914 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
915 l10n_Quote msg _loc = do
916 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
917 let (o,c) :: (Html5, Html5) =
918 case unNat depth `mod` 3 of
923 setDepth $ succNat depth
929 liftStateMarkup $ S.modify' $ \s ->
930 s{state_plainify=(state_plainify s){Plain.state_quote=d}}