diff options
author | bptato <nincsnevem662@gmail.com> | 2021-11-23 13:29:47 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-11-23 13:29:47 +0100 |
commit | c183dd305c92304dec888cefdf1d1379415a8a86 (patch) | |
tree | 94c4393c9cb7b00d685477ac4daddccaa064f00c /src/css | |
parent | 30f3b5deb3be13683e73175f241600c028910eaa (diff) | |
download | chawan-c183dd305c92304dec888cefdf1d1379415a8a86.tar.gz |
Support CSS next- and subsequent sibling combinators
Diffstat (limited to 'src/css')
-rw-r--r-- | src/css/selector.nim | 32 | ||||
-rw-r--r-- | src/css/style.nim | 48 |
2 files changed, 59 insertions, 21 deletions
diff --git a/src/css/selector.nim b/src/css/selector.nim index 8489f240..7cfbf328 100644 --- a/src/css/selector.nim +++ b/src/css/selector.nim @@ -12,13 +12,15 @@ type QueryMode* = enum QUERY_TYPE, QUERY_CLASS, QUERY_ATTR, QUERY_DELIM, QUERY_VALUE, - QUERY_PSEUDO, QUERY_PSELEM, QUERY_DESC_COMBINATOR, QUERY_CHILD_COMBINATOR + QUERY_PSEUDO, QUERY_PSELEM, QUERY_DESC_COMBINATOR, QUERY_CHILD_COMBINATOR, + QUERY_NEXT_SIBLING_COMBINATOR, QUERY_SUBSEQ_SIBLING_COMBINATOR PseudoElem* = enum PSEUDO_NONE, PSEUDO_BEFORE, PSEUDO_AFTER CombinatorType* = enum - DESCENDANT_COMBINATOR, CHILD_COMBINATOR + DESCENDANT_COMBINATOR, CHILD_COMBINATOR, NEXT_SIBLING_COMBINATOR, + SUBSEQ_SIBLING_COMBINATOR SelectorParser = object selectors: seq[SelectorList] @@ -152,12 +154,22 @@ proc parseSelectorCombinator(state: var SelectorParser, ct: CombinatorType, csst state.query = QUERY_TYPE proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = - if state.query == QUERY_DESC_COMBINATOR: + case state.query + of QUERY_DESC_COMBINATOR: state.parseSelectorCombinator(DESCENDANT_COMBINATOR, csstoken) - elif state.query == QUERY_CHILD_COMBINATOR: + of QUERY_CHILD_COMBINATOR: if csstoken.tokenType == CSS_WHITESPACE_TOKEN: return state.parseSelectorCombinator(CHILD_COMBINATOR, csstoken) + of QUERY_NEXT_SIBLING_COMBINATOR: + if csstoken.tokenType == CSS_WHITESPACE_TOKEN: + return + state.parseSelectorCombinator(NEXT_SIBLING_COMBINATOR, csstoken) + of QUERY_SUBSEQ_SIBLING_COMBINATOR: + if csstoken.tokenType == CSS_WHITESPACE_TOKEN: + return + state.parseSelectorCombinator(SUBSEQ_SIBLING_COMBINATOR, csstoken) + else: discard case csstoken.tokenType of CSS_IDENT_TOKEN: @@ -173,11 +185,19 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = else: discard state.query = QUERY_TYPE of CSS_DELIM_TOKEN: - if csstoken.rvalue == Rune('.'): + case csstoken.rvalue + of Rune('.'): state.query = QUERY_CLASS - elif csstoken.rvalue == Rune('>'): + of Rune('>'): if state.selectors[^1].len > 0 or state.combinator != nil: state.query = QUERY_CHILD_COMBINATOR + of Rune('+'): + if state.selectors[^1].len > 0 or state.combinator != nil: + state.query = QUERY_NEXT_SIBLING_COMBINATOR + of Rune('~'): + if state.selectors[^1].len > 0 or state.combinator != nil: + state.query = QUERY_SUBSEQ_SIBLING_COMBINATOR + else: discard of CSS_HASH_TOKEN: state.addSelector(Selector(t: ID_SELECTOR, id: $csstoken.value)) of CSS_COMMA_TOKEN: diff --git a/src/css/style.nim b/src/css/style.nim index d42b8e25..556fba67 100644 --- a/src/css/style.nim +++ b/src/css/style.nim @@ -73,11 +73,11 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = of COMBINATOR_SELECTOR: #combinator without at least two members makes no sense assert sel.csels.len > 1 - case sel.ct - of DESCENDANT_COMBINATOR: - let match = elem.selectorsMatch(sel.csels[^1]) - if match.success: - var i = sel.csels.len - 2 + let match = elem.selectorsMatch(sel.csels[^1]) + if match.success: + var i = sel.csels.len - 2 + case sel.ct + of DESCENDANT_COMBINATOR: var e = elem.parentElement while e != nil and e != elem.ownerDocument.root and i >= 0: let res = e.selectorsMatch(sel.csels[i]) @@ -88,13 +88,7 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = if res.success: dec i e = e.parentElement - return selectres(i == -1, match.pseudo) - else: - return selectres(false) - of CHILD_COMBINATOR: - let match = elem.selectorsMatch(sel.csels[^1]) - if match.success: - var i = sel.csels.len - 2 + of CHILD_COMBINATOR: var e = elem.parentElement while e != nil and e != elem.ownerDocument.root and i >= 0: let res = e.selectorsMatch(sel.csels[i]) @@ -106,9 +100,33 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = return selectres(false) dec i e = e.parentElement - return selectres(i == -1, match.pseudo) - else: - return selectres(false) + of NEXT_SIBLING_COMBINATOR: + var e = elem.previousElementSibling + while e != nil and i >= 0: + let res = e.selectorsMatch(sel.csels[i]) + + if res.pseudo != PSEUDO_NONE: + return selectres(false) + + if not res.success: + eprint "fail", e.tagType + return selectres(false) + dec i + e = e.previousElementSibling + of SUBSEQ_SIBLING_COMBINATOR: + var e = elem.previousElementSibling + while e != nil and i >= 0: + let res = e.selectorsMatch(sel.csels[i]) + + if res.pseudo != PSEUDO_NONE: + return selectres(false) + + if res.success: + dec i + e = e.previousElementSibling + return selectres(i == -1, match.pseudo) + else: + return selectres(false) func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult = for sel in selectors.sels: |