diff --git a/lib/documents.js b/lib/documents.js index c37ec057..2613a7a3 100644 --- a/lib/documents.js +++ b/lib/documents.js @@ -6,6 +6,7 @@ var types = exports.types = { run: "run", text: "text", tab: "tab", + checkbox: "checkbox", hyperlink: "hyperlink", noteReference: "noteReference", image: "image", @@ -87,6 +88,13 @@ function Tab() { }; } +function Checkbox(options) { + return { + type: types.checkbox, + checked: options.checked + }; +} + function Hyperlink(children, options) { return { type: types.hyperlink, @@ -227,6 +235,7 @@ exports.paragraph = exports.Paragraph = Paragraph; exports.run = exports.Run = Run; exports.text = exports.Text = Text; exports.tab = exports.Tab = Tab; +exports.checkbox = exports.Checkbox = Checkbox; exports.Hyperlink = Hyperlink; exports.noteReference = exports.NoteReference = NoteReference; exports.Notes = Notes; diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js index 28bd2efe..a4a6c0c6 100644 --- a/lib/docx/body-reader.js +++ b/lib/docx/body-reader.js @@ -165,10 +165,12 @@ function BodyReader(options) { complexFieldStack.push(unknownComplexField); currentInstrText = []; } else if (type === "end") { - complexFieldStack.pop(); + var complexFieldEnd = complexFieldStack.pop(); + if (complexFieldEnd.type === "checkbox") { + return elementResult(documents.checkbox({checked: false})); + } } else if (type === "separate") { - var hyperlinkOptions = parseHyperlinkFieldCode(currentInstrText.join('')); - var complexField = hyperlinkOptions === null ? unknownComplexField : {type: "hyperlink", options: hyperlinkOptions}; + var complexField = parseInstrText(currentInstrText.join('')); complexFieldStack.pop(); complexFieldStack.push(complexField); } @@ -182,18 +184,23 @@ function BodyReader(options) { return topHyperlink ? topHyperlink.options : null; } - function parseHyperlinkFieldCode(code) { - var externalLinkResult = /\s*HYPERLINK "(.*)"/.exec(code); + function parseInstrText(instrText) { + var externalLinkResult = /\s*HYPERLINK "(.*)"/.exec(instrText); if (externalLinkResult) { - return {href: externalLinkResult[1]}; + return {type: "hyperlink", options: {href: externalLinkResult[1]}}; } - var internalLinkResult = /\s*HYPERLINK\s+\\l\s+"(.*)"/.exec(code); + var internalLinkResult = /\s*HYPERLINK\s+\\l\s+"(.*)"/.exec(instrText); if (internalLinkResult) { - return {anchor: internalLinkResult[1]}; + return {type: "hyperlink", options: {anchor: internalLinkResult[1]}}; + } + + var checkboxResult = /\s*FORMCHECKBOX\s*/.exec(instrText); + if (checkboxResult) { + return {type: "checkbox"}; } - return null; + return unknownComplexField; } function readInstrText(element) { diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js index 292e1a2e..a431866c 100644 --- a/test/docx/body-reader.tests.js +++ b/test/docx/body-reader.tests.js @@ -7,12 +7,14 @@ var assertThat = hamjest.assertThat; var promiseThat = hamjest.promiseThat; var allOf = hamjest.allOf; var contains = hamjest.contains; +var equalTo = hamjest.equalTo; var hasProperties = hamjest.hasProperties; var willBe = hamjest.willBe; var FeatureMatcher = hamjest.FeatureMatcher; var documentMatchers = require("./document-matchers"); var isEmptyRun = documentMatchers.isEmptyRun; +var isCheckbox = documentMatchers.isCheckbox; var isHyperlink = documentMatchers.isHyperlink; var isRun = documentMatchers.isRun; var isText = documentMatchers.isText; @@ -529,6 +531,41 @@ test("complex fields", (function() { }; })()); +test("checkboxes", { + "complex field checkbox without default or checked elements is unchecked": function() { + var paragraphXml = xml.element("w:p", {}, [ + xml.element("w:r", {}, [ + xml.element("w:fldChar", {"w:fldCharType": "begin"}, [ + xml.element("w:ffData", {}, [ + xml.element("w:checkBox") + ]) + ]) + ]), + xml.element("w:instrText", {}, [ + xml.text(' FORMCHECKBOX ') + ]), + xml.element("w:r", {}, [ + xml.element("w:fldChar", {"w:fldCharType": "separate"}) + ]), + xml.element("w:r", {}, [ + xml.element("w:fldChar", {"w:fldCharType": "end"}) + ]) + ]); + + var paragraph = readXmlElementValue(paragraphXml); + + assertThat(paragraph.children, contains( + isEmptyRun, + isEmptyRun, + isRun({ + children: contains( + isCheckbox({checked: equalTo(false)}) + ) + }) + )); + } +}); + test("run has no style if it has no properties", function() { var runXml = runWithProperties([]); var run = readXmlElementValue(runXml); diff --git a/test/docx/document-matchers.js b/test/docx/document-matchers.js index 83c4486c..11b5aa96 100644 --- a/test/docx/document-matchers.js +++ b/test/docx/document-matchers.js @@ -7,6 +7,7 @@ var documents = require("../../lib/documents"); exports.isEmptyRun = isRun({children: []}); exports.isRun = isRun; exports.isText = isText; +exports.isCheckbox = isCheckbox; exports.isHyperlink = isHyperlink; exports.isTable = isTable; exports.isRow = isRow; @@ -20,6 +21,10 @@ function isText(text) { return isDocumentElement(documents.types.text, {value: text}); } +function isCheckbox(properties) { + return isDocumentElement(documents.types.checkbox, properties); +} + function isHyperlink(properties) { return isDocumentElement(documents.types.hyperlink, properties); }