git.iko.soy/typeable/pandoc
on master help sign in
Andrea Rossato's patch for OpenDocument support.

git-svn-id: https://pandoc.googlecode.com/svn/trunk@1252 788f1e2b-df1e-0410-8736-df70ead52e1b

commit2baf6d09eec6693ca87157c907d4a3a5d800ac83 authorfiddlosopher <fiddlosopher@788f1e2b-df1e-0410-8736-df70ead52e1b> dateWed 19 Mar 2008, 18:45 (19 years ago) parent74e8085
6 files changed+539−11
Main.hs+12−11 Text/Pandoc.hs+2 Text/Pandoc/Writers/OpenDocument.hs+519 pandoc.cabal+1 templates/DefaultHeaders.hs+4 templates/headers/OpenDocument.header+1
Main.hs+12−11
@@ -77,17 +77,18 @@ readPandoc state input = read input
7777
7878-- | Association list of formats and pairs of writers and default headers.
7979writers :: [ ( String, ( WriterOptions -> Pandoc -> String, String ) ) ]
80−writers = [("native" , (writeDoc, ""))
81− ,("html" , (writeHtmlString, ""))
82− ,("s5" , (writeS5String, defaultS5Header))
83− ,("docbook" , (writeDocbook, defaultDocbookHeader))
84− ,("latex" , (writeLaTeX, defaultLaTeXHeader))
85− ,("context" , (writeConTeXt, defaultConTeXtHeader))
86− ,("texinfo" , (writeTexinfo, ""))
87− ,("man" , (writeMan, ""))
88− ,("markdown" , (writeMarkdown, ""))
89− ,("rst" , (writeRST, ""))
90− ,("rtf" , (writeRTF, defaultRTFHeader))
80+writers = [("native" , (writeDoc, ""))
81+ ,("html" , (writeHtmlString, ""))
82+ ,("s5" , (writeS5String, defaultS5Header))
83+ ,("docbook" , (writeDocbook, defaultDocbookHeader))
84+ ,("opendocument" , (writeOpenDocument, defaultOpenDocumentHeader))
85+ ,("latex" , (writeLaTeX, defaultLaTeXHeader))
86+ ,("context" , (writeConTeXt, defaultConTeXtHeader))
87+ ,("texinfo" , (writeTexinfo, ""))
88+ ,("man" , (writeMan, ""))
89+ ,("markdown" , (writeMarkdown, ""))
90+ ,("rst" , (writeRST, ""))
91+ ,("rtf" , (writeRTF, defaultRTFHeader))
9192 ]
9293
9394-- | Writer for Pandoc native format.
Text/Pandoc.hs+2
@@ -74,6 +74,7 @@ module Text.Pandoc
7474 , writeS5
7575 , writeS5String
7676 , writeDocbook
77+ , writeOpenDocument
7778 , writeMan
7879 , writeRTF
7980 , prettyPandoc
@@ -101,6 +102,7 @@ import Text.Pandoc.Writers.Texinfo
101102import Text.Pandoc.Writers.HTML
102103import Text.Pandoc.Writers.S5
103104import Text.Pandoc.Writers.Docbook
105+import Text.Pandoc.Writers.OpenDocument
104106import Text.Pandoc.Writers.Man
105107import Text.Pandoc.Writers.RTF
106108import Text.Pandoc.DefaultHeaders
Text/Pandoc/Writers/OpenDocument.hsnew file+519
@@ -0,0 +1,519 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE PatternGuards #-}
3+{-
4+Copyright (C) 2008 Andrea Rossato <andrea.rossato@unibz.it>
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Writers.OpenDocument
23+ Copyright : Copyright (C) 2008 Andrea Rossato
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : Andrea Rossato <andrea.rossato@unibz.it>
27+ Stability : alpha
28+ Portability : portable
29+
30+Conversion of 'Pandoc' documents to OpenDocument XML.
31+-}
32+module Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) where
33+import Text.Pandoc.Definition
34+import Text.Pandoc.Shared
35+import Text.Pandoc.Readers.TeXMath
36+import Text.PrettyPrint.HughesPJ hiding ( Str )
37+
38+import Control.Applicative ((<$>))
39+import Control.Monad.State
40+import Data.Char (chr)
41+
42+--
43+-- code to format XML
44+--
45+
46+-- | Escape one character as needed for XML.
47+escapeCharForXML :: Char -> String
48+escapeCharForXML x = case x of
49+ '&' -> "&amp;"
50+ '<' -> "&lt;"
51+ '>' -> "&gt;"
52+ '"' -> "&quot;"
53+ '\160' -> "&nbsp;"
54+ c -> [c]
55+
56+-- | True if the character needs to be escaped.
57+needsEscaping :: Char -> Bool
58+needsEscaping c = c `elem` "&<>\"\160"
59+
60+-- | Escape string as needed for XML. Entity references are not preserved.
61+escapeStringForXML :: String -> String
62+escapeStringForXML "" = ""
63+escapeStringForXML str =
64+ case break needsEscaping str of
65+ (okay, "") -> okay
66+ (okay, (c:cs)) -> okay ++ escapeCharForXML c ++ escapeStringForXML cs
67+
68+-- | Return a text object with a string of formatted XML attributes.
69+attributeList :: [(String, String)] -> Doc
70+attributeList = text . concatMap
71+ (\(a, b) -> " " ++ escapeStringForXML a ++ "=\"" ++
72+ escapeStringForXML b ++ "\"")
73+
74+-- | Put the supplied contents between start and end tags of tagType,
75+-- with specified attributes and (if specified) indentation.
76+inTags:: Bool -> String -> [(String, String)] -> Doc -> Doc
77+inTags isIndented tagType attribs contents =
78+ let openTag = char '<' <> text tagType <> attributeList attribs <>
79+ char '>'
80+ closeTag = text "</" <> text tagType <> char '>'
81+ in if isIndented
82+ then openTag $$ nest 2 contents $$ closeTag
83+ else openTag <> contents <> closeTag
84+
85+-- | Return a self-closing tag of tagType with specified attributes
86+selfClosingTag :: String -> [(String, String)] -> Doc
87+selfClosingTag tagType attribs =
88+ char '<' <> text tagType <> attributeList attribs <> text " />"
89+
90+-- | Put the supplied contents between start and end tags of tagType.
91+inTagsSimple :: String -> Doc -> Doc
92+inTagsSimple tagType = inTags False tagType []
93+
94+-- | Put the supplied contents in indented block btw start and end tags.
95+inTagsIndented :: String -> Doc -> Doc
96+inTagsIndented tagType = inTags True tagType []
97+
98+-- | Auxiliary function to convert Plain block to Para.
99+plainToPara :: Block -> Block
100+plainToPara (Plain x) = Para x
101+plainToPara x = x
102+
103+--
104+-- OpenDocument writer
105+--
106+
107+data WriterState =
108+ WriterState { stNotes :: [Doc]
109+ , stTableStyles :: [Doc]
110+ , stParaStyles :: [Doc]
111+ , stListStyles :: [(Int, [Doc])]
112+ , indentPara :: Int
113+ } deriving Show
114+
115+defaultWriterState :: WriterState
116+defaultWriterState =
117+ WriterState { stNotes = []
118+ , stTableStyles = []
119+ , stParaStyles = []
120+ , stListStyles = []
121+ , indentPara = 0
122+ }
123+
124+addTableStyle :: Doc -> State WriterState ()
125+addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s }
126+
127+addNote :: Doc -> State WriterState ()
128+addNote i = modify $ \s -> s { stNotes = i : stNotes s }
129+
130+addParaStyle :: Doc -> State WriterState ()
131+addParaStyle i = modify $ \s -> s { stParaStyles = i : stParaStyles s }
132+
133+increaseIndent :: State WriterState ()
134+increaseIndent = modify $ \s -> s { indentPara = 1 + indentPara s }
135+
136+resetIndent :: State WriterState ()
137+resetIndent = modify $ \s -> s { indentPara = 0 }
138+
139+inParagraphTags :: Doc -> Doc
140+inParagraphTags = inTags False "text:p" [("text:style-name", "Text_20_body")]
141+
142+inParagraphTagsWithStyle :: String -> Doc -> Doc
143+inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)]
144+
145+inSpanTags :: String -> Doc -> Doc
146+inSpanTags s = inTags False "text:span" [("text:style-name",s)]
147+
148+inHeaderTags :: Int -> Doc -> Doc
149+inHeaderTags i = inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i)
150+ , ("text:outline-level", show i)]
151+
152+-- | Convert list of authors to a docbook <author> section
153+authorToOpenDocument :: [Char] -> Doc
154+authorToOpenDocument name =
155+ if ',' `elem` name
156+ then -- last name first
157+ let (lastname, rest) = break (==',') name
158+ firstname = removeLeadingSpace rest in
159+ inParagraphTags $ (text $ escapeStringForXML firstname) <+>
160+ (text $ escapeStringForXML lastname)
161+ else -- last name last
162+ let namewords = words name
163+ lengthname = length namewords
164+ (firstname, lastname) = case lengthname of
165+ 0 -> ("","")
166+ 1 -> ("", name)
167+ n -> (joinWithSep " " (take (n-1) namewords), last namewords)
168+ in inParagraphTags $ (text $ escapeStringForXML firstname) <+>
169+ (text $ escapeStringForXML lastname)
170+
171+-- | Convert Pandoc document to string in OpenDocument format.
172+writeOpenDocument :: WriterOptions -> Pandoc -> String
173+writeOpenDocument opts (Pandoc (Meta title authors date) blocks) =
174+ let root = inTags True "office:document-content" openDocumentNameSpaces
175+ header = if writerStandalone opts
176+ then text (writerHeader opts)
177+ else empty
178+ (tit, _) = runState (wrap opts title) defaultWriterState
179+ meta = if writerStandalone opts
180+ then inHeaderTags 1 tit $$
181+ (vcat (map authorToOpenDocument authors)) $$
182+ (inParagraphTags (text $ escapeStringForXML date))
183+ else empty
184+ before = writerIncludeBefore opts
185+ after = writerIncludeAfter opts
186+ (doc, s) = runState (blocksToOpenDocument opts blocks) defaultWriterState
187+
188+ body = (if null before then empty else text before) $$
189+ doc $$
190+ (if null after then empty else text after)
191+ body' = if writerStandalone opts
192+ then inTagsIndented "office:body" $
193+ inTagsIndented "office:text" (meta $$ body)
194+ else body
195+ listStyle (n,l) = inTags True "text:list-style" [("style:name", "L" ++ show n)] (vcat l)
196+ listStyles = map listStyle (stListStyles s)
197+ in render $ header $$ root (generateStyles (stTableStyles s ++ stParaStyles s ++ listStyles) $$ body' $$ text "")
198+
199+withParagraphStyle :: WriterOptions -> String -> [Block] -> State WriterState Doc
200+withParagraphStyle o s (b:bs)
201+ | Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l
202+ | otherwise = go =<< blockToOpenDocument o b
203+ where go i = ($$) i <$> withParagraphStyle o s bs
204+withParagraphStyle _ _ [] = return empty
205+
206+inPreformattedTags :: String -> State WriterState Doc
207+inPreformattedTags s = do
208+ n <- paraStyle "Preformatted_20_Text" []
209+ return . inParagraphTagsWithStyle ("P" ++ show n) . hcat . rest $ s
210+ where rest (' ':' ':' ':' ':xs) = selfClosingTag "text:tab" [] : rest xs
211+ rest ( x:xs) = char x : rest xs
212+ rest [] = []
213+
214+
215+orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc
216+orderedListToOpenDocument o pn is =
217+ vcat . map (inTagsIndented "text:list-item") <$>
218+ mapM (orderedItemToOpenDocument o pn . map plainToPara) is
219+
220+orderedItemToOpenDocument :: WriterOptions -> Int -> [Block] -> State WriterState Doc
221+orderedItemToOpenDocument o n (b:bs)
222+ | OrderedList a l <- b = newLevel a l
223+ | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show n) <$> inlinesToOpenDocument o l
224+ | otherwise = go =<< blockToOpenDocument o b
225+ where
226+ go i = ($$) i <$> orderedItemToOpenDocument o n bs
227+ newLevel a l = do
228+ nn <- length <$> gets stParaStyles
229+ ls <- head <$> gets stListStyles
230+ modify $ \s -> s { stListStyles = orderedListLevelStyle a ls : tail (stListStyles s) }
231+ inTagsIndented "text:list" <$> orderedListToOpenDocument o nn l
232+orderedItemToOpenDocument _ _ [] = return empty
233+
234+newOrderedListStyle :: ListAttributes -> State WriterState (Int,Int)
235+newOrderedListStyle a = do
236+ ln <- (+) 1 . length <$> gets stListStyles
237+ pn <- paraListStyle ln
238+ let nbs = orderedListLevelStyle a (ln, [])
239+ modify $ \s -> s { stListStyles = nbs : stListStyles s }
240+ return (ln,pn)
241+
242+bulletListToOpenDocument :: WriterOptions -> [[Block]] -> State WriterState Doc
243+bulletListToOpenDocument o b = do
244+ ln <- (+) 1 . length <$> gets stListStyles
245+ (pn,ns) <- bulletListStyle ln
246+ modify $ \s -> s { stListStyles = ns : stListStyles s }
247+ is <- listItemsToOpenDocument ("P" ++ show pn) o b
248+ return $ inTags True "text:list" [("text:style-name", "L" ++ show ln)] is
249+
250+listItemsToOpenDocument :: String -> WriterOptions -> [[Block]] -> State WriterState Doc
251+listItemsToOpenDocument s o is =
252+ vcat . map (inTagsIndented "text:list-item") <$> mapM (withParagraphStyle o s . map plainToPara) is
253+
254+deflistItemToOpenDocument :: WriterOptions -> ([Inline],[Block]) -> State WriterState Doc
255+deflistItemToOpenDocument o (t,d) = do
256+ t' <- withParagraphStyle o "Definition-term" [Para t]
257+ d' <- withParagraphStyle o "Definition-definition" (map plainToPara d)
258+ return $ t' $$ d'
259+
260+inBlockQuote :: WriterOptions -> Int -> [Block] -> State WriterState Doc
261+inBlockQuote o i (b:bs)
262+ | BlockQuote l <- b = do increaseIndent
263+ ni <- paraStyle "Quotations" []
264+ go ni =<< inBlockQuote o ni l
265+ | Para l <- b = do go i =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
266+ | otherwise = do go i =<< blockToOpenDocument o b
267+ where go ni block = ($$) block <$> inBlockQuote o ni bs
268+inBlockQuote _ _ [] = resetIndent >> return empty
269+
270+-- | Convert a list of Pandoc blocks to OpenDocument.
271+blocksToOpenDocument :: WriterOptions -> [Block] -> State WriterState Doc
272+blocksToOpenDocument o b = vcat <$> mapM (blockToOpenDocument o) b
273+
274+-- | Convert a Pandoc block element to OpenDocument.
275+blockToOpenDocument :: WriterOptions -> Block -> State WriterState Doc
276+blockToOpenDocument o bs
277+ | Plain b <- bs = wrap o b
278+ | Para b <- bs = inParagraphTags <$> wrap o b
279+ | Header i b <- bs = inHeaderTags i <$> wrap o b
280+ | BlockQuote b <- bs = doBlockQuote b
281+ | CodeBlock _ s <- bs = preformatted s
282+ | RawHtml s <- bs = preformatted s
283+ | DefinitionList b <- bs = defList b
284+ | BulletList b <- bs = bulletListToOpenDocument o b
285+ | OrderedList a b <- bs = orderedList a b
286+ | Table c a w h r <- bs = table c a w h r
287+ | Null <- bs = return empty
288+ | HorizontalRule <- bs = return empty
289+ | otherwise = return empty
290+ where
291+ defList b = vcat <$> mapM (deflistItemToOpenDocument o) b
292+ preformatted s = vcat <$> mapM (inPreformattedTags . escapeStringForXML) (lines s)
293+ doBlockQuote b = do increaseIndent
294+ i <- paraStyle "Quotations" []
295+ inBlockQuote o i (map plainToPara b)
296+ orderedList a b = do (ln,pn) <- newOrderedListStyle a
297+ inTags True "text:list" [ ("text:style-name", "L" ++ show ln)]
298+ <$> orderedListToOpenDocument o pn b
299+ table c a w h r = do
300+ tn <- length <$> gets stTableStyles
301+ pn <- length <$> gets stParaStyles
302+ let genIds = map chr [65..]
303+ name = "Table" ++ show (tn + 1)
304+ columnIds = zip genIds w
305+ mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name ++ "." ++ [fst n])]
306+ columns = map mkColumn columnIds
307+ paraHStyles = paraTableStyles "Heading" pn a
308+ paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) a
309+ newPara = map snd . filter (not . isEmpty . snd)
310+ addTableStyle $ tableStyle tn columnIds
311+ mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
312+ captionDoc <- if null c
313+ then return empty
314+ else withParagraphStyle o "Caption" [Para c]
315+ th <- colHeadsToOpenDocument o name (map fst paraHStyles) h
316+ tr <- mapM (tableRowToOpenDocument o name (map fst paraStyles)) r
317+ return $ inTags True "table:table" [ ("table:name" , name)
318+ , ("table:style-name", name)
319+ ] (vcat columns $$ th $$ vcat tr) $$ captionDoc
320+
321+colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
322+colHeadsToOpenDocument o tn ns hs =
323+ inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
324+ mapM (tableItemToOpenDocument o tn) (zip ns hs)
325+
326+tableRowToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
327+tableRowToOpenDocument o tn ns cs =
328+ inTagsIndented "table:table-row" . vcat <$>
329+ mapM (tableItemToOpenDocument o tn) (zip ns cs)
330+
331+tableItemToOpenDocument :: WriterOptions -> String -> (String,[Block])-> State WriterState Doc
332+tableItemToOpenDocument o tn (n,i) =
333+ let a = [ ("table:style-name" , tn ++ ".A1" )
334+ , ("office:value-type", "string" )
335+ ]
336+ in inTags True "table:table-cell" a <$>
337+ withParagraphStyle o n (map plainToPara i)
338+
339+-- | Take list of inline elements and return wrapped doc.
340+wrap :: WriterOptions -> [Inline] -> State WriterState Doc
341+wrap o l = if writerWrapText o
342+ then fsep <$> mapM (inlinesToOpenDocument o) (splitBy Space l)
343+ else inlinesToOpenDocument o l
344+
345+-- | Convert a list of inline elements to OpenDocument.
346+inlinesToOpenDocument :: WriterOptions -> [Inline] -> State WriterState Doc
347+inlinesToOpenDocument o l = hcat <$> mapM (inlineToOpenDocument o) l
348+
349+-- | Convert an inline element to OpenDocument.
350+inlineToOpenDocument :: WriterOptions -> Inline -> State WriterState Doc
351+inlineToOpenDocument o ils
352+ | Ellipses <- ils = return $ text "&#8230;"
353+ | EmDash <- ils = return $ text "&#8212;"
354+ | EnDash <- ils = return $ text "&#8211;"
355+ | Apostrophe <- ils = return $ char '\''
356+ | Space <- ils = return $ char ' '
357+ | LineBreak <- ils = return $ selfClosingTag "text:line-break" []
358+ | Str s <- ils = return $ text $ escapeStringForXML s
359+ | Emph l <- ils = inSpanTags "Emphasis" <$> inlinesToOpenDocument o l
360+ | Strong l <- ils = inSpanTags "Strong_20_Emphasis" <$> inlinesToOpenDocument o l
361+ | Strikeout l <- ils = inSpanTags "Strikeout" <$> inlinesToOpenDocument o l
362+ | Superscript l <- ils = inSpanTags "Superscript" <$> inlinesToOpenDocument o l
363+ | Subscript l <- ils = inSpanTags "Subscript" <$> inlinesToOpenDocument o l
364+ | Quoted _ l <- ils = inSpanTags "Citation" <$> inlinesToOpenDocument o l
365+ | Code s <- ils = preformatted s
366+ | Math s <- ils = inlinesToOpenDocument o (readTeXMath s)
367+ | TeX s <- ils = preformatted s
368+ | HtmlInline s <- ils = preformatted s
369+ | Link l (s,t) <- ils = mkLink s t <$> inlinesToOpenDocument o l
370+ | Image l (s,t) <- ils = mkLink s t <$> inlinesToOpenDocument o l
371+ | Note l <- ils = mkNote l
372+ | otherwise = return empty
373+ where
374+ preformatted = return . inSpanTags "Teletype" . text . escapeStringForXML
375+ mkLink s t = inTags False "text:a" [ ("xlink:type" , "simple")
376+ , ("xlink:href" , s )
377+ , ("office:name", t )
378+ ] . inSpanTags "Definition"
379+ mkNote l = do
380+ n <- length <$> gets stNotes
381+ let footNote t = inTags False "text:note"
382+ [ ("text:id" , "ftn" ++ show n)
383+ , ("text:note-class", "footnote" )] $
384+ inTagsSimple "text:note-citation" (text . show $ n + 1) $$
385+ inTagsSimple "text:note-body" t
386+ nn <- footNote <$> withParagraphStyle o "Footnote" l
387+ addNote nn
388+ return nn
389+
390+generateStyles :: [Doc] -> Doc
391+generateStyles acc =
392+ let scripts = selfClosingTag "office:scripts" []
393+ fonts = inTagsIndented "office:font-face-decls"
394+ (vcat $ map font ["Lucida Sans Unicode", "Tahoma", "Times New Roman"])
395+ font fn = selfClosingTag "style:font-face"
396+ [ ("style:name", fn)
397+ , ("svg:font-family", fn)]
398+ in scripts $$ fonts $$ inTagsIndented "office:automatic-styles" (vcat $ reverse acc)
399+
400+bulletListStyle :: Int -> State WriterState (Int,(Int,[Doc]))
401+bulletListStyle l =
402+ let doStyles i = inTags True "text:list-level-style-bullet"
403+ [ ("text:level" , show i )
404+ , ("text:style-name" , "Bullet_20_Symbols")
405+ , ("style:num-suffix", "." )
406+ , ("text:bullet-char", "*" )
407+ ] (listLevelStyle i)
408+ listElStyle = map doStyles [1..10]
409+ in do pn <- paraListStyle l
410+ return (pn, (l, listElStyle))
411+
412+orderedListLevelStyle :: ListAttributes -> (Int, [Doc]) -> (Int,[Doc])
413+orderedListLevelStyle (s,n, d) (l,ls) =
414+ let suffix = case d of
415+ OneParen -> [("style:num-suffix", ")")]
416+ TwoParens -> [("style:num-prefix", "(")
417+ ,("style:num-suffix", ")")]
418+ _ -> [("style:num-suffix", ".")]
419+ format = case n of
420+ UpperAlpha -> "A"
421+ LowerAlpha -> "a"
422+ UpperRoman -> "I"
423+ LowerRoman -> "i"
424+ _ -> "1"
425+ listStyle = inTags True "text:list-level-style-number"
426+ ([ ("text:level" , show $ 1 + length ls )
427+ , ("text:style-name" , "Numbering_20_Symbols")
428+ , ("style:num-format", format )
429+ , ("text:start-value", show s )
430+ ] ++ suffix) (listLevelStyle (1 + length ls))
431+ in (l, ls ++ [listStyle])
432+
433+listLevelStyle :: Int -> Doc
434+listLevelStyle i =
435+ selfClosingTag "style:list-level-properties"
436+ [ ("text:space-before" , show (0.25 * fromIntegral i :: Double) ++ "in")
437+ , ("text:min-label-width","0.25in")]
438+
439+tableStyle :: Int -> [(Char,Float)] -> Doc
440+tableStyle num wcs =
441+ let tableId = "Table" ++ show (num + 1)
442+ table = inTags True "style:style" [("style:name", tableId)] $
443+ selfClosingTag "style:table-properties" [ ("style:rel-width", "100%" )
444+ , ("table:align" , "center")]
445+ colStyle (c,w) = inTags True "style:style" [ ("style:name" , tableId ++ "." ++ [c])
446+ , ("style:family", "table-column" )] $
447+ selfClosingTag "style:table-column-properties" [("style:column-width", show (7 * w) ++ "in")]
448+ cellStyle = inTags True "style:style" [ ("style:name" , tableId ++ ".A1")
449+ , ("style:family", "table-cell" )] $
450+ selfClosingTag "style:table-cell-properties" [ ("fo:border", "none")]
451+ columnStyles = map colStyle wcs
452+
453+ in table $$ vcat columnStyles $$ cellStyle
454+
455+paraStyle :: String -> [(String,String)] -> State WriterState Int
456+paraStyle parent attrs = do
457+ pn <- (+) 1 . length <$> gets stParaStyles
458+ i <- (*) 0.5 . fromIntegral <$> gets indentPara :: State WriterState Double
459+ let styleAttr = [ ("style:name" , "P" ++ show pn)
460+ , ("style:family" , "paragraph" )
461+ , ("style:parent-style-name", parent )]
462+ indent = if i == 0
463+ then empty
464+ else selfClosingTag "style:paragraph-properties"
465+ [ ("fo:margin-left" , show i ++ "in")
466+ , ("fo:margin-right" , "0in" )
467+ , ("fo:text-indent" , "0in" )
468+ , ("style:auto-text-indent" , "false" )]
469+ addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) indent
470+ return pn
471+
472+paraListStyle :: Int -> State WriterState Int
473+paraListStyle l =
474+ paraStyle "Text_20_body" [("style:list-style-name", "L" ++ show l )]
475+
476+paraTableStyles :: String -> Int -> [Alignment] -> [(String, Doc)]
477+paraTableStyles _ _ [] = []
478+paraTableStyles t s (a:xs)
479+ | AlignRight <- a = ( pName s, res s "end" ) : paraTableStyles t (s + 1) xs
480+ | AlignCenter <- a = ( pName s, res s "center") : paraTableStyles t (s + 1) xs
481+ | otherwise = ("Table_20_" ++ t, empty ) : paraTableStyles t s xs
482+ where pName sn = "P" ++ show (sn + 1)
483+ res sn x = inTags True "style:style"
484+ [ ("style:name" , pName sn )
485+ , ("style:family" , "paragraph" )
486+ , ("style:parent-style-name", "Table_20_" ++ t)
487+ ] $
488+ selfClosingTag "style:paragraph-properties"
489+ [ ("fo:text-align", x)
490+ , ("style:justify-single-word", "false")
491+ ]
492+
493+openDocumentNameSpaces :: [(String, String)]
494+openDocumentNameSpaces =
495+ [ ("xmlns:office" , "urn:oasis:names:tc:opendocument:xmlns:office:1.0" )
496+ , ("xmlns:style" , "urn:oasis:names:tc:opendocument:xmlns:style:1.0" )
497+ , ("xmlns:text" , "urn:oasis:names:tc:opendocument:xmlns:text:1.0" )
498+ , ("xmlns:table" , "urn:oasis:names:tc:opendocument:xmlns:table:1.0" )
499+ , ("xmlns:draw" , "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" )
500+ , ("xmlns:fo" , "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0")
501+ , ("xmlns:xlink" , "http://www.w3.org/1999/xlink" )
502+ , ("xmlns:dc" , "http://purl.org/dc/elements/1.1/" )
503+ , ("xmlns:meta" , "urn:oasis:names:tc:opendocument:xmlns:meta:1.0" )
504+ , ("xmlns:number" , "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" )
505+ , ("xmlns:svg" , "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" )
506+ , ("xmlns:chart" , "urn:oasis:names:tc:opendocument:xmlns:chart:1.0" )
507+ , ("xmlns:dr3d" , "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" )
508+ , ("xmlns:math" , "http://www.w3.org/1998/Math/MathML" )
509+ , ("xmlns:form" , "urn:oasis:names:tc:opendocument:xmlns:form:1.0" )
510+ , ("xmlns:script" , "urn:oasis:names:tc:opendocument:xmlns:script:1.0" )
511+ , ("xmlns:ooo" , "http://openoffice.org/2004/office" )
512+ , ("xmlns:ooow" , "http://openoffice.org/2004/writer" )
513+ , ("xmlns:oooc" , "http://openoffice.org/2004/calc" )
514+ , ("xmlns:dom" , "http://www.w3.org/2001/xml-events" )
515+ , ("xmlns:xforms" , "http://www.w3.org/2002/xforms" )
516+ , ("xmlns:xsd" , "http://www.w3.org/2001/XMLSchema" )
517+ , ("xmlns:xsi" , "http://www.w3.org/2001/XMLSchema-instance" )
518+ , ("office:version", "1.0" )
519+ ]
pandoc.cabal+1
@@ -66,6 +66,7 @@ Library
6666 Text.Pandoc.Writers.HTML,
6767 Text.Pandoc.Writers.LaTeX,
6868 Text.Pandoc.Writers.ConTeXt,
69+ Text.Pandoc.Writers.OpenDocument,
6970 Text.Pandoc.Writers.Texinfo,
7071 Text.Pandoc.Writers.Man,
7172 Text.Pandoc.Writers.Markdown,
templates/DefaultHeaders.hs+4
@@ -31,6 +31,7 @@ module Text.Pandoc.DefaultHeaders (
3131 defaultLaTeXHeader,
3232 defaultConTeXtHeader,
3333 defaultDocbookHeader,
34+ defaultOpenDocumentHeader,
3435 defaultS5Header,
3536 defaultRTFHeader
3637 ) where
@@ -45,6 +46,9 @@ defaultConTeXtHeader = @ConTeXt.header@
4546defaultDocbookHeader :: String
4647defaultDocbookHeader = @Docbook.header@
4748
49+defaultOpenDocumentHeader :: String
50+defaultOpenDocumentHeader = @OpenDocument.header@
51+
4852defaultS5Header :: String
4953defaultS5Header = s5Meta ++ s5CSS ++ s5Javascript
5054
templates/headers/OpenDocument.headernew file+1
@@ -0,0 +1 @@
1+<?xml version="1.0" encoding="utf-8" ?>