Skip to content

Commit

Permalink
Support style mapping for highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
mwilliamson committed Jun 13, 2024
1 parent 700e395 commit 66c9ef9
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 1 deletion.
2 changes: 1 addition & 1 deletion NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 1.8.0

* Support parsing of run highlights.
* Add style mapping for highlights.

# 1.7.2

Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,43 @@ small-caps
Note that this matches text that has had small caps explicitly applied to it.
It will not match any text that is small caps because of its paragraph or run style.

#### Highlight

Match explicitly highlighted text:

```
highlight
```

Note that this matches text that has had a highlight explicitly applied to it.
It will not match any text that is highlighted because of its paragraph or run style.

It's also possible to match specific colours.
For instance, to match yellow highlights:

```
highlight[color='yellow']
```

The set of colours typically used are:

* `black`
* `blue`
* `cyan`
* `green`
* `magenta`
* `red`
* `yellow`
* `white`
* `darkBlue`
* `darkCyan`
* `darkGreen`
* `darkMagenta`
* `darkRed`
* `darkYellow`
* `darkGray`
* `lightGray`

#### Ignoring document elements

Use `!` to ignore a document element.
Expand Down
6 changes: 6 additions & 0 deletions lib/document-to-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ function DocumentConversion(options, comments) {
return convertElements(run.children, messages, options);
};
var paths = [];
if (run.highlight !== null) {
var path = findHtmlPath({type: "highlight", color: run.highlight});
if (path) {
paths.push(path);
}
}
if (run.isSmallCaps) {
paths.push(findHtmlPathForRunProperty("smallCaps"));
}
Expand Down
18 changes: 18 additions & 0 deletions lib/style-reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,23 @@ function documentMatcherRule() {
var strikethrough = identifierToConstant("strike", documentMatchers.strikethrough);
var allCaps = identifierToConstant("all-caps", documentMatchers.allCaps);
var smallCaps = identifierToConstant("small-caps", documentMatchers.smallCaps);

var highlight = sequence(
lop.rules.token("identifier", "highlight"),
lop.rules.sequence.capture(lop.rules.optional(lop.rules.sequence(
lop.rules.tokenOfType("open-square-bracket"),
lop.rules.sequence.cut(),
lop.rules.token("identifier", "color"),
lop.rules.tokenOfType("equals"),
lop.rules.sequence.capture(stringRule),
lop.rules.tokenOfType("close-square-bracket")
).head()))
).map(function(color) {
return documentMatchers.highlight({
color: color.valueOrElse(undefined)
});
});

var commentReference = identifierToConstant("comment-reference", documentMatchers.commentReference);

var breakMatcher = sequence(
Expand Down Expand Up @@ -191,6 +208,7 @@ function documentMatcherRule() {
strikethrough,
allCaps,
smallCaps,
highlight,
commentReference,
breakMatcher
);
Expand Down
15 changes: 15 additions & 0 deletions lib/styles/document-matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ exports.underline = new Matcher("underline");
exports.strikethrough = new Matcher("strikethrough");
exports.allCaps = new Matcher("allCaps");
exports.smallCaps = new Matcher("smallCaps");
exports.highlight = highlight;
exports.commentReference = new Matcher("commentReference");
exports.lineBreak = new Matcher("break", {breakType: "line"});
exports.pageBreak = new Matcher("break", {breakType: "page"});
Expand All @@ -27,6 +28,10 @@ function table(options) {
return new Matcher("table", options);
}

function highlight(options) {
return new HighlightMatcher(options);
}

function Matcher(elementType, options) {
options = options || {};
this._elementType = elementType;
Expand All @@ -46,6 +51,16 @@ Matcher.prototype.matches = function(element) {
(this._breakType === undefined || this._breakType === element.breakType);
};

function HighlightMatcher(options) {
options = options || {};
this._color = options.color;
}

HighlightMatcher.prototype.matches = function(element) {
return element.type === "highlight" &&
(this._color === undefined || element.color === this._color);
};

function isList(element, levelIndex, isOrdered) {
return element.numbering &&
element.numbering.level == levelIndex &&
Expand Down
46 changes: 46 additions & 0 deletions test/document-to-html.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,52 @@ test('small caps runs can be configured with style mapping', function() {
});


test('highlighted runs are ignored by default', function() {
var run = runOfText("Hello.", {highlight: "yellow"});
var converter = new DocumentConverter();
return converter.convertToHtml(run).then(function(result) {
assert.equal(result.value, "Hello.");
});
});

test('highlighted runs can be configured with style mapping for all highlights', function() {
var run = runOfText("Hello.", {highlight: "yellow"});
var converter = new DocumentConverter({
styleMap: [
{
from: documentMatchers.highlight(null),
to: htmlPaths.elements([htmlPaths.element("mark")])
}
]
});
return converter.convertToHtml(run).then(function(result) {
assert.equal(result.value, "<mark>Hello.</mark>");
});
});

test('highlighted runs can be configured with style mapping for specific highlight color', function() {
var paragraph = new documents.Paragraph([
runOfText("Yellow", {highlight: "yellow"}),
runOfText("Red", {highlight: "red"})
]);
var converter = new DocumentConverter({
styleMap: [
{
from: documentMatchers.highlight({color: "yellow"}),
to: htmlPaths.elements([htmlPaths.element("mark", {"class": "yellow"})])
},
{
from: documentMatchers.highlight({color: undefined}),
to: htmlPaths.elements([htmlPaths.element("mark")])
}
]
});
return converter.convertToHtml(paragraph).then(function(result) {
assert.equal(result.value, '<p><mark class="yellow">Yellow</mark><mark>Red</mark></p>');
});
});


test('run styles are converted to HTML if mapping exists', function() {
var run = runOfText("Hello.", {styleId: "Heading1Char", styleName: "Heading 1 Char"});
var converter = new DocumentConverter({
Expand Down
14 changes: 14 additions & 0 deletions test/style-reader.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ test("styleReader.readDocumentMatcher", {
);
},

"reads highlight without color": function() {
assertDocumentMatcher(
"highlight",
documentMatchers.highlight()
);
},

"reads highlight with color": function() {
assertDocumentMatcher(
"highlight[color='yellow']",
documentMatchers.highlight({color: "yellow"})
);
},

"reads comment-reference": function() {
assertDocumentMatcher(
"comment-reference",
Expand Down
20 changes: 20 additions & 0 deletions test/styles/document-matchers.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ test("matchers for lists with index 0 do not match elements that are not lists",
assert.ok(!matcher.matches(new Paragraph()));
});

test("highlight matcher does not match non-highlight elements", function() {
var matcher = documentMatchers.highlight();
assert.ok(!matcher.matches(new Paragraph()));
});

test("highlight matcher without color matches all highlight elements", function() {
var matcher = documentMatchers.highlight({});
assert.ok(matcher.matches({type: "highlight", color: "yellow"}));
});

test("highlight matcher with color matches highlight with that color", function() {
var matcher = documentMatchers.highlight({color: "yellow"});
assert.ok(matcher.matches({type: "highlight", color: "yellow"}));
});

test("highlight matcher with color does not match highlights with other colors", function() {
var matcher = documentMatchers.highlight({color: "yellow"});
assert.ok(!matcher.matches({type: "highlight", color: "red"}));
});

function paragraphWithStyle(styleId, styleName) {
return new Paragraph([], {styleId: styleId, styleName: styleName});
}
Expand Down

0 comments on commit 66c9ef9

Please sign in to comment.