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}}
639 html5CommonAttrs attrs $
640 H.span $$ html5ify ls
641 PlainSub -> H.sub $$ html5ify ls
642 PlainSup -> H.sup $$ html5ify ls
643 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
644 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
649 H.a ! HA.class_ "note-ref"
650 ! HA.id ("note-ref."<>attrify num)
651 ! HA.href ("#note."<>attrify num) $$
654 H.span ! HA.class_ "q" $$ do
655 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
656 Plain.l10n_Quote (html5ify $ Tree PlainI ls) loc
658 H.a ! HA.class_ "eref"
659 ! HA.href (attrify href) $$
661 then html5ify $ unURL href
665 Nothing -> html5ify ls
667 H.span ! HA.class_ "iref"
668 ! HA.id (attrifyIrefCount term count) $$
671 H.a ! HA.class_ "ref"
672 ! HA.href ("#"<>attrify to) $$
677 refs <- liftStateMarkup $ S.gets state_references
678 case Map.lookup to refs of
681 H.span ! HA.class_ "rref-broken" $$
686 forM_ (List.take 1 titles) $ \(Title title) -> do
687 html5ify $ Tree PlainQ $
690 Just u -> pure $ Tree (PlainEref u) title
693 H.a ! HA.class_ "rref"
694 ! HA.href ("#rref."<>attrify to)
695 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
699 instance Html5ify [Title] where
701 html5ify . fold . List.intersperse sep . toList
702 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
703 instance Html5ify About where
705 html5CommasDot $ concat $
707 , html5ify <$> authors
708 , html5ify <$> maybeToList date
709 , html5ify <$> maybeToList editor
710 , html5ify <$> series
713 html5Titles :: [Title] -> [Html5]
714 html5Titles ts | null ts = []
715 html5Titles ts = [html5Title $ joinTitles ts]
717 joinTitles = fold . List.intersperse sep . toList
718 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
719 html5Title (Title title) =
720 html5ify $ Tree PlainQ $
723 Just u -> pure $ Tree (PlainEref u) title
724 instance Html5ify Serie where
725 html5ify s@Serie{id=id_, name} = do
726 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
730 Plain.l10n_Colon loc :: Html5
734 Tree PlainEref{href} $
736 [ tree0 $ PlainText $ name
737 , tree0 $ PlainText $ Plain.l10n_Colon loc
738 , tree0 $ PlainText id_
740 instance Html5ify Entity where
741 html5ify Entity{..} = do
744 _ | not (TL.null email) ->
745 Tree (PlainEref $ URL $ "mailto:"<>email) $
746 pure $ tree0 $ PlainText name
749 pure $ tree0 $ PlainText name
750 _ -> tree0 $ PlainText name
755 instance Html5ify Words where
756 html5ify = html5ify . Anchor.plainifyWords
757 instance Html5ify Alias where
758 html5ify Alias{id=id_, ..} = do
759 H.a ! HA.class_ "alias"
760 ! HA.id (attrify id_) $$
762 instance Html5ify URL where
764 H.a ! HA.class_ "eref"
765 ! HA.href (attrify url) $$
767 instance Html5ify Date where
769 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
770 Plain.l10n_Date date loc
771 instance Html5ify Reference where
772 html5ify Reference{id=id_, ..} =
774 H.td ! HA.class_ "reference-key" $$
775 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
776 H.td ! HA.class_ "reference-content" $$ do
778 rrefs <- liftStateMarkup $ S.gets state_rrefs
779 case Map.lookup id_ rrefs of
782 H.span ! HA.class_ "reference-rrefs" $$
784 (<$> List.reverse anchs) $ \Anchor{..} ->
785 H.a ! HA.class_ "reference-rref"
786 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
787 html5ify $ DTC.posAncestors section
788 instance Html5ify PosPath where
796 Text.intercalate "." $
797 Text.pack . show . snd <$> as
798 instance Html5ify Plain.Plain where
800 sp <- liftStateMarkup $ S.gets state_plainify
801 let (t,sp') = Plain.runPlain p sp
803 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
805 html5CommasDot :: [Html5] -> Html5
806 html5CommasDot [] = pure ()
807 html5CommasDot hs = do
808 sequence_ $ List.intersperse ", " hs
811 html5AttrClass :: [TL.Text] -> Html5 -> Html5
812 html5AttrClass = \case
816 (H.AddCustomAttribute "class"
817 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
820 html5AttrId :: Ident -> Html5 -> Html5
821 html5AttrId (Ident id_) =
823 (H.AddCustomAttribute "id"
824 (H.String $ TL.unpack id_) <$>) .
827 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
828 html5CommonAttrs CommonAttrs{id=id_, ..} =
829 html5AttrClass classes .
830 maybe Cat.id html5AttrId id_
832 html5SectionNumber :: PosPath -> Html5
833 html5SectionNumber = go mempty
835 go :: PosPath -> PosPath -> Html5
837 case Seq.viewl next of
838 Seq.EmptyL -> pure ()
839 a@(_n,rank) Seq.:< as -> do
840 H.a ! HA.href ("#"<>attrify (prev Seq.|>a)) $$
842 when (not (null as) || null prev) $ do
846 html5SectionRef :: PosPath -> Html5
848 H.a ! HA.href ("#"<>attrify as) $$
852 instance Attrify Anchor where
853 attrify Anchor{..} = attrify section <> "." <> attrify count
854 instance Attrify Plain.Plain where
855 attrify p = attrify t
856 where (t,_) = Plain.runPlain p def
857 instance Attrify PosPath where
858 attrify = attrify . plainify
859 instance Attrify DTC.Pos where
860 attrify = attrify . DTC.posAncestors
862 attrifyIref :: Words -> H.AttributeValue
864 "iref" <> "." <> attrify (Anchor.plainifyWords term)
865 attrifyIrefCount :: Words -> Nat1 -> H.AttributeValue
866 attrifyIrefCount term count =
868 <> "." <> attrify (Anchor.plainifyWords term)
869 <> "." <> attrify count
873 ( Plain.L10n msg lang
874 , Plain.L10n TL.Text lang
875 ) => L10n msg lang where
876 l10n_Header_Address :: FullLocale lang -> msg
877 l10n_Header_Date :: FullLocale lang -> msg
878 l10n_Header_Version :: FullLocale lang -> msg
879 l10n_Header_Origin :: FullLocale lang -> msg
880 l10n_Header_Source :: FullLocale lang -> msg
881 instance L10n Html5 EN where
882 l10n_Header_Address _loc = "Address"
883 l10n_Header_Date _loc = "Date"
884 l10n_Header_Origin _loc = "Origin"
885 l10n_Header_Source _loc = "Source"
886 l10n_Header_Version _loc = "Version"
887 instance L10n Html5 FR where
888 l10n_Header_Address _loc = "Adresse"
889 l10n_Header_Date _loc = "Date"
890 l10n_Header_Origin _loc = "Origine"
891 l10n_Header_Source _loc = "Source"
892 l10n_Header_Version _loc = "Version"
894 instance Plain.L10n Html5 EN where
895 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
896 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
897 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
898 l10n_Quote msg _loc = do
899 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
900 let (o,c) :: (Html5, Html5) =
901 case unNat depth `mod` 3 of
906 setDepth $ succNat depth
912 liftStateMarkup $ S.modify' $ \s ->
913 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
914 instance Plain.L10n Html5 FR where
915 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
916 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
917 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
918 l10n_Quote msg _loc = do
919 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
920 let (o,c) :: (Html5, Html5) =
921 case unNat depth `mod` 3 of
926 setDepth $ succNat depth
932 liftStateMarkup $ S.modify' $ \s ->
933 s{state_plainify=(state_plainify s){Plain.state_quote=d}}