mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:38:11 +00:00
LibHTML: Add adjacent (+) and general (~) sibling combinators
This patch implements two more selector features: - "div + p" matches the <p> sibling immediately after a <div>. - "div ~ p" matches all <p> siblings after a <div>.
This commit is contained in:
parent
5a6c36dc91
commit
bedb00603c
5 changed files with 53 additions and 2 deletions
|
@ -15,6 +15,11 @@ div > .boo > .bee {
|
|||
background-color: #000000;
|
||||
color: #ff00ff;
|
||||
}
|
||||
#gen_sib ~ div,
|
||||
#adj_sib + div {
|
||||
background-color: #0000ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -45,5 +50,16 @@ div > .boo > .bee {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div id="gen_sib">All the siblings of this <div> should be blue.</div>
|
||||
<div>First sibling (should be blue)</div>
|
||||
<div>Second sibling (should be blue)</div>
|
||||
</div>
|
||||
<div>
|
||||
<div id="adj_sib">The first sibling of this <div> should be blue.</div>
|
||||
<div>First sibling (should be blue)</div>
|
||||
<div>Second sibling (should not be blue)</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -19,6 +19,8 @@ public:
|
|||
None,
|
||||
ImmediateChild,
|
||||
Descendant,
|
||||
AdjacentSibling,
|
||||
GeneralSibling,
|
||||
};
|
||||
Relation relation { Relation::None };
|
||||
|
||||
|
|
|
@ -51,6 +51,18 @@ static bool matches(const Selector& selector, int component_index, const Element
|
|||
if (!element.parent() || !element.parent()->is_element())
|
||||
return false;
|
||||
return matches(selector, component_index - 1, static_cast<const Element&>(*element.parent()));
|
||||
case Selector::Component::Relation::AdjacentSibling:
|
||||
ASSERT(component_index != 0);
|
||||
if (auto* sibling = element.previous_element_sibling())
|
||||
return matches(selector, component_index - 1, *sibling);
|
||||
return false;
|
||||
case Selector::Component::Relation::GeneralSibling:
|
||||
ASSERT(component_index != 0);
|
||||
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
|
||||
if (matches(selector, component_index - 1, *sibling))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -158,6 +158,12 @@ void dump_rule(const StyleRule& rule)
|
|||
case Selector::Component::Relation::Descendant:
|
||||
relation_description = "{Descendant}";
|
||||
break;
|
||||
case Selector::Component::Relation::AdjacentSibling:
|
||||
relation_description = "{AdjacentSibling}";
|
||||
break;
|
||||
case Selector::Component::Relation::GeneralSibling:
|
||||
relation_description = "{GeneralSibling}";
|
||||
break;
|
||||
}
|
||||
dbgprintf(" %s:%s %s\n", type_description, component.value.characters(), relation_description);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,11 @@ public:
|
|||
return isalnum(ch) || ch == '-' || ch == '_' || ch == '(' || ch == ')' || ch == '@';
|
||||
}
|
||||
|
||||
bool is_combinator(char ch) const
|
||||
{
|
||||
return ch == '~' || ch == '>' || ch == '+';
|
||||
}
|
||||
|
||||
Optional<Selector::Component> parse_selector_component()
|
||||
{
|
||||
consume_whitespace();
|
||||
|
@ -93,8 +98,18 @@ public:
|
|||
if (peek() == '{')
|
||||
return {};
|
||||
|
||||
if (peek() == '>') {
|
||||
if (is_combinator(peek())) {
|
||||
switch (peek()) {
|
||||
case '>':
|
||||
relation = Selector::Component::Relation::ImmediateChild;
|
||||
break;
|
||||
case '+':
|
||||
relation = Selector::Component::Relation::AdjacentSibling;
|
||||
break;
|
||||
case '~':
|
||||
relation = Selector::Component::Relation::GeneralSibling;
|
||||
break;
|
||||
}
|
||||
consume_one();
|
||||
consume_whitespace();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue