diff --git a/src/Text/Pandoc/Writers/Docx/OpenXML.hs b/src/Text/Pandoc/Writers/Docx/OpenXML.hs index 473f51e62..c3be160f0 100644 --- a/src/Text/Pandoc/Writers/Docx/OpenXML.hs +++ b/src/Text/Pandoc/Writers/Docx/OpenXML.hs @@ -25,7 +25,7 @@ import Control.Applicative ((<|>)) import Control.Monad.Except (catchError) import Crypto.Hash (hashWith, SHA1(SHA1)) import qualified Data.ByteString.Lazy as BL -import Data.Char (isLetter, isSpace) +import Data.Char (isLetter, isSpace, isAlphaNum) import Text.Pandoc.Char (isCJK) import Data.Ord (comparing) import Data.String (fromString) @@ -1140,14 +1140,18 @@ wrapBookmark ident contents = do return $ Elem bookmarkStart : contents ++ [Elem bookmarkEnd] -- Word imposes a 40 character limit on bookmark names and requires --- that they begin with a letter. So we just use a hash of the --- identifier when otherwise we'd have an illegal bookmark name. +-- that they begin with a letter or @_@ and contain only letters, +-- numbers or underscores. Bookmarks beginning with @_@ are +-- hidden in the user interface (and in particular hidden from screen +-- readers, which we want); these are to be used for cross-references. +-- When the id is otherwise illegal we use a hash of the identifier. toBookmarkName :: Text -> Text toBookmarkName s - | Just (c, _) <- T.uncons s - , isLetter c - , T.length s <= 40 = s - | otherwise = T.pack $ 'X' : drop 1 (show (hashWith SHA1 (fromText s))) + | T.length s < 40 + , T.all (\c -> isAlphaNum c || c == '_') s + = "_" <> s + | otherwise = "_" <> T.pack (drop 1 (show (hashWith SHA1 (fromText s)))) + -- we drop 1 because a SHA1 is 40 characters and we need room for the `_` maxListLevel :: Int maxListLevel = 8 diff --git a/test/docx/golden/block_quotes.docx b/test/docx/golden/block_quotes.docx index 00be50e4d..a56e2b6be 100644 Binary files a/test/docx/golden/block_quotes.docx and b/test/docx/golden/block_quotes.docx differ diff --git a/test/docx/golden/custom_style_preserve.docx b/test/docx/golden/custom_style_preserve.docx index cd0b9b69a..66fa80775 100644 Binary files a/test/docx/golden/custom_style_preserve.docx and b/test/docx/golden/custom_style_preserve.docx differ diff --git a/test/docx/golden/headers.docx b/test/docx/golden/headers.docx index 64a9d7a01..927319c56 100644 Binary files a/test/docx/golden/headers.docx and b/test/docx/golden/headers.docx differ diff --git a/test/docx/golden/image.docx b/test/docx/golden/image.docx index cea29628a..6d406e047 100644 Binary files a/test/docx/golden/image.docx and b/test/docx/golden/image.docx differ diff --git a/test/docx/golden/links.docx b/test/docx/golden/links.docx index e51a54f6f..e4771e734 100644 Binary files a/test/docx/golden/links.docx and b/test/docx/golden/links.docx differ diff --git a/test/docx/golden/lists.docx b/test/docx/golden/lists.docx index fbea56b38..318f74abb 100644 Binary files a/test/docx/golden/lists.docx and b/test/docx/golden/lists.docx differ diff --git a/test/docx/golden/lists_div_bullets.docx b/test/docx/golden/lists_div_bullets.docx index 07fbf73ba..d3733238b 100644 Binary files a/test/docx/golden/lists_div_bullets.docx and b/test/docx/golden/lists_div_bullets.docx differ diff --git a/test/docx/golden/nested_anchors_in_header.docx b/test/docx/golden/nested_anchors_in_header.docx index 333eac410..8ef14a778 100644 Binary files a/test/docx/golden/nested_anchors_in_header.docx and b/test/docx/golden/nested_anchors_in_header.docx differ diff --git a/test/docx/golden/notes.docx b/test/docx/golden/notes.docx index a8dd65878..5aef60373 100644 Binary files a/test/docx/golden/notes.docx and b/test/docx/golden/notes.docx differ diff --git a/test/docx/golden/tables-default-widths.docx b/test/docx/golden/tables-default-widths.docx index e8e72c391..ac25a17cd 100644 Binary files a/test/docx/golden/tables-default-widths.docx and b/test/docx/golden/tables-default-widths.docx differ diff --git a/test/docx/golden/tables.docx b/test/docx/golden/tables.docx index 63ccd94ee..0a3063bd7 100644 Binary files a/test/docx/golden/tables.docx and b/test/docx/golden/tables.docx differ