diff options
author | bptato <nincsnevem662@gmail.com> | 2021-11-23 13:01:23 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-11-23 13:01:23 +0100 |
commit | 30f3b5deb3be13683e73175f241600c028910eaa (patch) | |
tree | 8524e4451cbf7ef4f8850f9b74f9df8bfd839ac0 /src/css | |
parent | ff1b68086d699510dcdbea6051460926556bd401 (diff) | |
download | chawan-30f3b5deb3be13683e73175f241600c028910eaa.tar.gz |
Support CSS child combinators
Diffstat (limited to 'src/css')
-rw-r--r-- | src/css/selector.nim | 49 | ||||
-rw-r--r-- | src/css/style.nim | 33 |
2 files changed, 56 insertions, 26 deletions
diff --git a/src/css/selector.nim b/src/css/selector.nim index 97c7d695..8489f240 100644 --- a/src/css/selector.nim +++ b/src/css/selector.nim @@ -12,13 +12,13 @@ type QueryMode* = enum QUERY_TYPE, QUERY_CLASS, QUERY_ATTR, QUERY_DELIM, QUERY_VALUE, - QUERY_PSEUDO, QUERY_PSELEM, QUERY_COMBINATOR + QUERY_PSEUDO, QUERY_PSELEM, QUERY_DESC_COMBINATOR, QUERY_CHILD_COMBINATOR PseudoElem* = enum PSEUDO_NONE, PSEUDO_BEFORE, PSEUDO_AFTER CombinatorType* = enum - DESCENDANT_COMBINATOR + DESCENDANT_COMBINATOR, CHILD_COMBINATOR SelectorParser = object selectors: seq[SelectorList] @@ -86,10 +86,8 @@ func getSpecificity(sel: Selector): int = of UNIVERSAL_SELECTOR: discard of COMBINATOR_SELECTOR: - case sel.ct - of DESCENDANT_COMBINATOR: - for child in sel.csels: - result += getSpecificity(child) + for child in sel.csels: + result += getSpecificity(child) func getSpecificity*(sels: SelectorList): int = for sel in sels.sels: @@ -135,17 +133,31 @@ proc addSelectorList(state: var SelectorParser) = state.combinator = nil state.selectors.add(SelectorList()) +proc parseSelectorCombinator(state: var SelectorParser, ct: CombinatorType, csstoken: CSSToken) = + if csstoken.tokenType in {CSS_IDENT_TOKEN, CSS_HASH_TOKEN, + CSS_COLON_TOKEN}: + if state.combinator != nil and state.combinator.ct != ct: + let nc = Selector(t: COMBINATOR_SELECTOR, ct: ct) + nc.csels.add(SelectorList()) + nc.csels[^1].add(state.combinator) + state.combinator = nc + + if state.combinator == nil: + state.combinator = Selector(t: COMBINATOR_SELECTOR, ct: ct) + + state.combinator.csels.add(state.selectors[^1]) + if state.combinator.csels[^1].len > 0: + state.combinator.csels.add(SelectorList()) + state.selectors[^1] = SelectorList() + state.query = QUERY_TYPE + proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = - if state.query == QUERY_COMBINATOR: - if csstoken.tokenType in {CSS_IDENT_TOKEN, CSS_HASH_TOKEN, - CSS_COLON_TOKEN}: - if state.combinator == nil: - state.combinator = Selector(t: COMBINATOR_SELECTOR, ct: DESCENDANT_COMBINATOR) - state.combinator.csels.add(state.selectors[^1]) - if state.combinator.csels[^1].len > 0: - state.combinator.csels.add(SelectorList()) - state.selectors[^1] = SelectorList() - state.query = QUERY_TYPE + if state.query == QUERY_DESC_COMBINATOR: + state.parseSelectorCombinator(DESCENDANT_COMBINATOR, csstoken) + elif state.query == QUERY_CHILD_COMBINATOR: + if csstoken.tokenType == CSS_WHITESPACE_TOKEN: + return + state.parseSelectorCombinator(CHILD_COMBINATOR, csstoken) case csstoken.tokenType of CSS_IDENT_TOKEN: @@ -163,6 +175,9 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = of CSS_DELIM_TOKEN: if csstoken.rvalue == Rune('.'): state.query = QUERY_CLASS + elif csstoken.rvalue == Rune('>'): + if state.selectors[^1].len > 0 or state.combinator != nil: + state.query = QUERY_CHILD_COMBINATOR of CSS_HASH_TOKEN: state.addSelector(Selector(t: ID_SELECTOR, id: $csstoken.value)) of CSS_COMMA_TOKEN: @@ -170,7 +185,7 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = state.addSelectorList() of CSS_WHITESPACE_TOKEN: if state.selectors[^1].len > 0 or state.combinator != nil: - state.query = QUERY_COMBINATOR + state.query = QUERY_DESC_COMBINATOR of CSS_COLON_TOKEN: if state.query == QUERY_PSEUDO: state.query = QUERY_PSELEM diff --git a/src/css/style.nim b/src/css/style.nim index 897c1652..d42b8e25 100644 --- a/src/css/style.nim +++ b/src/css/style.nim @@ -71,26 +71,42 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = of FUNC_SELECTOR: return selectres(false) of COMBINATOR_SELECTOR: + #combinator without at least two members makes no sense + assert sel.csels.len > 1 case sel.ct of DESCENDANT_COMBINATOR: - #combinator without at least two members makes no sense - assert sel.csels.len > 1 - if elem.selectorsMatch(sel.csels[^1]).success: + let match = elem.selectorsMatch(sel.csels[^1]) + if match.success: var i = sel.csels.len - 2 var e = elem.parentElement - var pseudo = PSEUDO_NONE while e != nil and e != elem.ownerDocument.root and i >= 0: let res = e.selectorsMatch(sel.csels[i]) if res.pseudo != PSEUDO_NONE: - if pseudo != PSEUDO_NONE: - return selectres(false) - pseudo = res.pseudo + return selectres(false) if res.success: dec i e = e.parentElement - return selectres(i == -1, pseudo) + 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 + var e = elem.parentElement + while e != nil and e != elem.ownerDocument.root and i >= 0: + let res = e.selectorsMatch(sel.csels[i]) + + if res.pseudo != PSEUDO_NONE: + return selectres(false) + + if not res.success: + return selectres(false) + dec i + e = e.parentElement + return selectres(i == -1, match.pseudo) else: return selectres(false) @@ -129,7 +145,6 @@ func selectElems(document: Document, sel: Selector): seq[Element] = return document.all_elements.filter((elem) => selectorsMatch(elem, sel.fsels).psuccess) return newSeq[Element]() of COMBINATOR_SELECTOR: - #TODO return document.all_elements.filter((elem) => selectorMatches(elem, sel)) func selectElems(document: Document, selectors: SelectorList): seq[Element] = |