diff options
| author | Michael Williamson <mike@zwobble.org> | 2020-11-05 19:35:33 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2020-11-05 19:35:33 +0000 |
| commit | f7cfac642bf63fac77c99d4cc30601ded8b2c107 (patch) | |
| tree | 771fee9fc5c43e54f94a4f6bb7475edec50cda8e | |
| parent | e832f604e34d344d996f8101023b6272085f934c (diff) | |
Add style mapping for all caps
| -rw-r--r-- | NEWS | 4 | ||||
| -rw-r--r-- | README.md | 11 | ||||
| -rw-r--r-- | lib/document-to-html.js | 3 | ||||
| -rw-r--r-- | lib/documents.js | 1 | ||||
| -rw-r--r-- | lib/docx/body-reader.js | 1 | ||||
| -rw-r--r-- | lib/style-reader.js | 28 | ||||
| -rw-r--r-- | lib/styles/document-matchers.js | 1 | ||||
| -rw-r--r-- | test/document-to-html.tests.js | 24 | ||||
| -rw-r--r-- | test/docx/body-reader.tests.js | 1 | ||||
| -rw-r--r-- | test/style-reader.tests.js | 57 |
10 files changed, 93 insertions, 38 deletions
@@ -1,3 +1,7 @@ +# 1.4.14 + +* Add style mapping for all caps. + # 1.4.13 * Use package-lock.json instead of npm-shrinkwrap.json. @@ -726,6 +726,17 @@ strike Note that this matches text that has had strikethrough explicitly applied to it. It will not match any text that is struckthrough because of its paragraph or run style. +#### All caps + +Match explicitly all caps text: + +``` +all-caps +``` + +Note that this matches text that has had all caps explicitly applied to it. +It will not match any text that is all caps because of its paragraph or run style. + #### Small caps Match explicitly small caps text: diff --git a/lib/document-to-html.js b/lib/document-to-html.js index 2267933..32e8b03 100644 --- a/lib/document-to-html.js +++ b/lib/document-to-html.js @@ -130,6 +130,9 @@ function DocumentConversion(options, comments) { if (run.isSmallCaps) { paths.push(findHtmlPathForRunProperty("smallCaps")); } + if (run.isAllCaps) { + paths.push(findHtmlPathForRunProperty("allCaps")); + } if (run.isStrikethrough) { paths.push(findHtmlPathForRunProperty("strikethrough", "s")); } diff --git a/lib/documents.js b/lib/documents.js index df48beb..edc9b7c 100644 --- a/lib/documents.js +++ b/lib/documents.js @@ -59,6 +59,7 @@ function Run(children, properties) { isUnderline: properties.isUnderline, isItalic: properties.isItalic, isStrikethrough: properties.isStrikethrough, + isAllCaps: properties.isAllCaps, isSmallCaps: properties.isSmallCaps, verticalAlignment: properties.verticalAlignment || verticalAlignment.baseline, font: properties.font || null, diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js index ad4f409..77f194b 100644 --- a/lib/docx/body-reader.js +++ b/lib/docx/body-reader.js @@ -73,6 +73,7 @@ function BodyReader(options) { isUnderline: readUnderline(element.first("w:u")), isItalic: readBooleanElement(element.first("w:i")), isStrikethrough: readBooleanElement(element.first("w:strike")), + isAllCaps: readBooleanElement(element.first("w:caps")), isSmallCaps: readBooleanElement(element.first("w:smallCaps")) }; }); diff --git a/lib/style-reader.js b/lib/style-reader.js index f686b28..07521ad 100644 --- a/lib/style-reader.js +++ b/lib/style-reader.js @@ -39,7 +39,7 @@ function readDocumentMatcher(string) { function documentMatcherRule() { var sequence = lop.rules.sequence; - + var identifierToConstant = function(identifier, constant) { return lop.rules.then( lop.rules.token("identifier", identifier), @@ -48,15 +48,15 @@ function documentMatcherRule() { } ); }; - + var paragraphRule = identifierToConstant("p", documentMatchers.paragraph); var runRule = identifierToConstant("r", documentMatchers.run); - + var elementTypeRule = lop.rules.firstOf("p or r or table", paragraphRule, runRule ); - + var styleIdRule = lop.rules.then( classRule, function(styleId) { @@ -86,7 +86,7 @@ function documentMatcherRule() { } ) ); - + var styleNameRule = lop.rules.sequence( lop.rules.tokenOfType("open-square-bracket"), lop.rules.sequence.cut(), @@ -95,7 +95,7 @@ function documentMatcherRule() { lop.rules.tokenOfType("close-square-bracket") ).head(); - + var listTypeRule = lop.rules.firstOf("list type", identifierToConstant("ordered-list", {isOrdered: true}), identifierToConstant("unordered-list", {isOrdered: false}) @@ -130,7 +130,7 @@ function documentMatcherRule() { return matcherOptions; }); } - + var paragraphOrRun = sequence( sequence.capture(elementTypeRule), sequence.capture(createMatcherSuffixesRule([ @@ -141,7 +141,7 @@ function documentMatcherRule() { ).map(function(createMatcher, matcherOptions) { return createMatcher(matcherOptions); }); - + var table = sequence( lop.rules.token("identifier", "table"), sequence.capture(createMatcherSuffixesRule([ @@ -156,9 +156,10 @@ function documentMatcherRule() { var italic = identifierToConstant("i", documentMatchers.italic); var underline = identifierToConstant("u", documentMatchers.underline); var strikethrough = identifierToConstant("strike", documentMatchers.strikethrough); + var allCaps = identifierToConstant("all-caps", documentMatchers.allCaps); var smallCaps = identifierToConstant("small-caps", documentMatchers.smallCaps); var commentReference = identifierToConstant("comment-reference", documentMatchers.commentReference); - + var breakMatcher = sequence( lop.rules.token("identifier", "br"), sequence.cut(), @@ -187,6 +188,7 @@ function documentMatcherRule() { italic, underline, strikethrough, + allCaps, smallCaps, commentReference, breakMatcher @@ -211,7 +213,7 @@ function htmlPathRule() { }).valueOrElse(false); } ); - + var separatorRule = lop.rules.then( lop.rules.optional(lop.rules.sequence( lop.rules.tokenOfType("colon"), @@ -229,7 +231,7 @@ function htmlPathRule() { identifierRule, lop.rules.tokenOfType("choice") ); - + var styleElementRule = lop.rules.sequence( capture(tagNamesRule), capture(lop.rules.zeroOrMore(classRule)), @@ -249,7 +251,7 @@ function htmlPathRule() { } return htmlPaths.element(tagName, attributes, options); }); - + return lop.rules.firstOf("html path", lop.rules.then(lop.rules.tokenOfType("bang"), function() { return htmlPaths.ignore; @@ -267,7 +269,7 @@ function htmlPathRule() { ) ); } - + var identifierRule = lop.rules.then( lop.rules.tokenOfType("identifier"), decodeEscapeSequences diff --git a/lib/styles/document-matchers.js b/lib/styles/document-matchers.js index 11b577f..005e2db 100644 --- a/lib/styles/document-matchers.js +++ b/lib/styles/document-matchers.js @@ -5,6 +5,7 @@ exports.bold = new Matcher("bold"); exports.italic = new Matcher("italic"); exports.underline = new Matcher("underline"); exports.strikethrough = new Matcher("strikethrough"); +exports.allCaps = new Matcher("allCaps"); exports.smallCaps = new Matcher("smallCaps"); exports.commentReference = new Matcher("commentReference"); exports.lineBreak = new Matcher("break", {breakType: "line"}); diff --git a/test/document-to-html.tests.js b/test/document-to-html.tests.js index 6e61d45..4283e86 100644 --- a/test/document-to-html.tests.js +++ b/test/document-to-html.tests.js @@ -296,6 +296,30 @@ test('subscript runs are wrapped in <sub> tags', function() { }); }); +test('all caps runs are ignored by default', function() { + var run = runOfText("Hello.", {isAllCaps: true}); + var converter = new DocumentConverter(); + return converter.convertToHtml(run).then(function(result) { + assert.equal(result.value, "Hello."); + }); +}); + +test('all caps runs can be configured with style mapping', function() { + var run = runOfText("Hello.", {isAllCaps: true}); + var converter = new DocumentConverter({ + styleMap: [ + { + from: documentMatchers.allCaps, + to: htmlPaths.elements([htmlPaths.element("span")]) + } + ] + }); + return converter.convertToHtml(run).then(function(result) { + assert.equal(result.value, "<span>Hello.</span>"); + }); +}); + + test('small caps runs are ignored by default', function() { var run = runOfText("Hello.", {isSmallCaps: true}); var converter = new DocumentConverter(); diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js index 62ae12f..adb32f8 100644 --- a/test/docx/body-reader.tests.js +++ b/test/docx/body-reader.tests.js @@ -531,6 +531,7 @@ var booleanRunProperties = [ {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"} ]; diff --git a/test/style-reader.tests.js b/test/style-reader.tests.js index 7b37f25..b77ce7e 100644 --- a/test/style-reader.tests.js +++ b/test/style-reader.tests.js @@ -15,11 +15,11 @@ test('styleReader.readHtmlPath', { 'reads empty path': function() { assertHtmlPath("", htmlPaths.empty); }, - + 'reads single element': function() { assertHtmlPath("p", htmlPaths.elements(["p"])); }, - + 'reads choice of elements': function() { assertHtmlPath( "ul|ol", @@ -28,18 +28,18 @@ test('styleReader.readHtmlPath', { ]) ); }, - + 'reads nested elements': function() { assertHtmlPath("ul > li", htmlPaths.elements(["ul", "li"])); }, - + 'reads class on element': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {"class": "tip"}) ]); assertHtmlPath("p.tip", expected); }, - + 'reads class with escaped colon': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {"class": "a:b"}) @@ -53,21 +53,21 @@ test('styleReader.readHtmlPath', { ]); assertHtmlPath("p.tip.help", expected); }, - + 'reads when element must be fresh': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {}, {"fresh": true}) ]); assertHtmlPath("p:fresh", expected); }, - + 'reads separator for elements': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {}, {separator: "x"}) ]); assertHtmlPath("p:separator('x')", expected); }, - + 'reads separator with escape sequence': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {}, {separator: "\r\n\t\'\\"}) @@ -88,21 +88,21 @@ test("styleReader.readDocumentMatcher", { "reads plain paragraph": function() { assertDocumentMatcher("p", documentMatchers.paragraph()); }, - + "reads paragraph with style ID": function() { assertDocumentMatcher( "p.Heading1", documentMatchers.paragraph({styleId: "Heading1"}) ); }, - + "reads paragraph with exact style name": function() { assertDocumentMatcher( "p[style-name='Heading 1']", documentMatchers.paragraph({styleName: documentMatchers.equalTo("Heading 1")}) ); }, - + "reads paragraph with style name prefix": function() { assertDocumentMatcher( "p[style-name^='Heading']", @@ -116,14 +116,14 @@ test("styleReader.readDocumentMatcher", { documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}}) ); }, - + "reads p:unordered-list(1) as unordered list with index of 0": function() { assertDocumentMatcher( "p:unordered-list(1)", documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 0}}) ); }, - + "reads plain run": function() { assertDocumentMatcher( "r", @@ -152,36 +152,43 @@ test("styleReader.readDocumentMatcher", { }) ); }, - + "reads bold": function() { assertDocumentMatcher( "b", documentMatchers.bold ); }, - + "reads italic": function() { assertDocumentMatcher( "i", documentMatchers.italic ); }, - + "reads underline": function() { assertDocumentMatcher( "u", documentMatchers.underline ); }, - + "reads strikethrough": function() { assertDocumentMatcher( "strike", documentMatchers.strikethrough ); }, - - "reads smallcaps": function() { + + "reads all-caps": function() { + assertDocumentMatcher( + "all-caps", + documentMatchers.allCaps + ); + }, + + "reads small-caps": function() { assertDocumentMatcher( "small-caps", documentMatchers.smallCaps @@ -194,21 +201,21 @@ test("styleReader.readDocumentMatcher", { documentMatchers.commentReference ); }, - + "reads line breaks": function() { assertDocumentMatcher( "br[type='line']", documentMatchers.lineBreak ); }, - + "reads page breaks": function() { assertDocumentMatcher( "br[type='page']", documentMatchers.pageBreak ); }, - + "reads column breaks": function() { assertDocumentMatcher( "br[type='column']", @@ -217,7 +224,7 @@ test("styleReader.readDocumentMatcher", { } }); - + function assertDocumentMatcher(input, expected) { assert.deepEqual(readDocumentMatcher(input), results.success(expected)); } @@ -232,7 +239,7 @@ test("styleReader.read", { } ); }, - + "reads style mapping with no HTML path": function() { assertStyleMapping( "r =>", @@ -242,7 +249,7 @@ test("styleReader.read", { } ); }, - + "error when not all input is consumed": function() { assert.deepEqual( readStyle("r => span a"), |
