Skip to content

Commit 30a2583

Browse files
author
Alexander Krotov
committed
Docx writer: write endnotes to endnotes.xml
1 parent 7401c4b commit 30a2583

File tree

2 files changed

+68
-13
lines changed

2 files changed

+68
-13
lines changed

data/docx/word/styles.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,14 @@
337337
<w:unhideWhenUsed />
338338
<w:qFormat />
339339
</w:style>
340+
<w:style w:type="paragraph" w:styleId="EndnoteText">
341+
<w:name w:val="Endnote Text" />
342+
<w:basedOn w:val="Normal" />
343+
<w:next w:val="EndnoteText" />
344+
<w:uiPriority w:val="9" />
345+
<w:unhideWhenUsed />
346+
<w:qFormat />
347+
</w:style>
340348
<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
341349
<w:name w:val="Default Paragraph Font" />
342350
<w:semiHidden />
@@ -428,6 +436,13 @@
428436
<w:vertAlign w:val="superscript" />
429437
</w:rPr>
430438
</w:style>
439+
<w:style w:type="character" w:styleId="EndnoteReference">
440+
<w:name w:val="Endnote Reference" />
441+
<w:basedOn w:val="BodyTextChar" />
442+
<w:rPr>
443+
<w:vertAlign w:val="superscript" />
444+
</w:rPr>
445+
</w:style>
431446
<w:style w:type="character" w:styleId="Hyperlink">
432447
<w:name w:val="Hyperlink" />
433448
<w:basedOn w:val="BodyTextChar" />

src/Text/Pandoc/Writers/Docx.hs

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ defaultWriterEnv = WriterEnv{ envTextProperties = []
120120

121121
data WriterState = WriterState{
122122
stFootnotes :: [Element]
123+
, stEndnotes :: [Element]
123124
, stComments :: [([(String,String)], [Inline])]
124125
, stSectionIds :: Set.Set String
125126
, stExternalLinks :: M.Map String String
@@ -137,6 +138,7 @@ data WriterState = WriterState{
137138
defaultWriterState :: WriterState
138139
defaultWriterState = WriterState{
139140
stFootnotes = defaultFootnotes
141+
, stEndnotes = []
140142
, stComments = []
141143
, stSectionIds = Set.empty
142144
, stExternalLinks = M.empty
@@ -283,7 +285,7 @@ writeDocx opts doc@(Pandoc meta _) = do
283285
}
284286

285287

286-
((contents, footnotes, comments), st) <- runStateT
288+
((contents, footnotes, endnotes, comments), st) <- runStateT
287289
(runReaderT
288290
(writeOpenXML opts{writerWrapText = WrapNone} doc')
289291
env)
@@ -352,6 +354,8 @@ writeDocx opts doc@(Pandoc meta _) = do
352354
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml")
353355
,("/word/footnotes.xml",
354356
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml")
357+
,("/word/endnotes.xml",
358+
"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml")
355359
] ++
356360
map (\x -> (maybe "" ("/word/" ++) $ extractTarget x,
357361
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml")) headers ++
@@ -396,8 +400,11 @@ writeDocx opts doc@(Pandoc meta _) = do
396400
,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
397401
"rId7",
398402
"footnotes.xml")
399-
,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
403+
,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes",
400404
"rId8",
405+
"endnotes.xml")
406+
,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
407+
"rId9",
401408
"comments.xml")
402409
]
403410

@@ -436,14 +443,23 @@ writeDocx opts doc@(Pandoc meta _) = do
436443
$ renderXml docContents
437444

438445
-- footnotes
439-
let notes = mknode "w:footnotes" stdAttributes footnotes
440-
let footnotesEntry = toEntry "word/footnotes.xml" epochtime $ renderXml notes
446+
let footnotesNode = mknode "w:footnotes" stdAttributes footnotes
447+
let footnotesEntry = toEntry "word/footnotes.xml" epochtime $ renderXml footnotesNode
441448

442449
-- footnote rels
443450
let footnoteRelEntry = toEntry "word/_rels/footnotes.xml.rels" epochtime
444451
$ renderXml $ mknode "Relationships" [("xmlns","http://schemas.openxmlformats.org/package/2006/relationships")]
445452
linkrels
446453

454+
-- endnotes
455+
let endnotesNode = mknode "w:endnotes" stdAttributes endnotes
456+
let endnotesEntry = toEntry "word/endnotes.xml" epochtime $ renderXml endnotesNode
457+
458+
-- endnote rels
459+
let endnoteRelEntry = toEntry "word/_rels/endnotes.xml.rels" epochtime
460+
$ renderXml $ mknode "Relationships" [("xmlns","http://schemas.openxmlformats.org/package/2006/relationships")]
461+
linkrels
462+
447463
-- comments
448464
let commentsEntry = toEntry "word/comments.xml" epochtime
449465
$ renderXml $ mknode "w:comments" stdAttributes comments
@@ -544,15 +560,16 @@ writeDocx opts doc@(Pandoc meta _) = do
544560
, "word/_rels/" `isPrefixOf` (eRelativePath e)
545561
, ".xml.rels" `isSuffixOf` (eRelativePath e)
546562
, eRelativePath e /= "word/_rels/document.xml.rels"
547-
, eRelativePath e /= "word/_rels/footnotes.xml.rels" ]
563+
, eRelativePath e /= "word/_rels/footnotes.xml.rels"
564+
, eRelativePath e /= "word/_rels/endnotes.xml.rels" ]
548565
let otherMediaEntries = [ e | e <- zEntries refArchive
549566
, "word/media/" `isPrefixOf` eRelativePath e ]
550567

