@@ -0,0 +1,181 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+Module : Text.Pandoc.Writers.Docx
4+Copyright : Copyright (C) 2012-2021 John MacFarlane
5+License : GNU GPL, version 2 or above
6+Maintainer : John MacFarlane <jgm@berkeley.edu>
7+
8+Conversion of table blocks to docx.
9+-}
10+module Text.Pandoc.Writers.Docx.Types
11+ ( EnvProps (..)
12+ , WriterEnv (..)
13+ , defaultWriterEnv
14+ , WriterState (..)
15+ , defaultWriterState
16+ , WS
17+ , ListMarker (..)
18+ , listMarkerToId
19+ , pStyleM
20+ , isStyle
21+ , setFirstPara
22+ , withParaProp
23+ , withParaPropM
24+ ) where
25+
26+import Control.Applicative ((<|>))
27+import Control.Monad.Reader
28+import Control.Monad.State.Strict
29+import Data.Text (Text)
30+import Text.Pandoc.Class.PandocMonad (PandocMonad)
31+import Text.Pandoc.Definition
32+import Text.Pandoc.MIME (MimeType)
33+import Text.Pandoc.Writers.Docx.StyleMap
34+import Text.Pandoc.Writers.OOXML
35+import Text.Pandoc.XML.Light as XML
36+import qualified Data.ByteString as B
37+import qualified Data.Map as M
38+import qualified Data.Set as Set
39+import qualified Data.Text as T
40+
41+data ListMarker = NoMarker
42+ | BulletMarker
43+ | NumberMarker ListNumberStyle ListNumberDelim Int
44+ deriving (Show, Read, Eq, Ord)
45+
46+listMarkerToId :: ListMarker -> Text
47+listMarkerToId NoMarker = "990"
48+listMarkerToId BulletMarker = "991"
49+listMarkerToId (NumberMarker sty delim n) = T.pack $
50+ '9' : '9' : styNum : delimNum : show n
51+ where styNum = case sty of
52+ DefaultStyle -> '2'
53+ Example -> '3'
54+ Decimal -> '4'
55+ LowerRoman -> '5'
56+ UpperRoman -> '6'
57+ LowerAlpha -> '7'
58+ UpperAlpha -> '8'
59+ delimNum = case delim of
60+ DefaultDelim -> '0'
61+ Period -> '1'
62+ OneParen -> '2'
63+ TwoParens -> '3'
64+
65+
66+data EnvProps = EnvProps{ styleElement :: Maybe Element
67+ , otherElements :: [Element]
68+ }
69+
70+instance Semigroup EnvProps where
71+ EnvProps s es <> EnvProps s' es' = EnvProps (s <|> s') (es ++ es')
72+
73+instance Monoid EnvProps where
74+ mempty = EnvProps Nothing []
75+ mappend = (<>)
76+
77+data WriterEnv = WriterEnv
78+ { envTextProperties :: EnvProps
79+ , envParaProperties :: EnvProps
80+ , envRTL :: Bool
81+ , envListLevel :: Int
82+ , envListNumId :: Int
83+ , envInDel :: Bool
84+ , envChangesAuthor :: Text
85+ , envChangesDate :: Text
86+ , envPrintWidth :: Integer
87+ }
88+
89+defaultWriterEnv :: WriterEnv
90+defaultWriterEnv = WriterEnv
91+ { envTextProperties = mempty
92+ , envParaProperties = mempty
93+ , envRTL = False
94+ , envListLevel = -1
95+ , envListNumId = 1
96+ , envInDel = False
97+ , envChangesAuthor = "unknown"
98+ , envChangesDate = "1969-12-31T19:00:00Z"
99+ , envPrintWidth = 1
100+ }
101+
102+
103+data WriterState = WriterState{
104+ stFootnotes :: [Element]
105+ , stComments :: [([(Text, Text)], [Inline])]
106+ , stSectionIds :: Set.Set Text
107+ , stExternalLinks :: M.Map Text Text
108+ , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
109+ , stLists :: [ListMarker]
110+ , stInsId :: Int
111+ , stDelId :: Int
112+ , stStyleMaps :: StyleMaps
113+ , stFirstPara :: Bool
114+ , stInTable :: Bool
115+ , stInList :: Bool
116+ , stTocTitle :: [Inline]
117+ , stDynamicParaProps :: Set.Set ParaStyleName
118+ , stDynamicTextProps :: Set.Set CharStyleName
119+ , stCurId :: Int
120+ }
121+
122+defaultWriterState :: WriterState
123+defaultWriterState = WriterState{
124+ stFootnotes = defaultFootnotes
125+ , stComments = []
126+ , stSectionIds = Set.empty
127+ , stExternalLinks = M.empty
128+ , stImages = M.empty
129+ , stLists = [NoMarker]
130+ , stInsId = 1
131+ , stDelId = 1
132+ , stStyleMaps = StyleMaps M.empty M.empty
133+ , stFirstPara = False
134+ , stInTable = False
135+ , stInList = False
136+ , stTocTitle = [Str "Table of Contents"]
137+ , stDynamicParaProps = Set.empty
138+ , stDynamicTextProps = Set.empty
139+ , stCurId = 20
140+ }
141+
142+setFirstPara :: PandocMonad m => WS m ()
143+setFirstPara = modify $ \s -> s { stFirstPara = True }
144+
145+type WS m = ReaderT WriterEnv (StateT WriterState m)
146+
147+-- Word will insert these footnotes into the settings.xml file
148+-- (whether or not they're visible in the document). If they're in the
149+-- file, but not in the footnotes.xml file, it will produce
150+-- problems. So we want to make sure we insert them into our document.
151+defaultFootnotes :: [Element]
152+defaultFootnotes = [ mknode "w:footnote"
153+ [("w:type", "separator"), ("w:id", "-1")]
154+ [ mknode "w:p" []
155+ [mknode "w:r" []
156+ [ mknode "w:separator" [] ()]]]
157+ , mknode "w:footnote"
158+ [("w:type", "continuationSeparator"), ("w:id", "0")]
159+ [ mknode "w:p" []
160+ [ mknode "w:r" []
161+ [ mknode "w:continuationSeparator" [] ()]]]]
162+
163+pStyleM :: (PandocMonad m) => ParaStyleName -> WS m XML.Element
164+pStyleM styleName = do
165+ pStyleMap <- gets (smParaStyle . stStyleMaps)
166+ let sty' = getStyleIdFromName styleName pStyleMap
167+ return $ mknode "w:pStyle" [("w:val", fromStyleId sty')] ()
168+
169+withParaProp :: PandocMonad m => Element -> WS m a -> WS m a
170+withParaProp d p =
171+ local (\env -> env {envParaProperties = ep <> envParaProperties env}) p
172+ where ep = if isStyle d then EnvProps (Just d) [] else EnvProps Nothing [d]
173+
174+withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
175+withParaPropM md p = do
176+ d <- md
177+ withParaProp d p
178+
179+isStyle :: Element -> Bool
180+isStyle e = isElem [] "w" "rStyle" e ||
181+ isElem [] "w" "pStyle" e