@@ -30,8 +30,10 @@ Conversion of 'Pandoc' documents to ODT.
3030-}
3131module Text.Pandoc.Writers.ODT ( writeODT ) where
3232import Data.IORef
33−import Data.List ( isPrefixOf )
33+import Data.List ( isPrefixOf, isSuffixOf )
3434import Data.Maybe ( fromMaybe )
35+import Text.XML.Light.Output
36+import Text.TeXMath
3537import qualified Data.ByteString.Lazy as B
3638import Text.Pandoc.UTF8 ( fromStringLazy )
3739import Codec.Archive.Zip
@@ -41,13 +43,14 @@ import Text.Pandoc.ImageSize ( imageSize, sizeInPoints )
4143import Text.Pandoc.MIME ( getMimeType )
4244import Text.Pandoc.Definition
4345import Text.Pandoc.Walk
46+import Text.Pandoc.Writers.Shared ( fixDisplayMath )
4447import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument )
4548import Control.Monad (liftM)
4649import Text.Pandoc.XML
4750import Text.Pandoc.Pretty
4851import qualified Control.Exception as E
4952import Data.Time.Clock.POSIX ( getPOSIXTime )
50−import System.FilePath ( takeExtension )
53+import System.FilePath ( takeExtension, takeDirectory )
5154
5255-- | Produce an ODT file from a Pandoc document.
5356writeODT :: WriterOptions -- ^ Writer options
@@ -61,9 +64,9 @@ writeODT opts doc@(Pandoc meta _) = do
6164 Just f -> B.readFile f
6265 Nothing -> (B.fromChunks . (:[])) `fmap`
6366 readDataFile datadir "reference.odt"
64− -- handle pictures
67+ -- handle formulas and pictures
6568 picEntriesRef <- newIORef ([] :: [Entry])
66− doc' <- walkM (transformPic opts picEntriesRef) doc
69+ doc' <- walkM (transformPicMath opts picEntriesRef) $ walk fixDisplayMath doc
6770 let newContents = writeOpenDocument opts{writerWrapText = False} doc'
6871 epochtime <- floor `fmap` getPOSIXTime
6972 let contentEntry = toEntry "content.xml" epochtime
@@ -73,7 +76,11 @@ writeODT opts doc@(Pandoc meta _) = do
7376 $ contentEntry : picEntries
7477 -- construct META-INF/manifest.xml based on archive
7578 let toFileEntry fp = case getMimeType fp of
76− Nothing -> empty
79+ Nothing -> if "Formula-" `isPrefixOf` fp && "/" `isSuffixOf` fp
80+ then selfClosingTag "manifest:file-entry"
81+ [("manifest:media-type","application/vnd.oasis.opendocument.formula")
82+ ,("manifest:full-path",fp)]
83+ else empty
7784 Just m -> selfClosingTag "manifest:file-entry"
7885 [("manifest:media-type", m)
7986 ,("manifest:full-path", fp)
@@ -81,6 +88,8 @@ writeODT opts doc@(Pandoc meta _) = do
8188 ]
8289 let files = [ ent | ent <- filesInArchive archive,
8390 not ("META-INF" `isPrefixOf` ent) ]
91+ let formulas = [ takeDirectory ent ++ "/" | ent <- filesInArchive archive,
92+ "Formula-" `isPrefixOf` ent, takeExtension ent == ".xml" ]
8493 let manifestEntry = toEntry "META-INF/manifest.xml" epochtime
8594 $ fromStringLazy $ render Nothing
8695 $ text "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
@@ -92,6 +101,7 @@ writeODT opts doc@(Pandoc meta _) = do
92101 [("manifest:media-type","application/vnd.oasis.opendocument.text")
93102 ,("manifest:full-path","/")]
94103 $$ vcat ( map toFileEntry $ files )
104+ $$ vcat ( map toFileEntry $ formulas )
95105 )
96106 )
97107 let archive' = addEntryToArchive manifestEntry archive
@@ -119,8 +129,8 @@ writeODT opts doc@(Pandoc meta _) = do
119129 $ addEntryToArchive metaEntry archive'
120130 return $ fromArchive archive''
121131
122−transformPic :: WriterOptions -> IORef [Entry] -> Inline -> IO Inline
123−transformPic opts entriesRef (Image lab (src,_)) = do
132+transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> IO Inline
133+transformPicMath opts entriesRef (Image lab (src,_)) = do
124134 res <- fetchItem (writerSourceURL opts) src
125135 case res of
126136 Left (_ :: E.SomeException) -> do
@@ -137,5 +147,29 @@ transformPic opts entriesRef (Image lab (src,_)) = do
137147 let entry = toEntry newsrc epochtime $ toLazy img
138148 modifyIORef entriesRef (entry:)
139149 return $ Image lab (newsrc, tit')
140−transformPic _ _ x = return x
150+transformPicMath _ entriesRef (Math t math) = do
151+ entries <- readIORef entriesRef
152+ let dt = if t == InlineMath then DisplayInline else DisplayBlock
153+ case texMathToMathML dt math of
154+ Left _ -> return $ Math t math
155+ Right r -> do
156+ let conf = useShortEmptyTags (const False) defaultConfigPP
157+ let mathml = ppcTopElement conf r
158+ epochtime <- floor `fmap` getPOSIXTime
159+ let dirname = "Formula-" ++ show (length entries) ++ "/"
160+ let fname = dirname ++ "content.xml"
161+ let entry = toEntry fname epochtime (fromStringLazy mathml)
162+ modifyIORef entriesRef (entry:)
163+ return $ RawInline (Format "opendocument") $ render Nothing $
164+ inTags False "draw:frame" [("text:anchor-type",
165+ if t == DisplayMath
166+ then "paragraph"
167+ else "as-char")
168+ ,("style:vertical-pos", "middle")
169+ ,("style:vertical-rel", "text")] $
170+ selfClosingTag "draw:object" [("xlink:href", dirname)
171+ , ("xlink:type", "simple")
172+ , ("xlink:show", "embed")
173+ , ("xlink:actuate", "onLoad")]
141174
175+transformPicMath _ _ x = return x