1 {-# LANGUAGE DeriveFunctor #-}
2 {-# LANGUAGE DisambiguateRecordFields #-}
3 {-# LANGUAGE DuplicateRecordFields #-}
4 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
5 {-# LANGUAGE OverloadedStrings #-}
6 {-# LANGUAGE RecordWildCards #-}
7 {-# LANGUAGE TypeApplications #-}
8 {-# LANGUAGE FlexibleInstances #-}
9 {-# LANGUAGE ScopedTypeVariables #-}
10 {-# LANGUAGE ViewPatterns #-}
11 {-# OPTIONS_GHC -fno-warn-orphans #-}
12 -- | Render a DTC source file in HTML5.
13 module Language.DTC.Write.HTML5 where
15 -- import Control.Monad.Trans.Class (MonadTrans(..))
17 -- import Data.Eq (Eq(..))
18 -- import Data.Functor.Compose (Compose(..))
19 -- import Data.Functor.Identity (Identity(..))
20 -- import Data.Map.Strict (Map)
21 -- import Data.String (IsString(..))
22 -- import Prelude (Num(..), undefined)
23 -- import qualified Control.Monad.Trans.State as S
24 -- import qualified Data.Map.Strict as Map
25 import Control.Monad (forM_, mapM_)
26 import Data.Eq (Eq(..))
27 import Data.Foldable (Foldable(..))
28 import Data.Function (($), (.))
29 import Data.Functor ((<$>))
31 import Data.Maybe (Maybe(..))
32 import Data.Monoid (Monoid(..))
33 import Data.Semigroup (Semigroup(..))
34 import Data.Text (Text)
35 import Data.Tuple (snd)
36 import Text.Blaze ((!))
37 import Text.Blaze.Html (Html)
38 import Text.Show (Show(..))
39 import qualified Data.List as List
40 import qualified Data.Text as Text
41 import qualified Data.Text.Lazy as TL
42 import qualified Text.Blaze.Html5 as H
43 import qualified Text.Blaze.Html5.Attributes as HA
44 import qualified Text.Blaze.Internal as H
46 import Text.Blaze.Utils
48 import Language.DTC.Document (Document)
49 import Language.DTC.Write.XML ()
50 import Language.XML (XmlName(..), XmlPos(..))
51 import qualified Language.DTC.Document as DTC
53 -- import Debug.Trace (trace)
55 instance H.ToMarkup DTC.Ident where
56 toMarkup (DTC.Ident i) = H.toMarkup i
57 instance AttrValue XmlPos where
58 attrValue = attrValue . textXmlPosAncestors . xmlPosAncestors
66 {- NOTE: composing state and markups
67 type HtmlM st = Compose (S.State st) H.MarkupM
68 instance Monad (HtmlM st) where
70 Compose sma >>= a2csmb =
71 Compose $ sma >>= \ma ->
72 case ma >>= H.Empty . a2csmb of
73 H.Append _ma (H.Empty csmb) ->
74 H.Append ma <$> getCompose csmb
77 ($$) :: (Html -> Html) -> HTML -> HTML
78 ($$) f m = Compose $ f <$> getCompose m
82 unMarkupValue :: H.MarkupM a -> b -> H.MarkupM b
84 H.Parent x0 x1 x2 m -> H.Parent x0 x1 x2 . unMarkupValue m
85 H.CustomParent x0 m -> H.CustomParent x0 . unMarkupValue m
86 H.Leaf x0 x1 x2 _ -> H.Leaf x0 x1 x2
87 H.CustomLeaf x0 x1 _ -> H.CustomLeaf x0 x1
88 H.Content x0 _ -> H.Content x0
89 H.Comment x0 _ -> H.Comment x0
90 H.Append x0 m -> H.Append x0 . unMarkupValue m
91 H.AddAttribute x0 x1 x2 m -> H.AddAttribute x0 x1 x2 . unMarkupValue m
92 H.AddCustomAttribute x0 x1 m -> H.AddCustomAttribute x0 x1 . unMarkupValue m
95 markupValue :: H.MarkupM a -> a
96 markupValue m0 = case m0 of
97 H.Parent _ _ _ m1 -> markupValue m1
98 H.CustomParent _ m1 -> markupValue m1
100 H.CustomLeaf _ _ x -> x
103 H.Append _ m1 -> markupValue m1
104 H.AddAttribute _ _ _ m1 -> markupValue m1
105 H.AddCustomAttribute _ _ m1 -> markupValue m1
108 html5Document :: Document -> Html
109 html5Document DTC.Document{..} = do
113 H.meta ! HA.httpEquiv "Content-Type"
114 ! HA.content "text/html; charset=UTF-8"
115 whenSome (DTC.titles $ DTC.about (head :: DTC.Head)) $ \ts ->
116 let t = textHorizontals $ List.head $ (DTC.unTitle <$> ts) <> [[DTC.Plain ""]] in
117 H.title $ H.toMarkup t
118 -- link ! rel "Chapter" ! title "SomeTitle">
119 H.link ! HA.rel "stylesheet"
120 ! HA.type_ "text/css"
121 ! HA.href "style/dtc-html5.css"
124 html5Body :: DTC.Body -> Html
128 ! HA.class_ "section"
129 ! HA.id (attrValue pos) $ do
130 html5CommonAttrs attrs $
131 H.table ! HA.class_ "section-header" $
134 H.td ! HA.class_ "section-number" $ do
135 html5SectionNumber $ xmlPosAncestors pos
136 H.td ! HA.class_ "section-title" $ do
137 html5Horizontals $ DTC.unTitle title
139 {- aliases :: [Alias]
141 DTC.Verticals vs -> html5Verticals vs
143 H.nav ! HA.class_ "toc"
144 ! HA.id (attrValue pos) $
147 H.nav ! HA.class_ "tof"
148 ! HA.id (attrValue pos) $
151 textXmlPosAncestors :: [(XmlName,Int)] -> Text
152 textXmlPosAncestors =
153 snd . foldr (\(n,c) (nParent,acc) ->
165 html5SectionNumber :: [(XmlName,Int)] -> Html
166 html5SectionNumber = go [] . List.reverse
168 go :: [(XmlName,Int)] -> [(XmlName,Int)] -> Html
170 go rs (a@(_n,cnt):as) = do
171 H.a ! HA.href (attrValue $ "#"<>textXmlPosAncestors (a:rs)) $
172 H.toMarkup $ show cnt
176 html5Verticals :: [DTC.Vertical] -> Html
177 html5Verticals = foldMap html5Vertical
179 html5Vertical :: DTC.Vertical -> Html
180 html5Vertical = \case
182 html5CommonAttrs attrs $
183 H.div ! HA.class_ "para"
184 ! HA.id (attrValue pos) $ do
185 html5Horizontals horis
187 html5CommonAttrs attrs $
188 H.ol ! HA.class_ "ol"
189 ! HA.id (attrValue pos) $ do
190 forM_ items $ \item ->
191 H.li $ html5Verticals item
193 html5CommonAttrs attrs $
194 H.ul ! HA.class_ "ul"
195 ! HA.id (attrValue pos) $ do
196 forM_ items $ \item ->
197 H.li $ html5Verticals item
199 html5CommonAttrs attrs $
200 H.div ! HA.class_ "rl"
201 ! HA.id (attrValue pos) $ do
203 forM_ refs html5Reference
205 H.Comment (H.Text t) ()
207 html5CommonAttrs attrs $
208 H.div ! HA.class_ (attrValue $ "figure-"<>type_)
209 ! HA.id (attrValue pos) $ do
210 H.table ! HA.class_ "figure-caption" $
213 H.td ! HA.class_ "figure-number" $ do
214 H.a ! HA.href "" $ H.toMarkup type_
216 H.td ! HA.class_ "figure-name" $
217 html5Horizontals $ DTC.unTitle title
218 H.div ! HA.class_ "figure-content" $ do
225 html5Reference :: DTC.Reference -> Html
226 html5Reference DTC.Reference{..} =
228 H.td ! HA.class_ "reference-key" $
230 H.td ! HA.class_ "reference-content" $
233 html5About :: DTC.About -> Html
234 html5About DTC.About{..} =
235 forM_ titles $ \(DTC.Title title) -> do
236 html5Horizontal $ DTC.Q title
248 html5CommonAttrs :: DTC.CommonAttrs -> Html -> Html
249 html5CommonAttrs DTC.CommonAttrs{..} =
252 _ -> H.AddCustomAttribute "class" (H.Text $ Text.unwords classes)) .
255 Just (DTC.Ident i) ->
256 H.AddCustomAttribute "id" (H.Text i)
258 html5Horizontal :: DTC.Horizontal -> Html
259 html5Horizontal = \case
261 DTC.B hs -> H.strong $ html5Horizontals hs
262 DTC.Code hs -> H.code $ html5Horizontals hs
263 DTC.Del hs -> H.del $ html5Horizontals hs
264 DTC.I hs -> H.i $ html5Horizontals hs
266 DTC.Q hs -> "« "<>H.i (html5Horizontals hs)<>" »"
267 DTC.SC hs -> html5Horizontals hs
268 DTC.Sub hs -> H.sub $ html5Horizontals hs
269 DTC.Sup hs -> H.sup $ html5Horizontals hs
270 DTC.U hs -> H.span ! HA.class_ "underline" $ html5Horizontals hs
271 DTC.Eref{..} -> H.a ! HA.class_ "eref" ! HA.href (attrValue href) $ html5Horizontals text
272 DTC.Iref{..} -> H.a ! HA.class_ "iref" ! HA.href (attrValue to) $ html5Horizontals text
274 H.a ! HA.class_ "ref"
275 ! HA.href ("#"<>attrValue to) $
278 else html5Horizontals text
279 DTC.Rref{..} -> H.a ! HA.class_ "rref" ! HA.href (attrValue to) $ html5Horizontals text
280 DTC.Plain t -> H.toMarkup t
282 html5Horizontals :: [DTC.Horizontal] -> Html
283 html5Horizontals = mapM_ html5Horizontal
285 textHorizontal :: DTC.Horizontal -> TL.Text
286 textHorizontal = \case
288 DTC.B hs -> "*"<>textHorizontals hs<>"*"
289 DTC.Code hs -> "`"<>textHorizontals hs<>"`"
290 DTC.Del hs -> "-"<>textHorizontals hs<>"-"
291 DTC.I hs -> "/"<>textHorizontals hs<>"/"
293 DTC.Q hs -> "« "<>textHorizontals hs<>" »"
294 DTC.SC hs -> textHorizontals hs
295 DTC.Sub hs -> textHorizontals hs
296 DTC.Sup hs -> textHorizontals hs
297 DTC.U hs -> "_"<>textHorizontals hs<>"_"
298 DTC.Eref{..} -> textHorizontals text
299 DTC.Iref{..} -> textHorizontals text
300 DTC.Ref{..} -> textHorizontals text
301 DTC.Rref{..} -> textHorizontals text
302 DTC.Plain t -> TL.fromStrict t
304 textHorizontals :: [DTC.Horizontal] -> TL.Text
305 textHorizontals = foldMap textHorizontal