551568
-- Create archive
552569
let archive = foldr addEntryToArchive emptyArchive $
553570
contentTypesEntry : relsEntry : contentEntry : relEntry :
554-
footnoteRelEntry : numEntry : styleEntry : footnotesEntry :
555-
commentsEntry :
571+
footnoteRelEntry : endnoteRelEntry : numEntry : styleEntry :
572+
footnotesEntry : endnotesEntry : commentsEntry :
556573
docPropsEntry : docPropsAppEntry : themeEntry :
557574
fontTableEntry : settingsEntry : webSettingsEntry :
558575
imageEntries ++ headerFooterEntries ++
@@ -751,7 +768,7 @@ makeTOC _ = return []
751768

752769
-- | Convert Pandoc document to two lists of
753770
-- OpenXML elements (the main document and footnotes).
754-
writeOpenXML :: (PandocMonad m) => WriterOptions -> Pandoc -> WS m ([Element], [Element],[Element])
771+
writeOpenXML :: (PandocMonad m) => WriterOptions -> Pandoc -> WS m ([Element], [Element], [Element], [Element])
755772
writeOpenXML opts (Pandoc meta blocks) = do
756773
let tit = docTitle meta
757774
let auths = docAuthors meta
@@ -778,7 +795,8 @@ writeOpenXML opts (Pandoc meta blocks) = do
778795
convertSpace xs = xs
779796
let blocks' = bottomUp convertSpace blocks
780797
doc' <- setFirstPara >> blocksToOpenXML opts blocks'
781-
notes' <- reverse <$> gets stFootnotes
798+
footnotes' <- reverse <$> gets stFootnotes
799+
endnotes' <- reverse <$> gets stEndnotes
782800
comments <- reverse <$> gets stComments
783801
let toComment (kvs, ils) = do
784802
annotation <- inlinesToOpenXML opts ils
@@ -798,7 +816,7 @@ writeOpenXML opts (Pandoc meta blocks) = do
798816
comments' <- mapM toComment comments
799817
toc <- makeTOC opts
800818
let meta' = title ++ subtitle ++ authors ++ date ++ abstract ++ toc
801-
return (meta' ++ doc', notes', comments')
819+
return (meta' ++ doc', footnotes', endnotes', comments')
802820

803821
-- | Convert a list of Pandoc blocks to OpenXML.
804822
blocksToOpenXML :: (PandocMonad m) => WriterOptions -> [Block] -> WS m [Element]
@@ -1225,8 +1243,8 @@ inlineToOpenXML' opts (Code attrs str) = do
12251243
Left msg -> do
12261244
unless (null msg) $ report $ CouldNotHighlight msg
12271245
unhighlighted
1228-
inlineToOpenXML' opts (Note _ bs) = do
1229-
notes <- gets stFootnotes
1246+
inlineToOpenXML' opts (Note FootNote bs) = do
1247+
footnotes <- gets stFootnotes
12301248
notenum <- (lift . lift) getUniqueId
12311249
footnoteStyle <- rStyleM "Footnote Reference"
12321250
let notemarker = mknode "w:r" []
@@ -1243,10 +1261,32 @@ inlineToOpenXML' opts (Note _ bs) = do
12431261
(withParaPropM (pStyleM "Footnote Text") $ blocksToOpenXML opts
12441262
$ insertNoteRef bs)
12451263
let newnote = mknode "w:footnote" [("w:id", notenum)] contents
1246-
modify $ \s -> s{ stFootnotes = newnote : notes }
1264+
modify $ \s -> s{ stFootnotes = newnote : footnotes }
12471265
return [ mknode "w:r" []
12481266
[ mknode "w:rPr" [] footnoteStyle
12491267
, mknode "w:footnoteReference" [("w:id", notenum)] () ] ]
1268+
inlineToOpenXML' opts (Note EndNote bs) = do
1269+
endnotes <- gets stEndnotes
1270+
notenum <- (lift . lift) getUniqueId
1271+
endnoteStyle <- rStyleM "Endnote Reference"
1272+
let notemarker = mknode "w:r" []
1273+
[ mknode "w:rPr" [] endnoteStyle
1274+
, mknode "w:endnoteRef" [] () ]
1275+
let notemarkerXml = RawInline (Format "openxml") $ ppElement notemarker
1276+
let insertNoteRef (Plain ils : xs) = Plain (notemarkerXml : Space : ils) : xs
1277+
insertNoteRef (Para ils : xs) = Para (notemarkerXml : Space : ils) : xs
1278+
insertNoteRef xs = Para [notemarkerXml] : xs
1279+
1280+
contents <- local (\env -> env{ envListLevel = -1
1281+
, envParaProperties = []
1282+
, envTextProperties = [] })
1283+
(withParaPropM (pStyleM "Endnote Text") $ blocksToOpenXML opts
1284+
$ insertNoteRef bs)
1285+
let newnote = mknode "w:endnote" [("w:id", notenum)] contents
1286+
modify $ \s -> s{ stEndnotes = newnote : endnotes }
1287+
return [ mknode "w:r" []
1288+
[ mknode "w:rPr" [] endnoteStyle
1289+
, mknode "w:endnoteReference" [("w:id", notenum)] () ] ]
12501290
-- internal link:
12511291
inlineToOpenXML' opts (Link _ txt ('#':xs,_)) = do
12521292
contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt

0 commit comments

Comments
 (0)