diff options
| author | Michael Williamson <mike@zwobble.org> | 2024-02-17 13:36:21 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2024-02-17 13:36:21 +0000 |
| commit | 2ab691683d81b1481f68d19295f6ba86f02fdd3a (patch) | |
| tree | d903cda7ea366883a727eb521eecb02a9587a873 | |
| parent | 318145ae7e4cdc02e418f25032159fa40cd47a19 (diff) | |
Support attributes in HTML paths in style mappings
| -rw-r--r-- | NEWS | 4 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | lib/style-reader.js | 48 | ||||
| -rw-r--r-- | test/style-reader.tests.js | 14 |
4 files changed, 60 insertions, 12 deletions
@@ -1,3 +1,7 @@ +# 1.7.0 + +* Support attributes in HTML paths in style mappings. + # 1.6.0 * Add transformDocument to the TypeScript declarations. @@ -805,6 +805,12 @@ append a dot followed by the name of the class: h1.section-title ``` +To add an attribute, use square brackets similarly to a CSS attribute selector: + +``` +p[lang="fr"] +``` + To require that an element is fresh, use `:fresh`: ``` diff --git a/lib/style-reader.js b/lib/style-reader.js index 07521ad..38202f9 100644 --- a/lib/style-reader.js +++ b/lib/style-reader.js @@ -57,12 +57,13 @@ function documentMatcherRule() { runRule ); - var styleIdRule = lop.rules.then( - classRule, - function(styleId) { - return {styleId: styleId}; - } - ); + var styleIdRule = lop.rules.sequence( + lop.rules.tokenOfType("dot"), + lop.rules.sequence.cut(), + lop.rules.sequence.capture(identifierRule) + ).map(function(styleId) { + return {styleId: styleId}; + }); var styleNameMatcherRule = lop.rules.firstOf("style name matcher", lop.rules.then( @@ -234,15 +235,19 @@ function htmlPathRule() { var styleElementRule = lop.rules.sequence( capture(tagNamesRule), - capture(lop.rules.zeroOrMore(classRule)), + capture(lop.rules.zeroOrMore(attributeOrClassRule)), capture(freshRule), capture(separatorRule) - ).map(function(tagName, classNames, fresh, separator) { + ).map(function(tagName, attributesList, fresh, separator) { var attributes = {}; var options = {}; - if (classNames.length > 0) { - attributes["class"] = classNames.join(" "); - } + attributesList.forEach(function(attribute) { + if (attribute.append && attributes[attribute.name]) { + attributes[attribute.name] += " " + attribute.value; + } else { + attributes[attribute.name] = attribute.value; + } + }); if (fresh) { options.fresh = true; } @@ -293,11 +298,30 @@ function decodeEscapeSequences(value) { }); } +var attributeRule = lop.rules.sequence( + lop.rules.tokenOfType("open-square-bracket"), + lop.rules.sequence.cut(), + lop.rules.sequence.capture(identifierRule), + lop.rules.tokenOfType("equals"), + lop.rules.sequence.capture(stringRule), + lop.rules.tokenOfType("close-square-bracket") +).map(function(name, value) { + return {name: name, value: value, append: false}; +}); + var classRule = lop.rules.sequence( lop.rules.tokenOfType("dot"), lop.rules.sequence.cut(), lop.rules.sequence.capture(identifierRule) -).head(); +).map(function(className) { + return {name: "class", value: className, append: true}; +}); + +var attributeOrClassRule = lop.rules.firstOf( + "attribute or class", + attributeRule, + classRule +); function parseString(rule, string) { var tokens = tokenise(string); diff --git a/test/style-reader.tests.js b/test/style-reader.tests.js index b77ce7e..93ddc79 100644 --- a/test/style-reader.tests.js +++ b/test/style-reader.tests.js @@ -54,6 +54,20 @@ test('styleReader.readHtmlPath', { assertHtmlPath("p.tip.help", expected); }, + 'reads attribute on element': function() { + var expected = htmlPaths.elements([ + htmlPaths.element("p", {"lang": "fr"}) + ]); + assertHtmlPath("p[lang='fr']", expected); + }, + + 'reads multiple attributes on element': function() { + var expected = htmlPaths.elements([ + htmlPaths.element("p", {"lang": "fr", "data-x": "y"}) + ]); + assertHtmlPath("p[lang='fr'][data-x='y']", expected); + }, + 'reads when element must be fresh': function() { var expected = htmlPaths.elements([ htmlPaths.element("p", {}, {"fresh": true}) |
