mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 01:36:15 -04:00
fix: Prevent class selector from doing substring match
Previously, "aa" would have matched "baaa". Now the matching is strict equality on tokenized words.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
<div class="nested">nested2</div>
|
||||
</div>
|
||||
|
||||
<div class="baaa">overlap1</div>
|
||||
|
||||
<script>
|
||||
const foos = document.getElementsByClassName('foo');
|
||||
</script>
|
||||
@@ -96,3 +98,10 @@
|
||||
testing.expectEqual('nested1', nested[0].textContent);
|
||||
testing.expectEqual('nested2', nested[1].textContent);
|
||||
</script>
|
||||
|
||||
<script id=overlappingSubstring>
|
||||
// "baaa" is a single class token; "aa" is a substring of it but not its own
|
||||
// token, so it must not match.
|
||||
const overlap = document.getElementsByClassName('aa');
|
||||
testing.expectEqual(0, overlap.length);
|
||||
</script>
|
||||
|
||||
@@ -187,37 +187,23 @@ pub fn classAttributeContains(class_attr: []const u8, class_name: []const u8) bo
|
||||
}
|
||||
|
||||
pub fn classAttributeContainsCase(class_attr: []const u8, class_name: []const u8, case_insensitive: bool) bool {
|
||||
if (class_name.len == 0 or class_name.len > class_attr.len) {
|
||||
if (class_name.len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var search = class_attr;
|
||||
while (true) {
|
||||
const pos = (if (case_insensitive)
|
||||
std.ascii.indexOfIgnoreCase(search, class_name)
|
||||
else
|
||||
std.mem.indexOf(u8, search, class_name)) orelse break;
|
||||
|
||||
const is_start = pos == 0 or isClassWhitespace(search[pos - 1]);
|
||||
const end = pos + class_name.len;
|
||||
const is_end = end == search.len or isClassWhitespace(search[end]);
|
||||
|
||||
if (is_start and is_end) return true;
|
||||
|
||||
search = search[pos + 1 ..];
|
||||
var it = std.mem.tokenizeAny(u8, class_attr, &[_]u8{ '\t', '\n', 0x0C, '\r', ' ' });
|
||||
while (it.next()) |token| {
|
||||
if (case_insensitive) {
|
||||
if (std.ascii.eqlIgnoreCase(token, class_name)) {
|
||||
return true;
|
||||
}
|
||||
} else if (std.mem.eql(u8, token, class_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The class attribute tokens are separated by ASCII whitespace (which,
|
||||
// unlike std.ascii.isWhitespace, does not include vertical tab).
|
||||
fn isClassWhitespace(c: u8) bool {
|
||||
return switch (c) {
|
||||
'\t', '\n', 0x0C, '\r', ' ' => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Part = union(enum) {
|
||||
id: []const u8,
|
||||
class: []const u8,
|
||||
|
||||
Reference in New Issue
Block a user