about summary refs log tree commit diff stats
path: root/src/html
diff options
context:
space:
mode:
Diffstat (limited to 'src/html')
-rw-r--r--src/html/dom.nim291
1 files changed, 4 insertions, 287 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index db7b9d89..7b8a14f1 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -1,15 +1,7 @@
 import uri
-import unicode
-import strutils
 import tables
-import streams
-import sequtils
-import sugar
-import algorithm
-
-import css/style
-import css/parser
-import css/selector
+
+import css/values
 import types/enums
 
 type
@@ -123,12 +115,12 @@ func lastChild(node: Node): Node =
     return nil
   return node.childNodes[^1]
 
-func firstElementChild(node: Node): Element =
+func firstElementChild*(node: Node): Element =
   if node.children.len == 0:
     return nil
   return node.children[0]
 
-func lastElementChild(node: Node): Element =
+func lastElementChild*(node: Node): Element =
   if node.children.len == 0:
     return nil
   return node.children[^1]
@@ -232,278 +224,3 @@ func getAttrValue*(element: Element, s: string): string =
   if attr != nil:
     return attr.value
   return ""
-
-#TODO case sensitivity
-
-type SelectResult = object
-  success: bool
-  pseudo: PseudoElem
-
-func selectres(s: bool, p: PseudoElem = PSEUDO_NONE): SelectResult =
-  return SelectResult(success: s, pseudo: p)
-
-func psuccess(s: SelectResult): bool =
-  return s.pseudo == PSEUDO_NONE and s.success
-
-func attrSelectorMatches(elem: Element, sel: Selector): bool =
-  case sel.rel
-  of ' ': return sel.attr in elem.attributes
-  of '=': return elem.getAttrValue(sel.attr) == sel.value
-  of '~': return sel.value in unicode.split(elem.getAttrValue(sel.attr))
-  of '|':
-    let val = elem.getAttrValue(sel.attr)
-    return val == sel.value or sel.value.startsWith(val & '-')
-  of '^': return elem.getAttrValue(sel.attr).startsWith(sel.value)
-  of '$': return elem.getAttrValue(sel.attr).endsWith(sel.value)
-  of '*': return elem.getAttrValue(sel.attr).contains(sel.value)
-  else: return false
-
-func pseudoSelectorMatches(elem: Element, sel: Selector): bool =
-  case sel.pseudo
-  of "first-child": return elem.parentNode.firstElementChild == elem
-  of "last-child": return elem.parentNode.lastElementChild == elem
-  of "hover": return elem.hover
-  else: return false
-
-func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult =
-  case sel.elem
-  of "after": return selectres(true, PSEUDO_AFTER)
-  of "before": return selectres(true, PSEUDO_AFTER)
-  else: return selectres(false)
-
-func selectorMatches(elem: Element, sel: Selector): SelectResult =
-  case sel.t
-  of TYPE_SELECTOR:
-    return selectres(elem.tagType == sel.tag)
-  of CLASS_SELECTOR:
-    return selectres(sel.class in elem.classList)
-  of ID_SELECTOR:
-    return selectres(sel.id == elem.id)
-  of ATTR_SELECTOR:
-    return selectres(elem.attrSelectorMatches(sel))
-  of PSEUDO_SELECTOR:
-    return selectres(pseudoSelectorMatches(elem, sel))
-  of PSELEM_SELECTOR:
-    return pseudoElemSelectorMatches(elem, sel)
-  of UNIVERSAL_SELECTOR:
-    return selectres(true)
-  of FUNC_SELECTOR:
-    return selectres(false)
-
-func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult =
-  for sel in selectors.sels:
-    let res = selectorMatches(elem, sel)
-    if not res.success:
-      return selectres(false)
-    if res.pseudo != PSEUDO_NONE:
-      if result.pseudo != PSEUDO_NONE:
-        return selectres(false)
-      result.pseudo = res.pseudo
-  result.success = true
-
-func selectElems(document: Document, sel: Selector): seq[Element] =
-  case sel.t
-  of TYPE_SELECTOR:
-    return document.type_elements[sel.tag]
-  of ID_SELECTOR:
-    return document.id_elements[sel.id]
-  of CLASS_SELECTOR:
-    return document.class_elements[sel.class]
-  of UNIVERSAL_SELECTOR:
-    return document.all_elements
-  of ATTR_SELECTOR:
-    return document.all_elements.filter((elem) => attrSelectorMatches(elem, sel))
-  of PSEUDO_SELECTOR:
-    return document.all_elements.filter((elem) => pseudoSelectorMatches(elem, sel))
-  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.selectors).psuccess)
-    of "is", "where":
-      return document.all_elements.filter((elem) => selectorsMatch(elem, sel.selectors).psuccess)
-    return newSeq[Element]()
-
-func selectElems(document: Document, selectors: SelectorList): seq[Element] =
-  assert(selectors.len > 0)
-  let sellist = optimizeSelectorList(selectors)
-  result = document.selectElems(selectors[0])
-  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].selectors).psuccess)
-      of "is", "where":
-        result = result.filter((elem) => selectorsMatch(elem, sellist[i].selectors).psuccess)
-      else: discard
-    else:
-      result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess)
-    inc i
-
-proc querySelector*(document: Document, q: string): seq[Element] =
-  let ss = newStringStream(q)
-  let cvals = parseCSSListOfComponentValues(ss)
-  let selectors = parseSelectors(cvals)
-
-  for sel in selectors:
-    result.add(document.selectElems(sel))
-
-proc applyProperty(elem: Element, decl: CSSDeclaration, pseudo: PseudoElem) =
-  let cval = getComputedValue(decl, elem.cssvalues)
-  case pseudo
-  of PSEUDO_NONE:
-    elem.cssvalues[cval.t] = cval
-  of PSEUDO_BEFORE:
-    elem.cssvalues_before[cval.t] = cval
-  of PSEUDO_AFTER:
-    elem.cssvalues_after[cval.t] = cval
-  elem.cssapplied = true
-
-type
-  ParsedRule* = tuple[sels: seq[SelectorList], oblock: CSSSimpleBlock]
-  ParsedStylesheet* = seq[ParsedRule]
-  ApplyResult = object
-    normal: seq[tuple[e:Element,d:CSSDeclaration,p:PseudoElem]]
-    important: seq[tuple[e:Element,d:CSSDeclaration,p:PseudoElem]]
-
-func calcRules(elem: Element, rules: ParsedStylesheet):
-    array[low(PseudoElem)..high(PseudoElem), seq[CSSSimpleBlock]] =
-  var tosorts: array[low(PseudoElem)..high(PseudoElem), seq[tuple[s:int,b:CSSSimpleBlock]]]
-  for rule in rules:
-    for sel in rule.sels:
-      let match = elem.selectorsMatch(sel)
-      if match.success:
-        let spec = getSpecificity(sel)
-        tosorts[match.pseudo].add((spec,rule.oblock))
-
-  for i in low(PseudoElem)..high(PseudoElem):
-    tosorts[i].sort((x, y) => cmp(x.s,y.s))
-    result[i] = tosorts[i].map((x) => x.b)
-
-proc applyRules*(document: Document, pss: ParsedStylesheet, reset: bool = false): ApplyResult =
-  var stack: seq[Element]
-
-  stack.add(document.head)
-  stack.add(document.body)
-  document.root.cssvalues.rootProperties()
-
-  while stack.len > 0:
-    let elem = stack.pop()
-    if not elem.cssapplied:
-      if reset:
-        elem.cssvalues.rootProperties()
-      let rules_pseudo = calcRules(elem, pss)
-      for pseudo in low(PseudoElem)..high(PseudoElem):
-        let rules = rules_pseudo[pseudo]
-        for rule in rules:
-          let decls = parseCSSListOfDeclarations(rule.value)
-          for item in decls:
-            if item of CSSDeclaration:
-              let decl = CSSDeclaration(item)
-              if decl.important:
-                result.important.add((elem, decl, pseudo))
-              else:
-                result.normal.add((elem, decl, pseudo))
-
-    var i = elem.children.len - 1
-    while i >= 0:
-      let child = elem.children[i]
-      stack.add(child)
-      dec i
-
-proc applyAuthorRules*(document: Document): ApplyResult =
-  var stack: seq[Element]
-  var embedded_rules: seq[ParsedStylesheet]
-
-  stack.add(document.head)
-  var rules_head = ""
-
-  for child in document.head.children:
-    if child.tagType == TAG_STYLE:
-      for ct in child.childNodes:
-        if ct.nodeType == TEXT_NODE:
-          rules_head &= Text(ct).data
-
-  stack.setLen(0)
-
-  stack.add(document.body)
-
-  if rules_head.len > 0:
-    let parsed = parseCSS(newStringStream(rules_head)).value.map((x) => (sels: parseSelectors(x.prelude), oblock: x.oblock))
-    embedded_rules.add(parsed)
-
-  while stack.len > 0:
-    let elem = stack.pop()
-    var rules_local = ""
-    for child in elem.children:
-      if child.tagType == TAG_STYLE:
-        for ct in child.childNodes:
-          if ct.nodeType == TEXT_NODE:
-            rules_local &= Text(ct).data
-
-    if rules_local.len > 0:
-      let parsed = parseCSS(newStringStream(rules_local)).value.map((x) => (sels: parseSelectors(x.prelude), oblock: x.oblock))
-      embedded_rules.add(parsed)
-
-    if not elem.cssapplied:
-      let this_rules = embedded_rules.concat()
-      let rules_pseudo = calcRules(elem, this_rules)
-
-      for pseudo in low(PseudoElem)..high(PseudoElem):
-        let rules = rules_pseudo[pseudo]
-        for rule in rules:
-          let decls = parseCSSListOfDeclarations(rule.value)
-          for item in decls:
-            if item of CSSDeclaration:
-              let decl = CSSDeclaration(item)
-              if decl.important:
-                result.important.add((elem, decl, pseudo))
-              else:
-                result.normal.add((elem, decl, pseudo))
-
-    var i = elem.children.len - 1
-    while i >= 0:
-      let child = elem.children[i]
-      stack.add(child)
-      dec i
-
-    if rules_local.len > 0:
-      discard embedded_rules.pop()
-
-proc applyStylesheets*(document: Document, uass: ParsedStylesheet, userss: ParsedStylesheet) =
-  let ua = document.applyRules(uass, true)
-  let user = document.applyRules(userss)
-  let author = document.applyAuthorRules()
-  var elems: seq[Element]
-
-  for rule in ua.normal:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-  for rule in user.normal:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-  for rule in author.normal:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-
-  for rule in author.important:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-  for rule in user.important:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-  for rule in ua.important:
-    if not rule.e.cssapplied:
-      elems.add(rule.e)
-    rule.e.applyProperty(rule.d, rule.p)
-
-  for elem in elems:
-    elem.cssvalues.inheritProperties(elem.parentElement.cssvalues)