summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Lehman <jonathan.lehman91@gmail.com>2017-02-18 11:50:51 -0500
committerGitHub <noreply@github.com>2017-02-18 11:50:51 -0500
commit140a1f71532d0a34df2cff7cff688e97dca7c164 (patch)
treed8aec937f9ae9e7a835c43cf6ffb777f2d40a898
parentc626ef8e1047fb9f27fc4db8c17783a711bd566a (diff)
parent35df4eed2249ee7e582cca4d371a78ce92c44d2a (diff)
Merge pull request #1 from jdlehman/hyperlink-edge-cases
Hyperlink edge cases
-rw-r--r--lib/docx/body-reader.js33
-rw-r--r--test/docx/body-reader.tests.js155
2 files changed, 179 insertions, 9 deletions
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index e92f8b4..11aeec5 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -20,7 +20,8 @@ function createBodyReader(options) {
}
function BodyReader(options) {
- var fieldHyperlink = null;
+ var complexFields = [];
+ var currentInstrText = [];
var relationships = options.relationships;
var contentTypes = options.contentTypes;
var docxFile = options.docxFile;
@@ -147,8 +148,9 @@ function BodyReader(options) {
var properties = _.find(children, isRunProperties);
children = children.filter(negate(isRunProperties));
- if (fieldHyperlink !== null) {
- children = [new documents.Hyperlink(children, {href: fieldHyperlink})];
+ var scopedHyperlink = scopedComplexFieldOfType(complexFields, "hyperlink");
+ if (scopedHyperlink !== undefined) {
+ children = [new documents.Hyperlink(children, {href: scopedHyperlink.href})];
}
return new documents.Run(children, properties);
@@ -158,15 +160,20 @@ function BodyReader(options) {
"w:fldChar": function(element) {
var type = element.attributes["w:fldCharType"];
if (type === "end") {
- fieldHyperlink = null;
+ complexFields.pop();
+ } else if (type === "separate") {
+ var href = parseHyperlinkFieldCode(currentInstrText.join(''));
+ if (href !== null) {
+ complexFields.push({type: "hyperlink", href: href});
+ } else {
+ complexFields.push(null);
+ }
+ currentInstrText = [];
}
return emptyResult();
},
"w:instrText": function(element) {
- var hyperlink = parseHyperlinkFieldCode(element.text());
- if (hyperlink !== null) {
- fieldHyperlink = hyperlink;
- }
+ currentInstrText.push(element.text());
return emptyResult();
},
"w:t": function(element) {
@@ -530,3 +537,13 @@ function parseHyperlinkFieldCode(code) {
return null;
}
}
+
+function complexFieldsOfType(complexFields, type) {
+ return complexFields.filter(function(complexField) {
+ return complexField.type === type;
+ });
+}
+
+function scopedComplexFieldOfType(complexFields, type) {
+ return _.last(complexFieldsOfType(complexFields, type));
+}
diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js
index ab4995c..a670202 100644
--- a/test/docx/body-reader.tests.js
+++ b/test/docx/body-reader.tests.js
@@ -148,9 +148,13 @@ test("complex fields", (function() {
var endXml = new XmlElement("w:r", {}, [
new XmlElement("w:fldChar", {"w:fldCharType": "end"})
]);
+ var separateXml = new XmlElement("w:r", {}, [
+ new XmlElement("w:fldChar", {"w:fldCharType": "separate"})
+ ]);
var hyperlinkInstrText = new XmlElement("w:instrText", {}, [
xml.text(' HYPERLINK "' + uri + '"')
]);
+ var hyperlinkRunXml = runOfText("this is a hyperlink");
return {
"stores instrText returns empty result": function() {
@@ -160,10 +164,10 @@ test("complex fields", (function() {
"runs in a complex field for hyperlinks are read as hyperlinks": function() {
var hyperlinkRunXml = runOfText("this is a hyperlink");
- var afterEndXml = runOfText("this will not be a hyperlink");
var paragraphXml = new XmlElement("w:p", {}, [
beginXml,
hyperlinkInstrText,
+ separateXml,
hyperlinkRunXml,
endXml
]);
@@ -175,6 +179,14 @@ test("complex fields", (function() {
children: contains(
isHyperlink({
href: uri,
+ children: []
+ })
+ )
+ }),
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
children: contains(
isText("this is a hyperlink")
)
@@ -190,6 +202,7 @@ test("complex fields", (function() {
var paragraphXml = new XmlElement("w:p", {}, [
beginXml,
hyperlinkInstrText,
+ separateXml,
endXml,
afterEndXml
]);
@@ -197,6 +210,14 @@ test("complex fields", (function() {
assertThat(paragraph.children, contains(
isEmptyRun,
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: []
+ })
+ )
+ }),
isEmptyRun,
isRun({
children: contains(
@@ -204,6 +225,138 @@ test("complex fields", (function() {
)
})
));
+ },
+
+ "can handle split instrText elements": function() {
+ var hyperlinkInstrTextPart1 = new XmlElement("w:instrText", {}, [
+ xml.text(" HYPE")
+ ]);
+ var hyperlinkInstrTextPart2 = new XmlElement("w:instrText", {}, [
+ xml.text('RLINK "' + uri + '"')
+ ]);
+ var paragraphXml = new XmlElement("w:p", {}, [
+ beginXml,
+ hyperlinkInstrTextPart1,
+ hyperlinkInstrTextPart2,
+ separateXml,
+ hyperlinkRunXml,
+ endXml
+ ]);
+ var paragraph = readXmlElementValue(paragraphXml);
+
+ assertThat(paragraph.children, contains(
+ isEmptyRun,
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: []
+ })
+ )
+ }),
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: contains(
+ isText("this is a hyperlink")
+ )
+ })
+ )
+ }),
+ isEmptyRun
+ ));
+ },
+
+ "hyperlink with a nested complex field uses the outer hyperlink": function() {
+ var authorInstrText = new XmlElement("w:instrText", {}, [
+ xml.text(' AUTHOR "John Doe"')
+ ]);
+ var paragraphXml = new XmlElement("w:p", {}, [
+ beginXml,
+ beginXml,
+ authorInstrText,
+ endXml,
+ hyperlinkInstrText,
+ separateXml,
+ hyperlinkRunXml,
+ endXml
+ ]);
+ var paragraph = readXmlElementValue(paragraphXml);
+
+ assertThat(paragraph.children, contains(
+ isEmptyRun,
+ isEmptyRun,
+ isEmptyRun,
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: []
+ })
+ )
+ }),
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: contains(
+ isText("this is a hyperlink")
+ )
+ })
+ )
+ }),
+ isEmptyRun
+ ));
+ },
+
+ "complex field nested within a hyperlink complex field is wrapped with the hyperlink": function() {
+ var authorInstrText = new XmlElement("w:instrText", {}, [
+ xml.text(' AUTHOR "John Doe"')
+ ]);
+ var paragraphXml = new XmlElement("w:p", {}, [
+ beginXml,
+ hyperlinkInstrText,
+ separateXml,
+ hyperlinkRunXml,
+ beginXml,
+ authorInstrText,
+ endXml,
+ endXml
+ ]);
+ var paragraph = readXmlElementValue(paragraphXml);
+
+ assertThat(paragraph.children, contains(
+ isEmptyRun,
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: []
+ })
+ )
+ }),
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: contains(
+ isText("this is a hyperlink")
+ )
+ })
+ )
+ }),
+ isRun({
+ children: contains(
+ isHyperlink({
+ href: uri,
+ children: []
+ })
+ )
+ }),
+ isEmptyRun,
+ isEmptyRun
+ ));
}
};
})());