aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2020-04-12 14:51:59 +0100
committerMichael Williamson <mike@zwobble.org>2020-04-12 14:51:59 +0100
commit74118f20abb76972854f2723d0beea52f8c7f677 (patch)
tree39ddd471da5bff7ec6e576ee57b40d083565940c
parentdd8b8291facb24be3e73ab17be56d43f33f40780 (diff)
Read font size for runs
-rw-r--r--lib/documents.js3
-rw-r--r--lib/docx/body-reader.js90
-rw-r--r--test/docx/body-reader.tests.js15
3 files changed, 64 insertions, 44 deletions
diff --git a/lib/documents.js b/lib/documents.js
index 518db6e..df48beb 100644
--- a/lib/documents.js
+++ b/lib/documents.js
@@ -61,7 +61,8 @@ function Run(children, properties) {
isStrikethrough: properties.isStrikethrough,
isSmallCaps: properties.isSmallCaps,
verticalAlignment: properties.verticalAlignment || verticalAlignment.baseline,
- font: properties.font || null
+ font: properties.font || null,
+ fontSize: properties.fontSize || null
};
}
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index a1e20a8..45f6a33 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -46,7 +46,7 @@ function BodyReader(options) {
}
return emptyResult();
}
-
+
function readParagraphIndent(element) {
return {
start: element.attributes["w:start"] || element.attributes["w:left"],
@@ -55,15 +55,19 @@ function BodyReader(options) {
hanging: element.attributes["w:hanging"]
};
}
-
+
function readRunProperties(element) {
return readRunStyle(element).map(function(style) {
+ var fontSizeString = element.firstOrEmpty("w:sz").attributes["w:val"];
+ var fontSize = fontSizeString ? parseInt(fontSizeString, 10) / 2 : null;
+
return {
type: "runProperties",
styleId: style.styleId,
styleName: style.name,
verticalAlignment: element.firstOrEmpty("w:vertAlign").attributes["w:val"],
font: element.firstOrEmpty("w:rFonts").attributes["w:ascii"],
+ fontSize: fontSize,
isBold: readBooleanElement(element.first("w:b")),
isUnderline: readBooleanElement(element.first("w:u")),
isItalic: readBooleanElement(element.first("w:i")),
@@ -72,7 +76,7 @@ function BodyReader(options) {
};
});
}
-
+
function readBooleanElement(element) {
if (element) {
var value = element.attributes["w:val"];
@@ -81,19 +85,19 @@ function BodyReader(options) {
return false;
}
}
-
+
function readParagraphStyle(element) {
return readStyle(element, "w:pStyle", "Paragraph", styles.findParagraphStyleById);
}
-
+
function readRunStyle(element) {
return readStyle(element, "w:rStyle", "Run", styles.findCharacterStyleById);
}
-
+
function readTableStyle(element) {
return readStyle(element, "w:tblStyle", "Table", styles.findTableStyleById);
}
-
+
function readStyle(element, styleTagName, styleType, findStyleById) {
var messages = [];
var styleElement = element.first(styleTagName);
@@ -112,9 +116,9 @@ function BodyReader(options) {
}
return elementResultWithMessages({styleId: styleId, name: name}, messages);
}
-
+
var unknownComplexField = {type: "unknown"};
-
+
function readFldChar(element) {
var type = element.attributes["w:fldCharType"];
if (type === "begin") {
@@ -130,7 +134,7 @@ function BodyReader(options) {
}
return emptyResult();
}
-
+
function currentHyperlinkHref() {
var topHyperlink = _.last(complexFieldStack.filter(function(complexField) {
return complexField.type === "hyperlink";
@@ -146,12 +150,12 @@ function BodyReader(options) {
return null;
}
}
-
+
function readInstrText(element) {
currentInstrText.push(element.text());
return emptyResult();
}
-
+
function noteReferenceReader(noteType) {
return function(element) {
var noteId = element.attributes["w:id"];
@@ -161,17 +165,17 @@ function BodyReader(options) {
}));
};
}
-
+
function readCommentReference(element) {
return elementResult(documents.commentReference({
commentId: element.attributes["w:id"]
}));
}
-
+
function readChildElements(element) {
return readXmlElements(element.children);
}
-
+
var xmlElementReaders = {
"w:p": function(element) {
return readXmlElements(element.children)
@@ -228,13 +232,13 @@ function BodyReader(options) {
return readXmlElements(element.children).map(function(children) {
function create(options) {
var targetFrame = element.attributes["w:tgtFrame"] || null;
-
+
return new documents.Hyperlink(
children,
_.extend({targetFrame: targetFrame}, options)
);
}
-
+
if (relationshipId) {
var href = relationships.findTargetByRelationshipId(relationshipId);
if (anchor) {
@@ -274,11 +278,11 @@ function BodyReader(options) {
return elementResult(new documents.BookmarkStart({name: name}));
}
},
-
+
"mc:AlternateContent": function(element) {
return readChildElements(element.first("mc:Fallback"));
},
-
+
"w:sdt": function(element) {
return readXmlElements(element.firstOrEmpty("w:sdtContent").children);
},
@@ -300,13 +304,13 @@ function BodyReader(options) {
"v:group": readChildElements,
"v:rect": readChildElements
};
-
+
return {
readXmlElement: readXmlElement,
readXmlElements: readXmlElements
};
-
+
function readTable(element) {
var propertiesResult = readTableProperties(element.firstOrEmpty("w:tblPr"));
return readXmlElements(element.children)
@@ -317,7 +321,7 @@ function BodyReader(options) {
});
});
}
-
+
function readTableProperties(element) {
return readTableStyle(element).map(function(style) {
return {
@@ -326,7 +330,7 @@ function BodyReader(options) {
};
});
}
-
+
function readTableRow(element) {
var properties = element.firstOrEmpty("w:trPr");
var isHeader = !!properties.first("w:tblHeader");
@@ -334,20 +338,20 @@ function BodyReader(options) {
return documents.TableRow(children, {isHeader: isHeader});
});
}
-
+
function readTableCell(element) {
return readXmlElements(element.children).map(function(children) {
var properties = element.firstOrEmpty("w:tcPr");
-
+
var gridSpan = properties.firstOrEmpty("w:gridSpan").attributes["w:val"];
var colSpan = gridSpan ? parseInt(gridSpan, 10) : 1;
-
+
var cell = documents.TableCell(children, {colSpan: colSpan});
cell._vMerge = readVMerge(properties);
return cell;
});
}
-
+
function readVMerge(properties) {
var element = properties.first("w:vMerge");
if (element) {
@@ -357,7 +361,7 @@ function BodyReader(options) {
return null;
}
}
-
+
function calculateRowSpans(rows) {
var unexpectedNonRows = _.any(rows, function(row) {
return row.type !== documents.types.tableRow;
@@ -377,9 +381,9 @@ function BodyReader(options) {
"unexpected non-cell element in table row, cell merging may be incorrect"
)]);
}
-
+
var columns = {};
-
+
rows.forEach(function(row) {
var cellIndex = 0;
row.children.forEach(function(cell) {
@@ -392,7 +396,7 @@ function BodyReader(options) {
cellIndex += cell.colSpan;
});
});
-
+
rows.forEach(function(row) {
row.children = row.children.filter(function(cell) {
return !cell._vMerge;
@@ -401,7 +405,7 @@ function BodyReader(options) {
delete cell._vMerge;
});
});
-
+
return elementResult(rows);
}
@@ -412,20 +416,20 @@ function BodyReader(options) {
.getElementsByTagName("pic:pic")
.getElementsByTagName("pic:blipFill")
.getElementsByTagName("a:blip");
-
+
return combineResults(blips.map(readBlip.bind(null, element)));
}
-
+
function readBlip(element, blip) {
var properties = element.first("wp:docPr").attributes;
var altText = isBlank(properties.descr) ? properties.title : properties.descr;
return readImage(findBlipImageFile(blip), altText);
}
-
+
function isBlank(value) {
return value == null || /^\s*$/.test(value);
}
-
+
function findBlipImageFile(blip) {
var embedRelationshipId = blip.attributes["r:embed"];
var linkRelationshipId = blip.attributes["r:link"];
@@ -439,10 +443,10 @@ function BodyReader(options) {
};
}
}
-
+
function readImageData(element) {
var relationshipId = element.attributes['r:id'];
-
+
if (relationshipId) {
return readImage(
findEmbeddedImageFile(relationshipId),
@@ -451,7 +455,7 @@ function BodyReader(options) {
return emptyResultWithMessages([warning("A v:imagedata element without a relationship ID was ignored")]);
}
}
-
+
function findEmbeddedImageFile(relationshipId) {
var path = uris.uriToZipEntryName("word", relationships.findTargetByRelationshipId(relationshipId));
return {
@@ -459,10 +463,10 @@ function BodyReader(options) {
read: docxFile.read.bind(docxFile, path)
};
}
-
+
function readImage(imageFile, altText) {
var contentType = contentTypes.findContentType(imageFile.path);
-
+
var image = documents.Image({
readImage: imageFile.read,
altText: altText,
@@ -472,7 +476,7 @@ function BodyReader(options) {
[] : warning("Image of type " + contentType + " is unlikely to display in web browsers");
return elementResultWithMessages(image, warnings);
}
-
+
function undefinedStyleWarning(type, styleId) {
return warning(
type + " style with ID " + styleId + " was referenced but not defined in the document");
@@ -489,7 +493,7 @@ function readNumberingProperties(element, numbering) {
return numbering.findLevel(numId, level);
}
}
-
+
var supportedImageTypes = {
"image/png": true,
"image/gif": true,
diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js
index d6f7199..73c8647 100644
--- a/test/docx/body-reader.tests.js
+++ b/test/docx/body-reader.tests.js
@@ -565,6 +565,21 @@ test("run has font read from properties", function() {
assert.deepEqual(run.font, "Arial");
});
+test("run has null fontSize by default", function() {
+ var runXml = runWithProperties([]);
+
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.fontSize, null);
+});
+
+test("run has fontSize read from properties", function() {
+ var fontSizeXml = new XmlElement("w:sz", {"w:val": "28"});
+ var runXml = runWithProperties([fontSizeXml]);
+
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.fontSize, 14);
+});
+
test("run properties not included as child of run", function() {
var runStyleXml = new XmlElement("w:rStyle");
var runPropertiesXml = new XmlElement("w:rPr", {}, [runStyleXml]);