diff --git a/dom.d b/dom.d
index 2d689b1..fd7eb0f 100644
--- a/dom.d
+++ b/dom.d
@@ -5,8 +5,6 @@
// FIXME: the scriptable list is quite arbitrary
-// FIXME: https://developer.mozilla.org/en-US/docs/Web/CSS/:is
-
// xml entity references?!
@@ -6940,6 +6938,9 @@ int intFromHex(string hex) {
string[] hasSelectors; /// :has(this)
string[] notSelectors; /// :not(this)
+ string[] isSelectors; /// :is(this)
+ string[] whereSelectors; /// :where(this)
+
ParsedNth[] nthOfType; /// .
ParsedNth[] nthLastOfType; /// .
ParsedNth[] nthChild; /// .
@@ -6990,6 +6991,9 @@ int intFromHex(string hex) {
foreach(a; notSelectors) ret ~= ":not(" ~ a ~ ")";
foreach(a; hasSelectors) ret ~= ":has(" ~ a ~ ")";
+ foreach(a; isSelectors) ret ~= ":is(" ~ a ~ ")";
+ foreach(a; whereSelectors) ret ~= ":where(" ~ a ~ ")";
+
foreach(a; nthChild) ret ~= ":nth-child(" ~ a.toString ~ ")";
foreach(a; nthOfType) ret ~= ":nth-of-type(" ~ a.toString ~ ")";
foreach(a; nthLastOfType) ret ~= ":nth-last-of-type(" ~ a.toString ~ ")";
@@ -7128,6 +7132,16 @@ int intFromHex(string hex) {
if(sel.matchesElement(e))
return false;
}
+ foreach(a; isSelectors) {
+ auto sel = Selector(a);
+ if(!sel.matchesElement(e))
+ return false;
+ }
+ foreach(a; whereSelectors) {
+ auto sel = Selector(a);
+ if(!sel.matchesElement(e))
+ return false;
+ }
foreach(a; nthChild) {
if(e.parentNode is null)
@@ -7548,9 +7562,14 @@ int intFromHex(string hex) {
SelectorComponent[] ret;
auto tokens = lexSelector(selector); // this will parse commas too
// and now do comma-separated slices (i haz phobosophobia!)
+ int parensCount = 0;
while (tokens.length > 0) {
size_t end = 0;
- while (end < tokens.length && tokens[end] != ",") ++end;
+ while (end < tokens.length && (parensCount > 0 || tokens[end] != ",")) {
+ if(tokens[end] == "(") parensCount++;
+ if(tokens[end] == ")") parensCount--;
+ ++end;
+ }
if (end > 0) ret ~= parseSelector(tokens[0..end], caseSensitiveTags);
if (tokens.length-end < 2) break;
tokens = tokens[end+1..$];
@@ -7744,6 +7763,14 @@ int intFromHex(string hex) {
current.nthLastOfType ~= ParsedNth(readFunctionalSelector());
state = State.SkippingFunctionalSelector;
continue;
+ case "is":
+ state = State.SkippingFunctionalSelector;
+ current.isSelectors ~= readFunctionalSelector();
+ continue; // now the rest of the parser skips past the parens we just handled
+ case "where":
+ state = State.SkippingFunctionalSelector;
+ current.whereSelectors ~= readFunctionalSelector();
+ continue; // now the rest of the parser skips past the parens we just handled
case "not":
state = State.SkippingFunctionalSelector;
current.notSelectors ~= readFunctionalSelector();
@@ -7763,10 +7790,6 @@ int intFromHex(string hex) {
case "visited", "active", "hover", "target", "focus", "selected":
current.attributesPresent ~= "nothing";
// FIXME
- /*
- // defined in the standard, but I don't implement it
- case "not":
- */
/+
// extensions not implemented
//case "text": // takes the text in the element and wraps it in an element, returning it
@@ -8768,6 +8791,17 @@ unittest {
assert(el.closest("p, div") is el);
}
+unittest {
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/:is
+ auto document = new Document(`
+
+ two
+ `);
+
+ assert(document.querySelectorAll(":is(.foo, main) p").length == 2);
+ assert(document.querySelector("div:where(.foo)") !is null);
+}
+
/*
Copyright: Adam D. Ruppe, 2010 - 2020
License: Boost License 1.0.