diff options
Diffstat (limited to 'src/css')
-rw-r--r-- | src/css/selector.nim | 33 | ||||
-rw-r--r-- | src/css/style.nim | 36 | ||||
-rw-r--r-- | src/css/values.nim | 42 |
3 files changed, 83 insertions, 28 deletions
diff --git a/src/css/selector.nim b/src/css/selector.nim index 7cfbf328..13131f80 100644 --- a/src/css/selector.nim +++ b/src/css/selector.nim @@ -48,7 +48,7 @@ type elem*: string of FUNC_SELECTOR: name*: string - fsels*: SelectorList + fsels*: seq[SelectorList] of COMBINATOR_SELECTOR: ct*: CombinatorType csels*: seq[SelectorList] @@ -77,13 +77,14 @@ func getSpecificity(sel: Selector): int = case sel.name of "is": var best = 0 - for child in sel.fsels.sels: + for child in sel.fsels: let s = getSpecificity(child) if s > best: best = s result += best of "not": - result += getSpecificity(sel.fsels) + for child in sel.fsels: + result += getSpecificity(child) else: discard of UNIVERSAL_SELECTOR: discard @@ -129,6 +130,12 @@ proc addSelector(state: var SelectorParser, sel: Selector) = else: state.selectors[^1].add(sel) +proc getLastSel(state: SelectorParser): Selector = + if state.combinator != nil: + return state.combinator.csels[^1].sels[^1] + else: + return state.selectors[^1].sels[^1] + proc addSelectorList(state: var SelectorParser) = if state.combinator != nil: state.selectors[^1].add(state.combinator) @@ -227,22 +234,24 @@ proc parseSelectorSimpleBlock(state: var SelectorParser, cssblock: CSSSimpleBloc state.query = QUERY_DELIM state.addSelector(Selector(t: ATTR_SELECTOR, attr: $csstoken.value, rel: ' ')) of QUERY_VALUE: - state.selectors[^1].sels[^1].value = $csstoken.value + state.getLastSel().value = $csstoken.value break else: discard of CSS_STRING_TOKEN: case state.query of QUERY_VALUE: - state.selectors[^1].sels[^1].value = $csstoken.value + state.getLastSel().value = $csstoken.value break else: discard of CSS_DELIM_TOKEN: case csstoken.rvalue of Rune('~'), Rune('|'), Rune('^'), Rune('$'), Rune('*'): if state.query == QUERY_DELIM: - state.selectors[^1].sels[^1].rel = char(csstoken.rvalue) + state.getLastSel().rel = char(csstoken.rvalue) of Rune('='): if state.query == QUERY_DELIM: + if state.getLastSel().rel == ' ': + state.getLastSel().rel = '=' state.query = QUERY_VALUE else: discard else: discard @@ -257,9 +266,13 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction) state.query = QUERY_TYPE else: return var fun = Selector(t: FUNC_SELECTOR, name: $cssfunction.name) - fun.fsels = SelectorList(parent: state.selectors[^1]) state.addSelector(fun) - state.selectors[^1] = fun.fsels + + let osels = state.selectors + let ocomb = state.combinator + state.combinator = nil + state.selectors = newSeq[SelectorList]() + state.addSelectorList() for cval in cssfunction.value: if cval of CSSToken: state.parseSelectorToken(CSSToken(cval)) @@ -267,7 +280,9 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction) state.parseSelectorSimpleBlock(CSSSimpleBlock(cval)) elif cval of CSSFunction: state.parseSelectorFunction(CSSFunction(cval)) - state.selectors[^1] = fun.fsels.parent + fun.fsels = state.selectors + state.selectors = osels + state.combinator = ocomb func parseSelectors*(cvals: seq[CSSComponentValue]): seq[SelectorList] = var state = SelectorParser() diff --git a/src/css/style.nim b/src/css/style.nim index e2bf2347..efffb8c6 100644 --- a/src/css/style.nim +++ b/src/css/style.nim @@ -53,6 +53,22 @@ func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult = func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult +func funcSelectorMatches(elem: Element, sel: Selector): SelectResult = + case sel.name + of "not": + for slist in sel.fsels: + let res = elem.selectorsMatch(slist) + if res.success: + return selectres(false) + return selectres(true) + of "is", "where": + for slist in sel.fsels: + let res = elem.selectorsMatch(slist) + if not res.success: + return selectres(false) + return selectres(true) + else: discard + func selectorMatches(elem: Element, sel: Selector): SelectResult = case sel.t of TYPE_SELECTOR: @@ -70,7 +86,7 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = of UNIVERSAL_SELECTOR: return selectres(true) of FUNC_SELECTOR: - return selectres(false) + return funcSelectorMatches(elem, sel) of COMBINATOR_SELECTOR: #combinator without at least two members makes no sense assert sel.csels.len > 1 @@ -110,7 +126,6 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = return selectres(false) if not res.success: - eprint "fail", e.tagType return selectres(false) dec i e = e.previousElementSibling @@ -157,12 +172,7 @@ func selectElems(document: Document, sel: Selector): seq[Element] = of PSELEM_SELECTOR: return document.all_elements.filter((elem) => pseudoElemSelectorMatches(elem, sel)) of FUNC_SELECTOR: - case sel.name - of "not": - return document.all_elements.filter((elem) => not selectorsMatch(elem, sel.fsels).psuccess) - of "is", "where": - return document.all_elements.filter((elem) => selectorsMatch(elem, sel.fsels).psuccess) - return newSeq[Element]() + return document.all_elements.filter((elem) => selectorMatches(elem, sel)) of COMBINATOR_SELECTOR: return document.all_elements.filter((elem) => selectorMatches(elem, sel)) @@ -173,15 +183,7 @@ func selectElems(document: Document, selectors: SelectorList): seq[Element] = var i = 1 while i < sellist.len: - if sellist[i].t == FUNC_SELECTOR: - case sellist[i].name - of "not": - result = result.filter((elem) => not selectorsMatch(elem, sellist[i].fsels).psuccess) - of "is", "where": - result = result.filter((elem) => selectorsMatch(elem, sellist[i].fsels).psuccess) - else: discard - else: - result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess) + result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess) inc i proc querySelector*(document: Document, q: string): seq[Element] = diff --git a/src/css/values.nim b/src/css/values.nim index 7d5d5bc5..b55869f7 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -39,6 +39,8 @@ type textdecoration*: CSSTextDecoration of VALUE_WORD_BREAK: wordbreak*: CSSWordBreak + of VALUE_LIST_STYLE_TYPE: + liststyletype*: CSSListStyleType of VALUE_NONE: discard CSSComputedValues* = ref array[low(CSSPropertyType)..high(CSSPropertyType), CSSComputedValue] @@ -66,6 +68,7 @@ const PropertyNames = { "word-break": PROPERTY_WORD_BREAK, "width": PROPERTY_WIDTH, "height": PROPERTY_HEIGHT, + "list-style-type": PROPERTY_LIST_STYLE_TYPE, }.toTable() const ValueTypes = [ @@ -86,11 +89,13 @@ const ValueTypes = [ PROPERTY_WORD_BREAK: VALUE_WORD_BREAK, PROPERTY_WIDTH: VALUE_LENGTH, PROPERTY_HEIGHT: VALUE_LENGTH, + PROPERTY_LIST_STYLE_TYPE: VALUE_LIST_STYLE_TYPE, ] const InheritedProperties = { PROPERTY_COLOR, PROPERTY_FONT_STYLE, PROPERTY_WHITE_SPACE, - PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK + PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK, + PROPERTY_LIST_STYLE_TYPE } func getPropInheritedArray(): array[low(CSSPropertyType)..high(CSSPropertyType), bool] = @@ -123,6 +128,15 @@ func cells*(l: CSSLength): int = #TODO return int(l.num / 8) +func listMarker*(t: CSSListStyleType, i: int): string = + case t + of LIST_STYLE_TYPE_NONE: return "" + of LIST_STYLE_TYPE_DISC: return "* " + of LIST_STYLE_TYPE_CIRCLE: return "o " + of LIST_STYLE_TYPE_SQUARE: return "O " + of LIST_STYLE_TYPE_DECIMAL: return $i & ". " + of LIST_STYLE_TYPE_JAPANESE_INFORMAL: return japaneseNumber(i) & "、" + func r(c: CSSColor): int = return c.rgba.r @@ -436,8 +450,8 @@ func cssDisplay(d: CSSDeclaration): CSSDisplay = case $tok.value of "block": return DISPLAY_BLOCK of "inline": return DISPLAY_INLINE + of "list-item": return DISPLAY_LIST_ITEM # of "inline-block": return DISPLAY_INLINE_BLOCK - # of "list-item": return DISPLAY_LIST_ITEM # of "table": return DISPLAY_TABLE # of "table-row-group": return DISPLAY_TABLE_ROW_GROUP # of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP @@ -511,6 +525,19 @@ func cssWordBreak(d: CSSDeclaration): CSSWordBreak = of "keep-all": return WORD_BREAK_KEEP_ALL raise newException(CSSValueError, "Invalid text decoration") +func cssListStyleType(d: CSSDeclaration): CSSListStyleType = + if isToken(d): + let tok = getToken(d) + if tok.tokenType == CSS_IDENT_TOKEN: + case $tok.value + of "none": return LIST_STYLE_TYPE_NONE + of "disc": return LIST_STYLE_TYPE_DISC + of "circle": return LIST_STYLE_TYPE_CIRCLE + of "square": return LIST_STYLE_TYPE_SQUARE + of "decimal": return LIST_STYLE_TYPE_DECIMAL + of "japanese-informal": return LIST_STYLE_TYPE_JAPANESE_INFORMAL + raise newException(CSSValueError, "Invalid list style") + func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue = let name = $d.name let ptype = propertyType(name) @@ -529,6 +556,7 @@ func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue = result.integer = cssFontWeight(d) of VALUE_TEXT_DECORATION: result.textdecoration = cssTextDecoration(d) of VALUE_WORD_BREAK: result.wordbreak = cssWordBreak(d) + of VALUE_LIST_STYLE_TYPE: result.liststyletype = cssListStyleType(d) of VALUE_NONE: discard except CSSValueError: result.globalValue = VALUE_UNSET @@ -611,6 +639,8 @@ func getComputedValue*(prop: CSSSpecifiedValue, current: CSSComputedValues): CSS return CSSComputedValue(t: prop.t, v: VALUE_TEXT_DECORATION, textdecoration: prop.textdecoration) of VALUE_WORD_BREAK: return CSSComputedValue(t: prop.t, v: VALUE_WORD_BREAK, wordbreak: prop.wordbreak) + of VALUE_LIST_STYLE_TYPE: + return CSSComputedValue(t: prop.t, v: VALUE_LIST_STYLE_TYPE, liststyletype: prop.liststyletype) of VALUE_NONE: return CSSComputedValue(t: prop.t, v: VALUE_NONE) func getComputedValue*(d: CSSDeclaration, current: CSSComputedValues): CSSComputedValue = @@ -629,3 +659,11 @@ proc inheritProperties*(vals: var CSSComputedValues, parent: CSSComputedValues) vals[prop] = getDefault(prop) if inherited(prop) and parent[prop] != nil and vals[prop] == getDefault(prop): vals[prop] = parent[prop] + +func inheritProperties*(parent: CSSComputedValues): CSSComputedValues = + new(result) + for prop in low(CSSPropertyType)..high(CSSPropertyType): + if inherited(prop) and parent[prop] != nil: + result[prop] = parent[prop] + else: + result[prop] = getDefault(prop) |