1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528 |
- var assert = require("assert");
- var path = require("path");
- var _ = require("underscore");
- var hamjest = require("hamjest");
- var assertThat = hamjest.assertThat;
- var promiseThat = hamjest.promiseThat;
- var allOf = hamjest.allOf;
- var contains = hamjest.contains;
- var hasProperties = hamjest.hasProperties;
- var willBe = hamjest.willBe;
- var FeatureMatcher = hamjest.FeatureMatcher;
- var documentMatchers = require("./document-matchers");
- var isEmptyRun = documentMatchers.isEmptyRun;
- var isHyperlink = documentMatchers.isHyperlink;
- var isRun = documentMatchers.isRun;
- var isText = documentMatchers.isText;
- var isTable = documentMatchers.isTable;
- var isRow = documentMatchers.isRow;
- var _readNumberingProperties = require("../../lib/docx/body-reader")._readNumberingProperties;
- var documents = require("../../lib/documents");
- var xml = require("../../lib/xml");
- var XmlElement = xml.Element;
- var Relationships = require("../../lib/docx/relationships-reader").Relationships;
- var Styles = require("../../lib/docx/styles-reader").Styles;
- var warning = require("../../lib/results").warning;
- var testing = require("../testing");
- var test = require("../test")(module);
- var createBodyReaderForTests = require("./testing").createBodyReaderForTests;
- var createFakeDocxFile = testing.createFakeDocxFile;
- function readXmlElement(element, options) {
- return createBodyReaderForTests(options).readXmlElement(element);
- }
- function readXmlElements(element, options) {
- return createBodyReaderForTests(options).readXmlElements(element);
- }
- function readXmlElementValue(element, options) {
- var result = readXmlElement(element, options);
- assert.deepEqual(result.messages, []);
- return result.value;
- }
- function readXmlElementsValue(elements, options) {
- var result = readXmlElements(elements, options);
- assert.deepEqual(result.messages, []);
- return result.value;
- }
- var fakeContentTypes = {
- findContentType: function(filePath) {
- var extensionTypes = {
- ".png": "image/png",
- ".emf": "image/x-emf"
- };
- return extensionTypes[path.extname(filePath)];
- }
- };
- test("paragraph has no style if it has no properties", function() {
- var paragraphXml = new XmlElement("w:p", {}, []);
- var paragraph = readXmlElementValue(paragraphXml);
- assert.deepEqual(paragraph.styleId, null);
- });
- test("paragraph has style ID and name read from paragraph properties if present", function() {
- var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var styles = new Styles({"Heading1": {name: "Heading 1"}}, {});
- var paragraph = readXmlElementValue(paragraphXml, {styles: styles});
- assert.deepEqual(paragraph.styleId, "Heading1");
- assert.deepEqual(paragraph.styleName, "Heading 1");
- });
- test("warning is emitted when paragraph style cannot be found", function() {
- var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var styles = new Styles({}, {});
- var result = readXmlElement(paragraphXml, {styles: styles});
- var paragraph = result.value;
- assert.deepEqual(paragraph.styleId, "Heading1");
- assert.deepEqual(paragraph.styleName, null);
- assert.deepEqual(result.messages, [warning("Paragraph style with ID Heading1 was referenced but not defined in the document")]);
- });
- test("paragraph has justification read from paragraph properties if present", function() {
- var justificationXml = new XmlElement("w:jc", {"w:val": "center"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [justificationXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var paragraph = readXmlElementValue(paragraphXml);
- assert.deepEqual(paragraph.alignment, "center");
- });
- test("paragraph indent", {
- "when w:start is set then start indent is read from w:start": function() {
- var paragraphXml = paragraphWithIndent({"w:start": "720", "w:left": "40"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.start, "720");
- },
- "when w:start is not set then start indent is read from w:left": function() {
- var paragraphXml = paragraphWithIndent({"w:left": "720"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.start, "720");
- },
- "when w:end is set then end indent is read from w:end": function() {
- var paragraphXml = paragraphWithIndent({"w:end": "720", "w:right": "40"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.end, "720");
- },
- "when w:end is not set then end indent is read from w:right": function() {
- var paragraphXml = paragraphWithIndent({"w:right": "720"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.end, "720");
- },
- "paragraph has indent firstLine read from paragraph properties if present": function() {
- var paragraphXml = paragraphWithIndent({"w:firstLine": "720"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.firstLine, "720");
- },
- "paragraph has indent hanging read from paragraph properties if present": function() {
- var paragraphXml = paragraphWithIndent({"w:hanging": "720"});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.hanging, "720");
- },
- "when indent attributes aren't set then indents are null": function() {
- var paragraphXml = paragraphWithIndent({});
- var paragraph = readXmlElementValue(paragraphXml);
- assert.equal(paragraph.indent.start, null);
- assert.equal(paragraph.indent.end, null);
- assert.equal(paragraph.indent.firstLine, null);
- assert.equal(paragraph.indent.hanging, null);
- }
- });
- function paragraphWithIndent(indentAttributes) {
- var indentXml = new XmlElement("w:ind", indentAttributes, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [indentXml]);
- return new XmlElement("w:p", {}, [propertiesXml]);
- }
- test("paragraph has numbering properties from paragraph properties if present", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"}),
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
- var propertiesXml = new XmlElement("w:pPr", {}, [numberingPropertiesXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var numbering = new NumberingMap({
- findLevel: {"42": {"1": {isOrdered: true, level: "1"}}}
- });
- var paragraph = readXmlElementValue(paragraphXml, {numbering: numbering});
- assert.deepEqual(paragraph.numbering, {level: "1", isOrdered: true});
- });
- test("paragraph has numbering from paragraph style if present", function() {
- var propertiesXml = new XmlElement("w:pPr", {}, [
- new XmlElement("w:pStyle", {"w:val": "List"})
- ]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var numbering = new NumberingMap({
- findLevelByParagraphStyleId: {"List": {isOrdered: true, level: "1"}}
- });
- var styles = new Styles({"List": {name: "List"}}, {});
- var paragraph = readXmlElementValue(paragraphXml, {numbering: numbering, styles: styles});
- assert.deepEqual(paragraph.numbering, {level: "1", isOrdered: true});
- });
- test("numbering properties in paragraph properties takes precedence over numbering in paragraph style", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"}),
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
- var propertiesXml = new XmlElement("w:pPr", {}, [
- new XmlElement("w:pStyle", {"w:val": "List"}),
- numberingPropertiesXml
- ]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var numbering = new NumberingMap({
- findLevel: {"42": {"1": {isOrdered: true, level: "1"}}},
- findLevelByParagraphStyleId: {"List": {isOrdered: true, level: "2"}}
- });
- var styles = new Styles({"List": {name: "List"}}, {});
- var paragraph = readXmlElementValue(paragraphXml, {numbering: numbering, styles: styles});
- assert.deepEqual(paragraph.numbering, {level: "1", isOrdered: true});
- });
- test("numbering properties are converted to numbering at specified level", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"}),
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
- var numbering = new NumberingMap({
- findLevel: {"42": {"1": {isOrdered: true, level: "1"}}}
- });
- var numberingLevel = _readNumberingProperties(null, numberingPropertiesXml, numbering);
- assert.deepEqual(numberingLevel, {level: "1", isOrdered: true});
- });
- test("numbering properties are ignored if w:ilvl is missing", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
- var numbering = new NumberingMap({
- findLevel: {"42": {"1": {isOrdered: true, level: "1"}}}
- });
- var numberingLevel = _readNumberingProperties(null, numberingPropertiesXml, numbering);
- assert.equal(numberingLevel, null);
- });
- test("numbering properties are ignored if w:numId is missing", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"})
- ]);
- var numbering = new NumberingMap({
- findLevel: {"42": {"1": {isOrdered: true, level: "1"}}}
- });
- var numberingLevel = _readNumberingProperties(null, numberingPropertiesXml, numbering);
- assert.equal(numberingLevel, null);
- });
- test("content of deleted paragraph is prepended to next paragraph", function() {
- var styles = new Styles(
- {
- "Heading1": {name: "Heading 1"},
- "Heading2": {name: "Heading 2"}
- },
- {}
- );
- var bodyXml = [
- new XmlElement("w:p", {}, [
- new XmlElement("w:pPr", {}, [
- new XmlElement("w:pStyle", {"w:val": "Heading1"}, []),
- new XmlElement("w:rPr", {}, [
- new XmlElement("w:del")
- ])
- ]),
- runOfText("One")
- ]),
- new XmlElement("w:p", {}, [
- new XmlElement("w:pPr", {}, [
- new XmlElement("w:pStyle", {"w:val": "Heading2"}, [])
- ]),
- runOfText("Two")
- ]),
- // Include a second paragraph that isn't deleted to ensure we only add
- // the deleted paragraph contents once.
- new XmlElement("w:p", {}, [
- runOfText("Three")
- ])
- ];
- var result = readXmlElementsValue(bodyXml, {styles: styles});
- assertThat(result, contains(
- hasProperties({
- type: documents.types.paragraph,
- styleId: "Heading2",
- children: contains(
- documents.run([documents.text("One")]),
- documents.run([documents.text("Two")])
- )
- }),
- hasProperties({
- type: documents.types.paragraph,
- children: contains(
- documents.run([documents.text("Three")])
- )
- })
- ));
- });
- test("complex fields", (function() {
- var uri = "http://example.com";
- var beginXml = new XmlElement("w:r", {}, [
- new XmlElement("w:fldChar", {"w:fldCharType": "begin"})
- ]);
- 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");
- var isEmptyHyperlinkedRun = isHyperlinkedRun({children: []});
- function isHyperlinkedRun(hyperlinkProperties) {
- return isRun({
- children: contains(
- isHyperlink(hyperlinkProperties)
- )
- });
- }
- return {
- "stores instrText returns empty result": function() {
- var instrText = readXmlElementValue(hyperlinkInstrText);
- assert.deepEqual(instrText, []);
- },
- "runs in a complex field for hyperlink without switch are read as external hyperlinks": function() {
- var hyperlinkRunXml = runOfText("this is a hyperlink");
- var paragraphXml = new XmlElement("w:p", {}, [
- beginXml,
- hyperlinkInstrText,
- separateXml,
- hyperlinkRunXml,
- endXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- href: uri,
- children: contains(
- isText("this is a hyperlink")
- )
- }),
- isEmptyRun
- ));
- },
- "runs in a complex field for hyperlink with l switch are read as internal hyperlinks": function() {
- var hyperlinkRunXml = runOfText("this is a hyperlink");
- var paragraphXml = new XmlElement("w:p", {}, [
- beginXml,
- new XmlElement("w:instrText", {}, [
- xml.text(' HYPERLINK \\l "InternalLink"')
- ]),
- separateXml,
- hyperlinkRunXml,
- endXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- anchor: "InternalLink",
- children: contains(
- isText("this is a hyperlink")
- )
- }),
- isEmptyRun
- ));
- },
- "runs after a complex field for hyperlinks are not read as hyperlinks": function() {
- var afterEndXml = runOfText("this will not be a hyperlink");
- var paragraphXml = new XmlElement("w:p", {}, [
- beginXml,
- hyperlinkInstrText,
- separateXml,
- endXml,
- afterEndXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isEmptyRun,
- isRun({
- children: contains(
- isText("this will not be a hyperlink")
- )
- })
- ));
- },
- "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,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- href: uri,
- children: contains(
- isText("this is a hyperlink")
- )
- }),
- isEmptyRun
- ));
- },
- "hyperlink is not ended by end of nested complex field": function() {
- var authorInstrText = new XmlElement("w:instrText", {}, [
- xml.text(' AUTHOR "John Doe"')
- ]);
- var paragraphXml = new XmlElement("w:p", {}, [
- beginXml,
- hyperlinkInstrText,
- separateXml,
- beginXml,
- authorInstrText,
- separateXml,
- endXml,
- hyperlinkRunXml,
- endXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- 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,
- beginXml,
- authorInstrText,
- separateXml,
- runOfText("John Doe"),
- endXml,
- endXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- href: uri,
- children: contains(
- isText("John Doe")
- )
- }),
- isEmptyHyperlinkedRun,
- isEmptyRun
- ));
- },
- "field without separate w:fldChar is ignored": function() {
- var hyperlinkRunXml = runOfText("this is a hyperlink");
- var paragraphXml = new XmlElement("w:p", {}, [
- beginXml,
- hyperlinkInstrText,
- separateXml,
- beginXml,
- endXml,
- hyperlinkRunXml,
- endXml
- ]);
- var paragraph = readXmlElementValue(paragraphXml);
- assertThat(paragraph.children, contains(
- isEmptyRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isEmptyHyperlinkedRun,
- isHyperlinkedRun({
- href: uri,
- children: contains(
- isText("this is a hyperlink")
- )
- }),
- isEmptyRun
- ));
- }
- };
- })());
- test("run has no style if it has no properties", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.styleId, null);
- });
- test("run has style ID and name read from run properties if present", function() {
- var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
- var runXml = runWithProperties([runStyleXml]);
- var styles = new Styles({}, {"Heading1Char": {name: "Heading 1 Char"}});
- var run = readXmlElementValue(runXml, {styles: styles});
- assert.deepEqual(run.styleId, "Heading1Char");
- assert.deepEqual(run.styleName, "Heading 1 Char");
- });
- test("warning is emitted when run style cannot be found", function() {
- var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
- var runXml = runWithProperties([runStyleXml]);
- var styles = new Styles({}, {});
- var result = readXmlElement(runXml, {styles: styles});
- var run = result.value;
- assert.deepEqual(run.styleId, "Heading1Char");
- assert.deepEqual(run.styleName, null);
- assert.deepEqual(result.messages, [warning("Run style with ID Heading1Char was referenced but not defined in the document")]);
- });
- test("isBold is false if bold element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isBold, false);
- });
- test("isBold is true if bold element is present", function() {
- var boldXml = new XmlElement("w:b");
- var runXml = runWithProperties([boldXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isBold, true);
- });
- test("isBold is false if bold element is present and w:val is false", function() {
- var boldXml = new XmlElement("w:b", {"w:val": "false"});
- var runXml = runWithProperties([boldXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isBold, false);
- });
- test("isUnderline is false if underline element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isUnderline, false);
- });
- test("isUnderline is false if underline element is present without w:val attribute", function() {
- var underlineXml = new XmlElement("w:u");
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, false);
- });
- test("isUnderline is false if underline element is present and w:val is false", function() {
- var underlineXml = new XmlElement("w:u", {"w:val": "false"});
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, false);
- });
- test("isUnderline is false if underline element is present and w:val is 0", function() {
- var underlineXml = new XmlElement("w:u", {"w:val": "0"});
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, false);
- });
- test("isUnderline is false if underline element is present and w:val is none", function() {
- var underlineXml = new XmlElement("w:u", {"w:val": "none"});
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, false);
- });
- test("isUnderline is true if underline element is present and w:val is not none or falsy", function() {
- var underlineXml = new XmlElement("w:u", {"w:val": "single"});
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, true);
- });
- test("isStrikethrough is false if strikethrough element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isStrikethrough, false);
- });
- test("isStrikethrough is true if strikethrough element is present", function() {
- var strikethroughXml = new XmlElement("w:strike");
- var runXml = runWithProperties([strikethroughXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isStrikethrough, true);
- });
- test("isItalic is false if bold element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isItalic, false);
- });
- test("isItalic is true if bold element is present", function() {
- var italicXml = new XmlElement("w:i");
- var runXml = runWithProperties([italicXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isItalic, true);
- });
- test("isSmallCaps is false if smallcaps element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isSmallCaps, false);
- });
- test("isSmallCaps is true if smallcaps element is present", function() {
- var smallCapsXml = new XmlElement("w:smallCaps");
- var runXml = runWithProperties([smallCapsXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isSmallCaps, true);
- });
- var booleanRunProperties = [
- {name: "isBold", tagName: "w:b"},
- {name: "isUnderline", tagName: "w:u"},
- {name: "isItalic", tagName: "w:i"},
- {name: "isStrikethrough", tagName: "w:strike"},
- {name: "isAllCaps", tagName: "w:caps"},
- {name: "isSmallCaps", tagName: "w:smallCaps"}
- ];
- booleanRunProperties.forEach(function(runProperty) {
- test(runProperty.name + " is false if " + runProperty.tagName + " is present and w:val is false", function() {
- var propertyXml = new XmlElement(runProperty.tagName, {"w:val": "false"});
- var runXml = runWithProperties([propertyXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run[runProperty.name], false);
- });
- test(runProperty.name + " is false if " + runProperty.tagName + " is present and w:val is 0", function() {
- var propertyXml = new XmlElement(runProperty.tagName, {"w:val": "0"});
- var runXml = runWithProperties([propertyXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run[runProperty.name], false);
- });
- test(runProperty.name + " is true if " + runProperty.tagName + " is present and w:val is true", function() {
- var propertyXml = new XmlElement(runProperty.tagName, {"w:val": "true"});
- var runXml = runWithProperties([propertyXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run[runProperty.name], true);
- });
- test(runProperty.name + " is true if " + runProperty.tagName + " is present and w:val is 1", function() {
- var propertyXml = new XmlElement(runProperty.tagName, {"w:val": "1"});
- var runXml = runWithProperties([propertyXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run[runProperty.name], true);
- });
- });
- test("run has baseline vertical alignment by default", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.baseline);
- });
- test("run has vertical alignment read from properties", function() {
- var verticalAlignmentXml = new XmlElement("w:vertAlign", {"w:val": "superscript"});
- var runXml = runWithProperties([verticalAlignmentXml]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.superscript);
- });
- test("run has null font by default", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.font, null);
- });
- test("run has font read from properties", function() {
- var fontXml = new XmlElement("w:rFonts", {"w:ascii": "Arial"});
- var runXml = runWithProperties([fontXml]);
- var run = readXmlElementValue(runXml);
- 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 with invalid w:sz has null font size", function() {
- var fontSizeXml = new XmlElement("w:sz", {"w:val": "28a"});
- var runXml = runWithProperties([fontSizeXml]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.fontSize, null);
- });
- test("run has no highlight by default", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.highlight, null);
- });
- test("run has highlight read from properties", function() {
- var highlightXml = new XmlElement("w:highlight", {"w:val": "yellow"});
- var runXml = runWithProperties([highlightXml]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.highlight, "yellow");
- });
- test("when highlight is none then run has no highlight", function() {
- var highlightXml = new XmlElement("w:highlight", {"w:val": "none"});
- var runXml = runWithProperties([highlightXml]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.highlight, null);
- });
- test("run properties not included as child of run", function() {
- var runStyleXml = new XmlElement("w:rStyle");
- var runPropertiesXml = new XmlElement("w:rPr", {}, [runStyleXml]);
- var runXml = new XmlElement("w:r", {}, [runPropertiesXml]);
- var result = readXmlElement(runXml);
- assert.deepEqual(result.value.children, []);
- });
- test("w:tab is read as document tab element", function() {
- var tabXml = new XmlElement("w:tab");
- var result = readXmlElement(tabXml);
- assert.deepEqual(result.value, new documents.Tab());
- });
- test("w:noBreakHyphen is read as non-breaking hyphen character", function() {
- var noBreakHyphenXml = new XmlElement("w:noBreakHyphen");
- var result = readXmlElement(noBreakHyphenXml);
- assert.deepEqual(result.value, new documents.Text("\u2011"));
- });
- test("soft hyphens are read as text", function() {
- var element = new XmlElement("w:softHyphen", {}, []);
- var text = readXmlElementValue(element);
- assert.deepEqual(text, new documents.Text("\u00AD"));
- });
- test("w:sym with supported font and supported code point in ASCII range is converted to text", function() {
- var element = new XmlElement("w:sym", {"w:font": "Wingdings", "w:char": "28"}, []);
- var text = readXmlElementValue(element);
- assert.deepEqual(text, new documents.Text("🕿"));
- });
- test("w:sym with supported font and supported code point in private use area is converted to text", function() {
- var element = new XmlElement("w:sym", {"w:font": "Wingdings", "w:char": "F028"}, []);
- var text = readXmlElementValue(element);
- assert.deepEqual(text, new documents.Text("🕿"));
- });
- test("w:sym with unsupported font and code point produces empty result with warning", function() {
- var element = new XmlElement("w:sym", {"w:font": "Dingwings", "w:char": "28"}, []);
- var result = readXmlElement(element);
- assert.deepEqual(result.value, []);
- assert.deepEqual(result.messages, [warning("A w:sym element with an unsupported character was ignored: char 28 in font Dingwings")]);
- });
- test("w:tbl is read as document table element", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:tr", {}, [
- new XmlElement("w:tc", {}, [
- new XmlElement("w:p", {}, [])
- ])
- ])
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- new documents.TableRow([
- new documents.TableCell([
- new documents.Paragraph([])
- ])
- ])
- ]));
- });
- test("table has no style if it has no properties", function() {
- var tableXml = new XmlElement("w:tbl", {}, []);
- var table = readXmlElementValue(tableXml);
- assert.deepEqual(table.styleId, null);
- });
- test("table has style ID and name read from table properties if present", function() {
- var styleXml = new XmlElement("w:tblStyle", {"w:val": "TableNormal"}, []);
- var propertiesXml = new XmlElement("w:tblPr", {}, [styleXml]);
- var tableXml = new XmlElement("w:tbl", {}, [propertiesXml]);
- var styles = new Styles({}, {}, {"TableNormal": {name: "Normal Table"}});
- var table = readXmlElementValue(tableXml, {styles: styles});
- assert.deepEqual(table.styleId, "TableNormal");
- assert.deepEqual(table.styleName, "Normal Table");
- });
- test("warning is emitted when table style cannot be found", function() {
- var styleXml = new XmlElement("w:tblStyle", {"w:val": "TableNormal"}, []);
- var propertiesXml = new XmlElement("w:tblPr", {}, [styleXml]);
- var tableXml = new XmlElement("w:tbl", {}, [propertiesXml]);
- var result = readXmlElement(tableXml, {styles: Styles.EMPTY});
- var table = result.value;
- assert.deepEqual(table.styleId, "TableNormal");
- assert.deepEqual(table.styleName, null);
- assert.deepEqual(result.messages, [warning("Table style with ID TableNormal was referenced but not defined in the document")]);
- });
- test("w:tblHeader marks table row as header", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:tr", {}, [
- new XmlElement("w:trPr", {}, [
- new XmlElement("w:tblHeader")
- ])
- ]),
- new XmlElement("w:tr")
- ]);
- var result = readXmlElementValue(tableXml);
- assertThat(result, isTable({
- children: contains(
- isRow({isHeader: true}),
- isRow({isHeader: false})
- )
- }));
- });
- test("w:gridSpan is read as colSpan for table cell", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:tr", {}, [
- new XmlElement("w:tc", {}, [
- new XmlElement("w:tcPr", {}, [
- new XmlElement("w:gridSpan", {"w:val": "2"})
- ]),
- new XmlElement("w:p", {}, [])
- ])
- ])
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- new documents.TableRow([
- new documents.TableCell([
- new documents.Paragraph([])
- ], {colSpan: 2})
- ])
- ]));
- });
- test("w:vMerge is read as rowSpan for table cell", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell()),
- row(emptyCell(vMerge("restart"))),
- row(emptyCell(vMerge("continue"))),
- row(emptyCell(vMerge("continue"))),
- row(emptyCell())
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell()]),
- docRow([docEmptyCell({rowSpan: 3})]),
- docRow([]),
- docRow([]),
- docRow([docEmptyCell()])
- ]));
- });
- test("w:vMerge without val is treated as continue", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(vMerge("restart"))),
- row(emptyCell(vMerge()))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell({rowSpan: 2})]),
- docRow([])
- ]));
- });
- test("w:vMerge accounts for cells spanning columns", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(), emptyCell(), emptyCell(vMerge("restart"))),
- row(emptyCell(gridSpan("2")), emptyCell(vMerge("continue"))),
- row(emptyCell(), emptyCell(), emptyCell(vMerge("continue"))),
- row(emptyCell(), emptyCell(), emptyCell())
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell(), docEmptyCell(), docEmptyCell({rowSpan: 3})]),
- docRow([docEmptyCell({colSpan: 2})]),
- docRow([docEmptyCell(), docEmptyCell()]),
- docRow([docEmptyCell(), docEmptyCell(), docEmptyCell()])
- ]));
- });
- test("no vertical cell merging if merged cells do not line up", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(gridSpan("2"), vMerge("restart"))),
- row(emptyCell(), emptyCell(vMerge("continue")))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell({colSpan: 2})]),
- docRow([docEmptyCell(), docEmptyCell()])
- ]));
- });
- test("warning if non-row in table", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:p")
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.messages, [warning("unexpected non-row element in table, cell merging may be incorrect")]);
- });
- test("warning if non-cell in table row", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(new XmlElement("w:p"))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.messages, [warning("unexpected non-cell element in table row, cell merging may be incorrect")]);
- });
- function row() {
- return new XmlElement("w:tr", {}, Array.prototype.slice.call(arguments));
- }
- function emptyCell() {
- return new XmlElement("w:tc", {}, [
- new XmlElement("w:tcPr", {}, Array.prototype.slice.call(arguments))
- ]);
- }
- function vMerge(val) {
- return new XmlElement("w:vMerge", {"w:val": val}, []);
- }
- function gridSpan(val) {
- return new XmlElement("w:gridSpan", {"w:val": val});
- }
- function docRow(children) {
- return new documents.TableRow(children);
- }
- function docEmptyCell(properties) {
- return new documents.TableCell([], properties);
- }
- test("w:bookmarkStart is read as a bookmarkStart", function() {
- var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_Peter", "w:id": "42"});
- var result = readXmlElement(bookmarkStart);
- assert.deepEqual(result.value.name, "_Peter");
- assert.deepEqual(result.value.type, "bookmarkStart");
- });
- test('_GoBack bookmark is ignored', function() {
- var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_GoBack"});
- var result = readXmlElement(bookmarkStart);
- assert.deepEqual(result.value, []);
- });
- var IMAGE_BUFFER = new Buffer("Not an image at all!");
- var IMAGE_RELATIONSHIP_ID = "rId5";
- function isSuccess(valueMatcher) {
- return hasProperties({
- messages: [],
- value: valueMatcher
- });
- }
- function isImage(options) {
- var matcher = hasProperties(_.extend({type: "image"}, _.omit(options, "buffer")));
- if (options.buffer) {
- return allOf(
- matcher,
- new FeatureMatcher(willBe(options.buffer), "buffer", "buffer", function(element) {
- return element.read();
- })
- );
- } else {
- return matcher;
- }
- }
- function readEmbeddedImage(element) {
- return readXmlElement(element, {
- relationships: new Relationships([
- imageRelationship("rId5", "media/hat.png")
- ]),
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.png": IMAGE_BUFFER
- })
- });
- }
- test("can read imagedata elements with r:id attribute", function() {
- var imagedataElement = new XmlElement("v:imagedata", {
- "r:id": IMAGE_RELATIONSHIP_ID,
- "o:title": "It's a hat"
- });
- var result = readEmbeddedImage(imagedataElement);
- return promiseThat(result, isSuccess(isImage({
- altText: "It's a hat",
- contentType: "image/png",
- buffer: IMAGE_BUFFER
- })));
- });
- test("when v:imagedata element has no relationship ID then it is ignored with warning", function() {
- var imagedataElement = new XmlElement("v:imagedata");
- var result = readXmlElement(imagedataElement);
- assert.deepEqual(result.value, []);
- assert.deepEqual(result.messages, [warning("A v:imagedata element without a relationship ID was ignored")]);
- });
- test("can read inline pictures", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip(IMAGE_RELATIONSHIP_ID),
- description: "It's a hat"
- });
- var result = readEmbeddedImage(drawing);
- return promiseThat(result, isSuccess(contains(isImage({
- altText: "It's a hat",
- contentType: "image/png",
- buffer: IMAGE_BUFFER
- }))));
- });
- test("alt text title is used if alt text description is missing", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip(IMAGE_RELATIONSHIP_ID),
- title: "It's a hat"
- });
- var result = readEmbeddedImage(drawing);
- return promiseThat(result, isSuccess(contains(isImage({
- altText: "It's a hat"
- }))));
- });
- test("alt text title is used if alt text description is blank", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip(IMAGE_RELATIONSHIP_ID),
- description: " ",
- title: "It's a hat"
- });
- var result = readEmbeddedImage(drawing);
- return promiseThat(result, isSuccess(contains(isImage({
- altText: "It's a hat"
- }))));
- });
- test("alt text description is preferred to alt text title", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip(IMAGE_RELATIONSHIP_ID),
- description: "It's a hat",
- title: "hat"
- });
- var result = readEmbeddedImage(drawing);
- return promiseThat(result, isSuccess(contains(isImage({
- altText: "It's a hat"
- }))));
- });
- test("can read anchored pictures", function() {
- var drawing = new XmlElement("w:drawing", {}, [
- new XmlElement("wp:anchor", {}, [
- new XmlElement("wp:docPr", {descr: "It's a hat"}),
- new XmlElement("a:graphic", {}, [
- new XmlElement("a:graphicData", {}, [
- new XmlElement("pic:pic", {}, [
- new XmlElement("pic:blipFill", {}, [
- new XmlElement("a:blip", {"r:embed": IMAGE_RELATIONSHIP_ID})
- ])
- ])
- ])
- ])
- ])
- ]);
- var result = readEmbeddedImage(drawing);
- return promiseThat(result, isSuccess(contains(isImage({
- altText: "It's a hat",
- contentType: "image/png",
- buffer: IMAGE_BUFFER
- }))));
- });
- test("can read linked pictures", function() {
- var drawing = createInlineImage({
- blip: createLinkedBlip("rId5"),
- description: "It's a hat"
- });
- var element = single(readXmlElementValue(drawing, {
- relationships: new Relationships([
- imageRelationship("rId5", "file:///media/hat.png")
- ]),
- contentTypes: fakeContentTypes,
- files: testing.createFakeFiles({
- "file:///media/hat.png": IMAGE_BUFFER
- })
- }));
- return promiseThat(element, isImage({
- altText: "It's a hat",
- contentType: "image/png",
- buffer: IMAGE_BUFFER
- }));
- });
- test("warning if blip has no image file", function() {
- var drawing = createInlineImage({
- blip: new XmlElement("a:blip"),
- description: "It's a hat"
- });
- var result = readXmlElement(drawing);
- assert.deepEqual(result.messages, [warning("Could not find image file for a:blip element")]);
- assert.deepEqual(result.value, []);
- });
- test("warning if unsupported image type", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip("rId5"),
- description: "It's a hat"
- });
- var result = readXmlElement(drawing, {
- relationships: new Relationships([
- imageRelationship("rId5", "media/hat.emf")
- ]),
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.emf": IMAGE_BUFFER
- })
- });
- assert.deepEqual(result.messages, [warning("Image of type image/x-emf is unlikely to display in web browsers")]);
- var element = single(result.value);
- assert.equal(element.contentType, "image/x-emf");
- });
- test("no elements created if image cannot be found in w:drawing", function() {
- var drawing = new XmlElement("w:drawing", {}, []);
- var result = readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- assert.deepEqual(result.value, []);
- });
- test("no elements created if image cannot be found in wp:inline", function() {
- var drawing = new XmlElement("wp:inline", {}, []);
- var result = readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- assert.deepEqual(result.value, []);
- });
- test("children of w:ins are converted normally", function() {
- assertChildrenAreConvertedNormally("w:ins");
- });
- test("children of w:object are converted normally", function() {
- assertChildrenAreConvertedNormally("w:object");
- });
- test("children of w:smartTag are converted normally", function() {
- assertChildrenAreConvertedNormally("w:smartTag");
- });
- test("children of v:group are converted normally", function() {
- assertChildrenAreConvertedNormally("v:group");
- });
- test("children of v:rect are converted normally", function() {
- assertChildrenAreConvertedNormally("v:rect");
- });
- function assertChildrenAreConvertedNormally(tagName) {
- var runXml = new XmlElement("w:r", {}, []);
- var result = readXmlElement(new XmlElement(tagName, {}, [runXml]));
- assert.deepEqual(result.value[0].type, "run");
- }
- test("w:hyperlink", {
- "is read as external hyperlink if it has a relationship ID": function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42"}, [runXml]);
- var relationships = new Relationships([
- hyperlinkRelationship("r42", "http://example.com")
- ]);
- var result = readXmlElement(hyperlinkXml, {relationships: relationships});
- assert.deepEqual(result.value.href, "http://example.com");
- assert.deepEqual(result.value.children[0].type, "run");
- },
- "is read as external hyperlink if it has a relationship ID and an anchor": function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [runXml]);
- var relationships = new Relationships([
- hyperlinkRelationship("r42", "http://example.com/")
- ]);
- var result = readXmlElement(hyperlinkXml, {relationships: relationships});
- assert.deepEqual(result.value.href, "http://example.com/#fragment");
- assert.deepEqual(result.value.children[0].type, "run");
- },
- "existing fragment is replaced when anchor is set on external link": function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [runXml]);
- var relationships = new Relationships([
- hyperlinkRelationship("r42", "http://example.com/#previous")
- ]);
- var result = readXmlElement(hyperlinkXml, {relationships: relationships});
- assert.deepEqual(result.value.href, "http://example.com/#fragment");
- assert.deepEqual(result.value.children[0].type, "run");
- },
- "is read as internal hyperlink if it has an anchor": function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"w:anchor": "_Peter"}, [runXml]);
- var result = readXmlElement(hyperlinkXml);
- assert.deepEqual(result.value.anchor, "_Peter");
- assert.deepEqual(result.value.children[0].type, "run");
- },
- "is ignored if it does not have a relationship ID nor anchor": function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {}, [runXml]);
- var result = readXmlElement(hyperlinkXml);
- assert.deepEqual(result.value[0].type, "run");
- },
- "target frame is read": function() {
- var hyperlinkXml = new XmlElement("w:hyperlink", {
- "w:anchor": "Introduction",
- "w:tgtFrame": "_blank"
- });
- var result = readXmlElementValue(hyperlinkXml);
- assertThat(result, hasProperties({targetFrame: "_blank"}));
- },
- "empty target frame is ignored": function() {
- var hyperlinkXml = new XmlElement("w:hyperlink", {
- "w:anchor": "Introduction",
- "w:tgtFrame": ""
- });
- var result = readXmlElementValue(hyperlinkXml);
- assertThat(result, hasProperties({targetFrame: null}));
- }
- });
- test("w:br without explicit type is read as line break", function() {
- var breakXml = new XmlElement("w:br", {}, []);
- var result = readXmlElementValue(breakXml);
- assert.deepEqual(result, documents.lineBreak);
- });
- test("w:br with textWrapping type is read as line break", function() {
- var breakXml = new XmlElement("w:br", {"w:type": "textWrapping"}, []);
- var result = readXmlElementValue(breakXml);
- assert.deepEqual(result, documents.lineBreak);
- });
- test("w:br with page type is read as page break", function() {
- var breakXml = new XmlElement("w:br", {"w:type": "page"}, []);
- var result = readXmlElementValue(breakXml);
- assert.deepEqual(result, documents.pageBreak);
- });
- test("w:br with column type is read as column break", function() {
- var breakXml = new XmlElement("w:br", {"w:type": "column"}, []);
- var result = readXmlElementValue(breakXml);
- assert.deepEqual(result, documents.columnBreak);
- });
- test("warning on breaks that aren't recognised", function() {
- var breakXml = new XmlElement("w:br", {"w:type": "unknownBreakType"}, []);
- var result = readXmlElement(breakXml);
- assert.deepEqual(result.value, []);
- assert.deepEqual(result.messages, [warning("Unsupported break type: unknownBreakType")]);
- });
- test("w:footnoteReference has ID read", function() {
- var referenceXml = new XmlElement("w:footnoteReference", {"w:id": "4"});
- var result = readXmlElement(referenceXml);
- assert.deepEqual(
- result.value,
- documents.noteReference({noteType: "footnote", noteId: "4"})
- );
- assert.deepEqual(result.messages, []);
- });
- test("w:commentReference has ID read", function() {
- var referenceXml = new XmlElement("w:commentReference", {"w:id": "4"});
- var result = readXmlElement(referenceXml);
- assert.deepEqual(
- result.value,
- documents.commentReference({commentId: "4"})
- );
- assert.deepEqual(result.messages, []);
- });
- test("emits warning on unrecognised element", function() {
- var unrecognisedElement = new XmlElement("w:not-an-element");
- var result = readXmlElement(unrecognisedElement);
- assert.deepEqual(
- result.messages,
- [{
- type: "warning",
- message: "An unrecognised element was ignored: w:not-an-element"
- }]
- );
- assert.deepEqual(result.value, []);
- });
- test("w:bookmarkEnd is ignored without warning", function() {
- var ignoredElement = new XmlElement("w:bookmarkEnd");
- var result = readXmlElement(ignoredElement);
- assert.deepEqual(result.messages, []);
- assert.deepEqual([], result.value);
- });
- test("text boxes have content appended after containing paragraph", function() {
- var textbox = new XmlElement("w:pict", {}, [
- new XmlElement("v:shape", {}, [
- new XmlElement("v:textbox", {}, [
- new XmlElement("w:txbxContent", {}, [
- paragraphWithStyleId("textbox-content")
- ])
- ])
- ])
- ]);
- var paragraph = new XmlElement("w:p", {}, [
- new XmlElement("w:r", {}, [textbox])
- ]);
- var result = readXmlElement(paragraph);
- assert.deepEqual(result.value[1].styleId, "textbox-content");
- });
- test("mc:Fallback is used when mc:AlternateContent is read", function() {
- var styles = new Styles({"first": {name: "First"}, "second": {name: "Second"}}, {});
- var textbox = new XmlElement("mc:AlternateContent", {}, [
- new XmlElement("mc:Choice", {"Requires": "wps"}, [
- paragraphWithStyleId("first")
- ]),
- new XmlElement("mc:Fallback", {}, [
- paragraphWithStyleId("second")
- ])
- ]);
- var result = readXmlElement(textbox, {styles: styles});
- assert.deepEqual(result.value[0].styleId, "second");
- });
- test("w:sdtContent is used when w:sdt is read", function() {
- var element = xml.element("w:sdt", {}, [
- xml.element("w:sdtContent", {}, [
- xml.element("w:t", {}, [xml.text("Blackdown")])
- ])
- ]);
- var result = readXmlElement(element);
- assert.deepEqual(result.value, [new documents.Text("Blackdown")]);
- });
- test("text nodes are ignored when reading children", function() {
- var runXml = new XmlElement("w:r", {}, [xml.text("[text]")]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run, new documents.Run([]));
- });
- function paragraphWithStyleId(styleId) {
- return new XmlElement("w:p", {}, [
- new XmlElement("w:pPr", {}, [
- new XmlElement("w:pStyle", {"w:val": styleId}, [])
- ])
- ]);
- }
- function runWithProperties(children) {
- return new XmlElement("w:r", {}, [createRunPropertiesXml(children)]);
- }
- function createRunPropertiesXml(children) {
- return new XmlElement("w:rPr", {}, children);
- }
- function single(array) {
- if (array.length === 1) {
- return array[0];
- } else {
- throw new Error("Array has " + array.length + " elements");
- }
- }
- function createInlineImage(options) {
- return new XmlElement("w:drawing", {}, [
- new XmlElement("wp:inline", {}, [
- new XmlElement("wp:docPr", {descr: options.description, title: options.title}),
- new XmlElement("a:graphic", {}, [
- new XmlElement("a:graphicData", {}, [
- new XmlElement("pic:pic", {}, [
- new XmlElement("pic:blipFill", {}, [
- options.blip
- ])
- ])
- ])
- ])
- ])
- ]);
- }
- function createEmbeddedBlip(relationshipId) {
- return new XmlElement("a:blip", {"r:embed": relationshipId});
- }
- function createLinkedBlip(relationshipId) {
- return new XmlElement("a:blip", {"r:link": relationshipId});
- }
- function runOfText(text) {
- var textXml = new XmlElement("w:t", {}, [xml.text(text)]);
- return new XmlElement("w:r", {}, [textXml]);
- }
- function hyperlinkRelationship(relationshipId, target) {
- return {
- relationshipId: relationshipId,
- target: target,
- type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
- };
- }
- function imageRelationship(relationshipId, target) {
- return {
- relationshipId: relationshipId,
- target: target,
- type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
- };
- }
- function NumberingMap(options) {
- var findLevel = options.findLevel;
- var findLevelByParagraphStyleId = options.findLevelByParagraphStyleId || {};
- return {
- findLevel: function(numId, level) {
- return findLevel[numId][level];
- },
- findLevelByParagraphStyleId: function(styleId) {
- return findLevelByParagraphStyleId[styleId];
- }
- };
- }
|