aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2025-11-20 15:16:07 +0000
committerMichael Williamson <mike@zwobble.org>2025-11-20 15:16:07 +0000
commit5b8d20f1cdca33a08cd0cb72af5b13c22653cea3 (patch)
treea6d3b52fd0d709327a28e4ffe0be8eb89246af5e
parent3261fbb689a2d54c151d6be7fa653553735e5861 (diff)
Handle hyperlinked wp:anchor and wp:inline elements
-rw-r--r--NEWS4
-rw-r--r--lib/docx/body-reader.js18
-rw-r--r--test/docx/body-reader.tests.js42
3 files changed, 56 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index 2b7fd2b..d9b8255 100644
--- a/NEWS
+++ b/NEWS
@@ -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", {}, [