Skip to content

Commit 6d48aa5

Browse files
committed
fix: Lookups for previous / next siblings
Ref: #324
1 parent 066d294 commit 6d48aa5

File tree

6 files changed

+106
-8
lines changed

6 files changed

+106
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
- Replace `attohttpc` with `reqwest` to simplify implementing non-blocking stylesheet resolving in the future release.
1212

13+
### Fixed
14+
15+
- Lookups for previous / next siblings, affecting selectors like `nth-child`. [#324](https://github.com/Stranger6667/css-inline/issues/324)
16+
1317
### Performance
1418

1519
- Avoid using binary search on attributes.

bindings/javascript/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Fixed
6+
7+
- Lookups for previous / next siblings, affecting selectors like `nth-child`. [#324](https://github.com/Stranger6667/css-inline/issues/324)
8+
59
### Performance
610

711
- Avoid using binary search on attributes.

bindings/python/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Fixed
6+
7+
- Lookups for previous / next siblings, affecting selectors like `nth-child`. [#324](https://github.com/Stranger6667/css-inline/issues/324)
8+
59
### Performance
610

711
- Avoid using binary search on attributes.

bindings/ruby/CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Fixed
6+
7+
- Lookups for previous / next siblings, affecting selectors like `nth-child`. [#324](https://github.com/Stranger6667/css-inline/issues/324)
8+
39
### Performance
410

511
- Avoid using binary search on attributes.
612

7-
## [Unreleased]
8-
913
## [0.12.0] - 2023-12-28
1014

1115
### Changed

css-inline/src/html/element.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,34 @@ impl<'a> Element<'a> {
6363
.and_then(|node_id| self.document.as_element(node_id))
6464
}
6565
fn previous_sibling_element(&self) -> Option<Element<'a>> {
66-
self.document[self.node_id]
67-
.previous_sibling
68-
.and_then(|node_id| self.document.as_element(node_id))
66+
let mut node = &self.document[self.node_id];
67+
loop {
68+
if let Some(previous_sibling_id) = node.previous_sibling {
69+
let previous_sibling = &self.document[previous_sibling_id];
70+
if let NodeData::Element { element, .. } = &previous_sibling.data {
71+
return Some(Element::new(self.document, previous_sibling_id, element));
72+
}
73+
node = previous_sibling;
74+
} else {
75+
// Node has no previous sibling at all
76+
return None;
77+
}
78+
}
6979
}
7080
fn next_sibling_element(&self) -> Option<Element<'a>> {
71-
self.document[self.node_id]
72-
.next_sibling
73-
.and_then(|node_id| self.document.as_element(node_id))
81+
let mut node = &self.document[self.node_id];
82+
loop {
83+
if let Some(next_sibling_id) = node.next_sibling {
84+
let next_sibling = &self.document[next_sibling_id];
85+
if let NodeData::Element { element, .. } = &next_sibling.data {
86+
return Some(Element::new(self.document, next_sibling_id, element));
87+
}
88+
node = next_sibling;
89+
} else {
90+
// Node has no next sibling at all
91+
return None;
92+
}
93+
}
7494
}
7595
pub(crate) fn matches(&self, selector: &Selector, cache: &mut NthIndexCache) -> bool {
7696
let mut context = matching::MatchingContext::new(

css-inline/tests/test_inlining.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,3 +835,65 @@ fn keep_link_tags() {
835835
"<html><head>\n<link href=\"external.css\" rel=\"stylesheet\">\n</head>\n<body>\n<h1 style=\"color: blue;\"></h1>\n\n</body></html>",
836836
);
837837
}
838+
839+
#[test]
840+
fn nth_child_selector() {
841+
let html = r#"
842+
<html>
843+
<head>
844+
<style>tbody tr:nth-child(odd) td {background-color:grey;}</style>
845+
</head>
846+
<body>
847+
<table>
848+
<tbody>
849+
<tr>
850+
<td>Test</td>
851+
<td>Test</td>
852+
</tr>
853+
<tr>
854+
<td>Test</td>
855+
<td>Test</td>
856+
</tr>
857+
<tr>
858+
<td>Test</td>
859+
<td>Test</td>
860+
</tr>
861+
<tr>
862+
<td>Test</td>
863+
<td>Test</td>
864+
</tr>
865+
</tbody>
866+
</table>
867+
</body>
868+
</html>"#;
869+
let inlined = inline(html).expect("Failed to inline");
870+
assert_eq!(
871+
inlined,
872+
r#"<html><head>
873+
874+
</head>
875+
<body>
876+
<table>
877+
<tbody>
878+
<tr>
879+
<td style="background-color: grey;">Test</td>
880+
<td style="background-color: grey;">Test</td>
881+
</tr>
882+
<tr>
883+
<td>Test</td>
884+
<td>Test</td>
885+
</tr>
886+
<tr>
887+
<td style="background-color: grey;">Test</td>
888+
<td style="background-color: grey;">Test</td>
889+
</tr>
890+
<tr>
891+
<td>Test</td>
892+
<td>Test</td>
893+
</tr>
894+
</tbody>
895+
</table>
896+
897+
</body></html>"#
898+
);
899+
}

0 commit comments

Comments
 (0)