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 | |
parent | 30f3b5deb3be13683e73175f241600c028910eaa (diff) | |
download | chawan-c183dd305c92304dec888cefdf1d1379415a8a86.tar.gz |
Support CSS next- and subsequent sibling combinators
Diffstat (limited to 'src')
-rw-r--r-- | src/css/selector.nim | 32 | ||||
-rw-r--r-- | src/css/style.nim | 48 | ||||
-rw-r--r-- | src/html/dom.nim | 16 | ||||
-rw-r--r-- | src/html/parser.nim | 12 |
4 files changed, 81 insertions, 27 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: diff --git a/src/html/dom.nim b/src/html/dom.nim index 7b8a14f1..1aa6c191 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -125,6 +125,22 @@ func lastElementChild*(node: Node): Element = return nil return node.children[^1] +func previousElementSibling*(elem: Element): Element = + var e = elem.previousSibling + while e != nil: + if e.nodeType == ELEMENT_NODE: + return Element(e) + e = e.previousSibling + return nil + +func nextElementSibling*(elem: Element): Element = + var e = elem.nextSibling + while e != nil: + if e.nodeType == ELEMENT_NODE: + return Element(e) + e = e.nextSibling + return nil + func `$`*(element: Element): string = return "Element of " & $element.tagType diff --git a/src/html/parser.nim b/src/html/parser.nim index 3f1ca218..0102fe17 100644 --- a/src/html/parser.nim +++ b/src/html/parser.nim @@ -166,25 +166,25 @@ proc insertNode(parent: Node, node: Node) = parent.childNodes.add(node) if parent.childNodes.len > 1: - let prevSibling = parent.childNodes[^1] + let prevSibling = parent.childNodes[^2] prevSibling.nextSibling = node node.previousSibling = prevSibling node.parentNode = parent if parent.nodeType == ELEMENT_NODE: - node.parentElement = (Element)parent + node.parentElement = Element(parent) if parent.ownerDocument != nil: node.ownerDocument = parent.ownerDocument elif parent.nodeType == DOCUMENT_NODE: - node.ownerDocument = (Document)parent + node.ownerDocument = Document(parent) if node.nodeType == ELEMENT_NODE: - parent.children.add((Element)node) + parent.children.add(Element(node)) - let element = ((Element)node) + let element = (Element(node)) if element.ownerDocument != nil: - node.ownerDocument.all_elements.add((Element)node) + node.ownerDocument.all_elements.add(Element(node)) element.ownerDocument.type_elements[element.tagType].add(element) if element.id != "": if not (element.id in element.ownerDocument.id_elements): |