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{rel, href} ->
102 H.link ! HA.rel (attrify rel)
103 ! HA.href (attrify href)
105 H.link ! HA.rel "self"
106 ! HA.href (attrify href)
107 unless (TL.null config_generator) $ do
108 H.meta ! HA.name "generator"
109 ! HA.content (attrify config_generator)
111 H.meta ! HA.name "keywords"
112 ! HA.content (attrify $ TL.intercalate ", " tags)
114 (`mapMaybe` toList body) $ \case
115 Tree k@BodySection{} _ -> Just k
117 forM_ chapters $ \case
119 H.link ! HA.rel "Chapter"
120 ! HA.title (attrify $ plainify title)
121 ! HA.href ("#"<>attrify pos)
123 unless (any (\DTC.Link{rel} -> rel == "stylesheet") links) $ do
127 H.link ! HA.rel "stylesheet"
128 ! HA.type_ "text/css"
129 ! HA.href (attrify css)
131 H.style ! HA.type_ "text/css" $
132 -- NOTE: as a special case, H.style wraps its content into an External,
133 -- so it does not HTML-escape its content.
135 forM_ state_styles $ \style ->
136 H.style ! HA.type_ "text/css" $
138 unless (any (\DTC.Link{rel} -> rel == "script") links) $ do
139 forM_ state_scripts $ \script ->
140 H.script ! HA.type_ "application/javascript" $
143 html5DocumentHead :: Head -> Html5
144 html5DocumentHead Head{DTC.about=About{..}} = do
145 H.div ! HA.class_ "document-head" $$
149 H.td ! HA.class_ "left" $$ docHeaders
150 H.td ! HA.class_ "right" $$ docAuthors
151 unless (null titles) $
152 H.div ! HA.class_ "title" $$ do
153 forM_ titles $ \title ->
154 H.h1 $$ html5ify title
157 H.table ! HA.class_ "document-headers" $$
159 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
160 forM_ series $ \s@Serie{id=id_, name} ->
164 headerName $ html5ify name
165 headerValue $ html5ify id_
167 headerName $ html5ify name
169 H.a ! HA.href (attrify href) $$
173 headerName $ l10n_Header_Date loc
174 headerValue $ html5ify d
177 headerName $ l10n_Header_Address loc
178 headerValue $ html5ify $ tree0 $ PlainEref{href}
179 forM_ links $ \Link{..} ->
180 unless (TL.null name) $
182 headerName $ html5ify name
183 headerValue $ html5ify $ Tree PlainEref{href} plain
184 forM_ headers $ \Header{..} ->
186 headerName $ html5ify name
187 headerValue $ html5ify value
189 H.table ! HA.class_ "document-authors" $$
191 forM_ authors $ \a ->
193 H.td ! HA.class_ "author" $$
195 header :: Html5 -> Html5
196 header h = H.tr ! HA.class_ "header" $$ h
197 headerName :: Html5 -> Html5
199 H.td ! HA.class_ "header-name" $$ do
201 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
203 headerValue :: Html5 -> Html5
205 H.td ! HA.class_ "header-value" $$ do
212 , Loqualize locales (L10n Html5)
213 , Loqualize locales (Plain.L10n Plain.Plain)
216 { config_css :: Either FilePath TL.Text
217 , config_locale :: LocaleIn locales
218 , config_generator :: TL.Text
220 instance Default Config where
222 { config_css = Right "style/dtc-html5.css"
223 , config_locale = LocaleIn @'[EN] en_US
224 , config_generator = "https://hackage.haskell.org/package/hdoc"
228 type Html5 = StateMarkup State ()
229 instance IsString Html5 where
230 fromString = html5ify
235 { state_styles :: Map FilePath TL.Text
236 , state_scripts :: Map FilePath TL.Text
237 , state_indexs :: Map DTC.Pos (Terms, Anchor.Irefs)
238 , state_rrefs :: Anchor.Rrefs
239 , state_figures :: Map TL.Text (Map DTC.Pos (Maybe Title))
240 , state_references :: Map Ident About
241 , state_notes :: Anchor.Notes
242 , state_plainify :: Plain.State
243 , state_l10n :: Loqualization (L10n Html5)
245 instance Default State where
248 , state_scripts = def
251 , state_figures = def
252 , state_references = def
254 , state_plainify = def
255 , state_l10n = Loqualization EN_US
261 { keys_index :: Map DTC.Pos Terms
262 , keys_figure :: Map TL.Text (Map DTC.Pos (Maybe Title))
263 , keys_reference :: Map Ident About
265 instance Default Keys where
266 def = Keys mempty mempty mempty
270 keys :: a -> S.State Keys ()
271 instance KeysOf Body where
273 instance KeysOf (Tree BodyNode) where
276 BodySection{..} -> keys ts
277 BodyBlock b -> keys b
278 instance KeysOf DTC.Block where
280 BlockPara{} -> return ()
281 BlockToC{} -> return ()
282 BlockToF{} -> return ()
284 S.modify $ \s -> s{keys_index=
285 Map.insert pos terms $ keys_index s}
287 S.modify $ \s -> s{keys_figure=
289 type_ (Map.singleton pos mayTitle) $
291 BlockReferences{..} ->
292 S.modify $ \s -> s{keys_reference=
295 (DTC.id (r::DTC.Reference))
296 (DTC.about (r::DTC.Reference)))
300 -- * Class 'Html5ify'
301 class Html5ify a where
302 html5ify :: a -> Html5
303 instance Html5ify H.Markup where
304 html5ify = Compose . return
305 instance Html5ify Char where
306 html5ify = html5ify . H.toMarkup
307 instance Html5ify Text where
308 html5ify = html5ify . H.toMarkup
309 instance Html5ify TL.Text where
310 html5ify = html5ify . H.toMarkup
311 instance Html5ify String where
312 html5ify = html5ify . H.toMarkup
313 instance Html5ify Title where
314 html5ify (Title t) = html5ify t
315 instance Html5ify Ident where
316 html5ify (Ident i) = html5ify i
317 instance Html5ify Int where
318 html5ify = html5ify . show
319 instance Html5ify Nat where
320 html5ify (Nat n) = html5ify n
321 instance Html5ify Nat1 where
322 html5ify (Nat1 n) = html5ify n
323 instance Html5ify a => Html5ify (Maybe a) where
324 html5ify = foldMap html5ify
326 -- * Type 'BodyCursor'
327 -- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
328 type BodyCursor = Tree.Zipper BodyNode
329 instance Html5ify Body where
331 forM_ (Tree.zippers body) $ \z ->
332 forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
334 instance Html5ify BodyCursor
336 let Tree n _ts = Tree.current z in
338 BodyBlock BlockToC{..} -> do
339 H.nav ! HA.class_ "toc"
340 ! HA.id (attrify pos) $$ do
341 H.span ! HA.class_ "toc-name" $$
342 H.a ! HA.href (attrify pos) $$ do
343 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
344 Plain.l10n_Table_of_Contents loc
346 forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
348 BodyBlock b -> html5ify b
349 BodySection{..} -> do
351 notes <- liftStateMarkup $ S.gets state_notes
353 p <- posParent $ posAncestors pos
354 let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p notes
358 Just (secNotes, state_notes) -> do
359 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
361 H.section ! HA.class_ "section"
362 ! HA.id (attrify pos) $$ do
363 forM_ aliases html5ify
364 html5CommonAttrs attrs{classes="section-header":classes attrs} $
368 H.td ! HA.class_ "section-number" $$ do
369 html5SectionNumber $ DTC.posAncestors pos
370 H.td ! HA.class_ "section-title" $$ do
371 (case List.length $ DTC.posAncestors pos of
380 forM_ (Tree.axis_child `Tree.runAxis` z) $
382 notes <- liftStateMarkup $ S.gets state_notes
383 html5ify $ Map.lookup (posAncestors pos) notes
384 instance Html5ify [Anchor.Note] where
386 H.aside ! HA.class_ "notes" $$ do
390 forM_ (List.reverse notes) $ \Anchor.Note{..} ->
392 H.td ! HA.class_ "note-ref" $$ do
393 H.a ! HA.class_ "note-number"
394 ! HA.id ("note."<>attrify note_number)
395 ! HA.href ("#note."<>attrify note_number) $$ do
398 H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
401 html5ify note_content
402 instance Html5ify Block where
404 BlockPara para -> html5ify para
405 BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
407 H.nav ! HA.class_ "tof"
408 ! HA.id (attrify pos) $$
409 H.table ! HA.class_ "tof" $$
413 html5CommonAttrs attrs
414 { classes = "figure":("figure-"<>type_):classes attrs
415 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
418 H.table ! HA.class_ "figure-caption" $$
422 then H.a ! HA.href ("#"<>attrify pos) $$ mempty
424 H.td ! HA.class_ "figure-number" $$ do
425 H.a ! HA.href ("#"<>attrify pos) $$ do
427 html5ify $ DTC.posAncestors pos
428 forM_ mayTitle $ \title ->
429 H.td ! HA.class_ "figure-title" $$ do
430 unless (TL.null type_) $ do
431 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
434 H.div ! HA.class_ "figure-content" $$ do
436 BlockIndex{pos} -> do
437 (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
438 let chars = Anchor.termsByChar allTerms
439 H.div ! HA.class_ "index"
440 ! HA.id (attrify pos) $$ do
441 H.nav ! HA.class_ "index-nav" $$ do
442 forM_ (Map.keys chars) $ \char ->
443 H.a ! HA.href ("#"<>(attrify pos <> "." <> attrify char)) $$
445 H.dl ! HA.class_ "index-chars" $$
446 forM_ (Map.toList chars) $ \(char,terms) -> do
448 let i = attrify pos <> "." <> attrify char in
450 ! HA.href ("#"<>i) $$
453 H.dl ! HA.class_ "index-term" $$ do
454 forM_ terms $ \aliases -> do
456 H.ul ! HA.class_ "index-aliases" $$
457 forM_ (List.take 1 aliases) $ \term ->
458 H.li ! HA.id (attrifyIref term) $$
462 List.sortBy (compare `on` DTC.section . snd) $
463 (`foldMap` aliases) $ \words ->
465 path <- Anchor.pathFromWords words
466 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
467 TreeMap.lookup path refsByTerm in
469 (<$> anchs) $ \(term,DTC.Anchor{..}) ->
470 H.a ! HA.class_ "index-iref"
471 ! HA.href ("#"<>attrifyIrefCount term count) $$
472 html5ify $ DTC.posAncestors section
473 BlockReferences{..} ->
474 html5CommonAttrs attrs
475 { classes = "references":classes attrs
476 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
482 html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
483 html5ifyToC depth z =
484 let Tree n _ts = Tree.current z in
486 BodySection{..} -> do
488 H.table ! HA.class_ "toc-entry" $$
491 H.td ! HA.class_ "section-number" $$
492 html5SectionRef $ DTC.posAncestors pos
493 H.td ! HA.class_ "section-title" $$
494 html5ify $ cleanPlain $ unTitle title
495 when (maybe True (> Nat 1) depth && not (null sections)) $
498 html5ifyToC (depth >>= predNat)
504 `Tree.axis_filter_current` \case
505 Tree BodySection{} _ -> True
508 html5ifyToF :: [TL.Text] -> Html5
509 html5ifyToF types = do
510 figsByType <- liftStateMarkup $ S.gets state_figures
512 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
516 Map.intersection figsByType $
517 Map.fromList [(ty,()) | ty <- types]
518 forM_ (Map.toList figs) $ \(pos, (type_, title)) ->
520 H.td ! HA.class_ "figure-number" $$
521 H.a ! HA.href ("#"<>attrify pos) $$ do
523 html5ify $ DTC.posAncestors pos
525 H.td ! HA.class_ "figure-title" $$
526 html5ify $ cleanPlain $ unTitle ti
528 cleanPlain :: Plain -> Plain
531 Tree PlainIref{} ls -> cleanPlain ls
532 Tree PlainNote{} _ -> mempty
533 Tree n ts -> pure $ Tree n $ cleanPlain ts
535 instance Html5ify Para where
539 { classes="para":cls item
543 html5CommonAttrs attrs
544 { classes = "para":classes attrs
548 forM_ items $ \item ->
549 html5AttrClass (cls item) $
552 id_ = Just . Ident . Plain.text def . DTC.posAncestors
555 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
556 ParaQuote{..} -> ["quote", "quote-"<>type_]
560 instance Html5ify ParaItem where
562 ParaPlain p -> H.p $$ html5ify p
563 ParaArtwork{..} -> H.pre $$ do html5ify text
564 ParaQuote{..} -> H.div $$ do html5ify paras
565 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
569 forM_ items $ \ListItem{..} -> do
571 H.td ! HA.class_ "name" $$ do
574 H.td ! HA.class_ "value" $$
578 forM_ items $ \item -> do
580 H.dd $$ html5ify item
581 instance Html5ify [Para] where
582 html5ify = mapM_ html5ify
584 instance Html5ify Plain where
590 -- NOTE: gather adjacent PlainNotes
592 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
593 H.sup ! HA.class_ "note-numbers" $$ do
595 forM_ notes $ \note -> do
604 instance Html5ify (Tree PlainNode)
605 where html5ify (Tree n ls) =
607 PlainBR -> html5ify H.br
608 PlainText t -> html5ify t
609 PlainGroup -> html5ify ls
610 PlainB -> H.strong $$ html5ify ls
611 PlainCode -> H.code $$ html5ify ls
612 PlainDel -> H.del $$ html5ify ls
614 i <- liftStateMarkup $ do
615 i <- S.gets $ Plain.state_italic . state_plainify
618 (state_plainify s){Plain.state_italic=
621 H.em ! HA.class_ (if i then "even" else "odd") $$
626 (state_plainify s){Plain.state_italic=i}}
627 PlainSub -> H.sub $$ html5ify ls
628 PlainSup -> H.sup $$ html5ify ls
629 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
630 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
635 H.a ! HA.class_ "note-ref"
636 ! HA.id ("note-ref."<>attrify num)
637 ! HA.href ("#note."<>attrify num) $$
640 H.span ! HA.class_ "q" $$ do
641 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
642 Plain.l10n_Quote (html5ify $ Tree PlainI ls) loc
644 H.a ! HA.class_ "eref"
645 ! HA.href (attrify href) $$
647 then html5ify $ unURL href
651 Nothing -> html5ify ls
653 H.span ! HA.class_ "iref"
654 ! HA.id (attrifyIrefCount term count) $$
657 H.a ! HA.class_ "ref"
658 ! HA.href ("#"<>attrify to) $$
663 refs <- liftStateMarkup $ S.gets state_references
664 case Map.lookup to refs of
667 H.span ! HA.class_ "rref-broken" $$
672 forM_ (List.take 1 titles) $ \(Title title) -> do
673 html5ify $ Tree PlainQ $
676 Just u -> pure $ Tree (PlainEref u) title
679 H.a ! HA.class_ "rref"
680 ! HA.href ("#rref."<>attrify to)
681 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
685 instance Html5ify [Title] where
687 html5ify . fold . List.intersperse sep . toList
688 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
689 instance Html5ify About where
691 html5CommasDot $ concat $
693 , html5ify <$> authors
694 , html5ify <$> maybeToList date
695 , html5ify <$> maybeToList editor
696 , html5ify <$> series
699 html5Titles :: [Title] -> [Html5]
700 html5Titles ts | null ts = []
701 html5Titles ts = [html5Title $ joinTitles ts]
703 joinTitles = fold . List.intersperse sep . toList
704 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
705 html5Title (Title title) =
706 html5ify $ Tree PlainQ $
709 Just u -> pure $ Tree (PlainEref u) title
710 instance Html5ify Serie where
711 html5ify s@Serie{id=id_, name} = do
712 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
716 Plain.l10n_Colon loc :: Html5
720 Tree PlainEref{href} $
722 [ tree0 $ PlainText $ name
723 , tree0 $ PlainText $ Plain.l10n_Colon loc
724 , tree0 $ PlainText id_
726 instance Html5ify Entity where
727 html5ify Entity{..} = do
730 _ | not (TL.null email) ->
731 Tree (PlainEref $ URL $ "mailto:"<>email) $
732 pure $ tree0 $ PlainText name
735 pure $ tree0 $ PlainText name
736 _ -> tree0 $ PlainText name
741 instance Html5ify Words where
742 html5ify = html5ify . Anchor.plainifyWords
743 instance Html5ify Alias where
744 html5ify Alias{id=id_, ..} = do
745 H.a ! HA.class_ "alias"
746 ! HA.id (attrify id_) $$
748 instance Html5ify URL where
750 H.a ! HA.class_ "eref"
751 ! HA.href (attrify url) $$
753 instance Html5ify Date where
755 Loqualization loc <- liftStateMarkup $ S.gets state_l10n
756 Plain.l10n_Date date loc
757 instance Html5ify Reference where
758 html5ify Reference{id=id_, ..} =
760 H.td ! HA.class_ "reference-key" $$
761 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
762 H.td ! HA.class_ "reference-content" $$ do
764 rrefs <- liftStateMarkup $ S.gets state_rrefs
765 case Map.lookup id_ rrefs of
768 H.span ! HA.class_ "reference-rrefs" $$
770 (<$> List.reverse anchs) $ \Anchor{..} ->
771 H.a ! HA.class_ "reference-rref"
772 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
773 html5ify $ DTC.posAncestors section
774 instance Html5ify PosPath where
782 Text.intercalate "." $
783 Text.pack . show . snd <$> as
784 instance Html5ify Plain.Plain where
786 sp <- liftStateMarkup $ S.gets state_plainify
787 let (t,sp') = Plain.runPlain p sp
789 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
791 html5CommasDot :: [Html5] -> Html5
792 html5CommasDot [] = pure ()
793 html5CommasDot hs = do
794 sequence_ $ List.intersperse ", " hs
797 html5AttrClass :: [TL.Text] -> Html5 -> Html5
798 html5AttrClass = \case
802 (H.AddCustomAttribute "class"
803 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
806 html5AttrId :: Ident -> Html5 -> Html5
807 html5AttrId (Ident id_) =
809 (H.AddCustomAttribute "id"
810 (H.String $ TL.unpack id_) <$>) .
813 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
814 html5CommonAttrs CommonAttrs{id=id_, ..} =
815 html5AttrClass classes .
816 maybe Cat.id html5AttrId id_
818 html5SectionNumber :: PosPath -> Html5
819 html5SectionNumber = go mempty
821 go :: PosPath -> PosPath -> Html5
823 case Seq.viewl next of
824 Seq.EmptyL -> pure ()
825 a@(_n,rank) Seq.:< as -> do
826 H.a ! HA.href ("#"<>attrify (prev Seq.|>a)) $$
828 when (not (null as) || null prev) $ do
832 html5SectionRef :: PosPath -> Html5
834 H.a ! HA.href ("#"<>attrify as) $$
838 instance Attrify Anchor where
839 attrify Anchor{..} = attrify section <> "." <> attrify count
840 instance Attrify Plain.Plain where
841 attrify p = attrify t
842 where (t,_) = Plain.runPlain p def
843 instance Attrify PosPath where
844 attrify = attrify . plainify
845 instance Attrify DTC.Pos where
846 attrify = attrify . DTC.posAncestors
848 attrifyIref :: Words -> H.AttributeValue
850 "iref" <> "." <> attrify (Anchor.plainifyWords term)
851 attrifyIrefCount :: Words -> Nat1 -> H.AttributeValue
852 attrifyIrefCount term count =
854 <> "." <> attrify (Anchor.plainifyWords term)
855 <> "." <> attrify count
859 ( Plain.L10n msg lang
860 , Plain.L10n TL.Text lang
861 ) => L10n msg lang where
862 l10n_Header_Address :: FullLocale lang -> msg
863 l10n_Header_Date :: FullLocale lang -> msg
864 l10n_Header_Version :: FullLocale lang -> msg
865 l10n_Header_Origin :: FullLocale lang -> msg
866 l10n_Header_Source :: FullLocale lang -> msg
867 instance L10n Html5 EN where
868 l10n_Header_Address _loc = "Address"
869 l10n_Header_Date _loc = "Date"
870 l10n_Header_Origin _loc = "Origin"
871 l10n_Header_Source _loc = "Source"
872 l10n_Header_Version _loc = "Version"
873 instance L10n Html5 FR where
874 l10n_Header_Address _loc = "Adresse"
875 l10n_Header_Date _loc = "Date"
876 l10n_Header_Origin _loc = "Origine"
877 l10n_Header_Source _loc = "Source"
878 l10n_Header_Version _loc = "Version"
880 instance Plain.L10n Html5 EN where
881 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
882 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
883 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
884 l10n_Quote msg _loc = do
885 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
886 let (o,c) :: (Html5, Html5) =
887 case unNat depth `mod` 3 of
892 setDepth $ succNat depth
898 liftStateMarkup $ S.modify' $ \s ->
899 s{state_plainify=(state_plainify s){Plain.state_quote=d}}
900 instance Plain.L10n Html5 FR where
901 l10n_Colon loc = html5ify (Plain.l10n_Colon loc :: TL.Text)
902 l10n_Table_of_Contents loc = html5ify (Plain.l10n_Table_of_Contents loc :: TL.Text)
903 l10n_Date date loc = html5ify (Plain.l10n_Date date loc :: TL.Text)
904 l10n_Quote msg _loc = do
905 depth <- liftStateMarkup $ S.gets $ Plain.state_quote . state_plainify
906 let (o,c) :: (Html5, Html5) =
907 case unNat depth `mod` 3 of
912 setDepth $ succNat depth
918 liftStateMarkup $ S.modify' $ \s ->
919 s{state_plainify=(state_plainify s){Plain.state_quote=d}}