diff options
| author | Michael Williamson <mike@zwobble.org> | 2025-11-20 15:16:07 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2025-11-20 15:16:07 +0000 |
| commit | 5b8d20f1cdca33a08cd0cb72af5b13c22653cea3 (patch) | |
| tree | a6d3b52fd0d709327a28e4ffe0be8eb89246af5e | |
| parent | 3261fbb689a2d54c151d6be7fa653553735e5861 (diff) | |
Handle hyperlinked wp:anchor and wp:inline elements
| -rw-r--r-- | NEWS | 4 | ||||
| -rw-r--r-- | lib/docx/body-reader.js | 18 | ||||
| -rw-r--r-- | test/docx/body-reader.tests.js | 42 |
3 files changed, 56 insertions, 8 deletions
@@ -1,3 +1,7 @@ +# 1.12.0 + +* Handle hyperlinked wp:anchor and wp:inline elements. + # 1.11.0 * Ignore style definitions using a style ID that has already been used. diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js index 826424b..febbbc2 100644 --- a/lib/docx/body-reader.js +++ b/lib/docx/body-reader.js @@ -586,14 +586,26 @@ function BodyReader(options) { } function readBlip(element, blip) { - var properties = element.first("wp:docPr").attributes; + var propertiesElement = element.firstOrEmpty("wp:docPr"); + var properties = propertiesElement.attributes; + var altText = isBlank(properties.descr) ? properties.title : properties.descr; + var blipImageFile = findBlipImageFile(blip); if (blipImageFile === null) { return emptyResultWithMessages([warning("Could not find image file for a:blip element")]); - } else { - return readImage(blipImageFile, altText); } + + return readImage(blipImageFile, altText).map(function(imageElement) { + var hlinkClickElement = propertiesElement.firstOrEmpty("a:hlinkClick"); + var relationshipId = hlinkClickElement.attributes["r:id"]; + if (relationshipId) { + var href = relationships.findTargetByRelationshipId(relationshipId); + return new documents.Hyperlink([imageElement], {href: href}); + } else { + return imageElement; + } + }); } function isBlank(value) { diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js index de7af2d..dee38a5 100644 --- a/test/docx/body-reader.tests.js +++ b/test/docx/body-reader.tests.js @@ -1455,11 +1455,15 @@ function isImage(options) { } } -function readEmbeddedImage(element) { +function readEmbeddedImage(element, options) { + options = options || {}; + + var relationships = [ + imageRelationship("rId5", "media/hat.png") + ].concat(options.relationships || []); + return readXmlElement(element, { - relationships: new Relationships([ - imageRelationship("rId5", "media/hat.png") - ]), + relationships: new Relationships(relationships), contentTypes: fakeContentTypes, docxFile: createFakeDocxFile({ "word/media/hat.png": IMAGE_BUFFER @@ -1642,6 +1646,30 @@ test("no elements created if image cannot be found in wp:inline", function() { assert.deepEqual(result.value, []); }); +test("can read pictures with hyperlink specified in document properties", function() { + var drawing = createInlineImage({ + blip: createEmbeddedBlip(IMAGE_RELATIONSHIP_ID), + docPrChildren: [ + new XmlElement("a:hlinkClick", {"r:id": "rId42"}) + ] + }); + var relationships = [hyperlinkRelationship("rId42", "http://example.com")]; + + var result = readEmbeddedImage(drawing, {relationships: relationships}); + + return promiseThat(result, isSuccess(contains( + isHyperlink({ + href: "http://example.com", + children: contains( + isImage({ + contentType: "image/png", + buffer: IMAGE_BUFFER + }) + ) + }) + ))); +}); + test("children of w:ins are converted normally", function() { assertChildrenAreConvertedNormally("w:ins"); }); @@ -1893,7 +1921,11 @@ function single(array) { function createInlineImage(options) { return new XmlElement("w:drawing", {}, [ new XmlElement("wp:inline", {}, [ - new XmlElement("wp:docPr", {descr: options.description, title: options.title}), + new XmlElement( + "wp:docPr", + {descr: options.description, title: options.title}, + options.docPrChildren + ), new XmlElement("a:graphic", {}, [ new XmlElement("a:graphicData", {}, [ new XmlElement("pic:pic", {}, [ |
