diff options
author | bptato <nincsnevem662@gmail.com> | 2022-07-30 21:11:52 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-07-31 09:27:05 +0200 |
commit | 8bc1392c463fbbfd99ae368b9e99dfcb97c52149 (patch) | |
tree | b6f9b49944b58204299f24f49ae25150db003322 /src | |
parent | a26dae6c0123e291352fc7d24699eb8c58193718 (diff) | |
download | chawan-8bc1392c463fbbfd99ae368b9e99dfcb97c52149.tar.gz |
Add interactive <select>
Diffstat (limited to 'src')
-rw-r--r-- | src/css/select.nim | 3 | ||||
-rw-r--r-- | src/css/selectorparser.nim | 4 | ||||
-rw-r--r-- | src/css/stylednode.nim | 8 | ||||
-rw-r--r-- | src/html/dom.nim | 19 | ||||
-rw-r--r-- | src/io/buffer.nim | 35 |
5 files changed, 62 insertions, 7 deletions
diff --git a/src/css/select.nim b/src/css/select.nim index f47df9af..0d142558 100644 --- a/src/css/select.nim +++ b/src/css/select.nim @@ -47,6 +47,9 @@ func pseudoSelectorMatches[T: Element|StyledNode](elem: T, sel: Selector, felem: elif elem.tagType == TAG_OPTION: return HTMLOptionElement(elem).selected return false + of PSEUDO_FOCUS: + when selem is StyledNode: felem.addDependency(selem, DEPEND_FOCUS) + return elem.document.focus == elem func selectorsMatch*[T: Element|StyledNode](elem: T, selectors: SelectorList, felem: T = nil): bool diff --git a/src/css/selectorparser.nim b/src/css/selectorparser.nim index 012d6e68..846aa865 100644 --- a/src/css/selectorparser.nim +++ b/src/css/selectorparser.nim @@ -21,7 +21,7 @@ type PseudoClass* = enum PSEUDO_FIRST_CHILD, PSEUDO_LAST_CHILD, PSEUDO_ONLY_CHILD, PSEUDO_HOVER, - PSEUDO_ROOT, PSEUDO_NTH_CHILD, PSEUDO_CHECKED + PSEUDO_ROOT, PSEUDO_NTH_CHILD, PSEUDO_CHECKED, PSEUDO_FOCUS CombinatorType* = enum DESCENDANT_COMBINATOR, CHILD_COMBINATOR, NEXT_SIBLING_COMBINATOR, @@ -212,6 +212,8 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) = state.addSelector(Selector(t: PSEUDO_SELECTOR, pseudo: PSEUDO_ROOT)) of "checked": state.addSelector(Selector(t: PSEUDO_SELECTOR, pseudo: PSEUDO_CHECKED)) + of "focus": + state.addSelector(Selector(t: PSEUDO_SELECTOR, pseudo: PSEUDO_FOCUS)) of QUERY_PSELEM: case csstoken.value of "before": diff --git a/src/css/stylednode.nim b/src/css/stylednode.nim index 52a13771..f75e3f66 100644 --- a/src/css/stylednode.nim +++ b/src/css/stylednode.nim @@ -39,7 +39,7 @@ type STYLED_ELEMENT, STYLED_TEXT DependencyType* = enum - DEPEND_HOVER, DEPEND_CHECKED + DEPEND_HOVER, DEPEND_CHECKED, DEPEND_FOCUS DependencyInfo* = object # All nodes we depend on, for each dependency type d. @@ -91,12 +91,18 @@ func isValid*(styledNode: StyledNode): bool = of DEPEND_CHECKED: if child.depends.prev[d] != elem.checked: return false + of DEPEND_FOCUS: + let focus = elem.document.focus == elem + if child.depends.prev[d] != focus: + return false return true proc applyDependValues*(styledNode: StyledNode) = let elem = Element(styledNode.node) styledNode.depends.prev[DEPEND_HOVER] = elem.hover styledNode.depends.prev[DEPEND_CHECKED] = elem.checked + let focus = elem.document.focus == elem + styledNode.depends.prev[DEPEND_FOCUS] = focus elem.invalid = false proc addDependency*(styledNode, dep: StyledNode, t: DependencyType) = diff --git a/src/html/dom.nim b/src/html/dom.nim index 5dde41fa..e404f18b 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -56,6 +56,7 @@ type parser_cannot_change_the_mode_flag*: bool is_iframe_srcdoc*: bool + focus*: Element CharacterData* = ref object of Node data*: string @@ -110,6 +111,8 @@ type HTMLSpanElement* = ref object of HTMLElement + HTMLOptGroupElement* = ref object of HTMLElement + HTMLOptionElement* = ref object of HTMLElement selected*: bool @@ -251,7 +254,10 @@ iterator options*(select: HTMLSelectElement): HTMLOptionElement {.inline.} = for child in select.children: if child.tagType == TAG_OPTION: yield HTMLOptionElement(child) - #TODO optgroups + elif child.tagType == TAG_OPTGROUP: + for opt in child.children: + if opt.tagType == TAG_OPTION: + yield HTMLOptionElement(child) func qualifiedName*(element: Element): string = if element.namespacePrefix.issome: element.namespacePrefix.get & ':' & element.localName @@ -277,6 +283,12 @@ func body*(document: Document): HTMLElement = return HTMLElement(element) return nil +func select*(option: HTMLOptionElement): HTMLSelectElement = + for anc in option.ancestors: + if anc.tagType == TAG_SELECT: + return HTMLSelectElement(anc) + return nil + func countChildren(node: Node, nodeType: NodeType): int = for child in node.childNodes: if child.nodeType == nodeType: @@ -546,6 +558,8 @@ func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace of TAG_SELECT: result = new(HTMLSelectElement) HTMLSelectElement(result).size = 1 + of TAG_OPTGROUP: + result = new(HTMLOptGroupElement) of TAG_OPTION: result = new(HTMLOptionElement) of TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6: @@ -672,7 +686,8 @@ func title*(document: Document): string = return "" func disabled*(option: HTMLOptionElement): bool = - #TODO optgroup + if option.parentElement.tagType == TAG_OPTGROUP and option.parentElement.attrb("disabled"): + return true return option.attrb("disabled") func text*(option: HTMLOptionElement): string = diff --git a/src/io/buffer.nim b/src/io/buffer.nim index 5652e84c..539e2f30 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -229,7 +229,7 @@ func getLink(node: StyledNode): HTMLAnchorElement = #TODO ::before links? const ClickableElements = { - TAG_A, TAG_INPUT + TAG_A, TAG_INPUT, TAG_OPTION } func getClickable(styledNode: StyledNode): Element = @@ -789,6 +789,9 @@ proc updateCursor(buffer: Buffer) = buffer.cpos.fromy = 0 buffer.cpos.cursory = buffer.lastVisibleLine - 1 + if buffer.cursory >= buffer.lines.len: + buffer.cpos.cursory = max(0, buffer.lines.len - 1) + if buffer.lines.len == 0: buffer.cpos.cursory = 0 @@ -1108,10 +1111,36 @@ proc submitForm(form: HTMLFormElement, submitter: Element): Option[ClickAction] proc click*(buffer: Buffer): Option[ClickAction] = let clickable = buffer.getCursorClickable() if clickable != nil: + template set_focus(e: Element) = + if buffer.document.focus != e: + buffer.document.focus = e + buffer.reshape = true + template restore_focus = + if buffer.document.focus != nil: + buffer.document.focus = nil + buffer.reshape = true case clickable.tagType + of TAG_SELECT: + set_focus clickable of TAG_A: + restore_focus return ClickAction(url: HTMLAnchorElement(clickable).href, httpmethod: HttpGet).some + of TAG_OPTION: + let option = HTMLOptionElement(clickable) + let select = option.select + if select != nil: + if buffer.document.focus == select: + # select option + if not select.attrb("multiple"): + for option in select.options: + option.selected = false + option.selected = true + restore_focus + else: + # focus on select + set_focus select of TAG_INPUT: + restore_focus let input = HTMLInputElement(clickable) case input.inputType of INPUT_SEARCH: @@ -1170,9 +1199,9 @@ proc click*(buffer: Buffer): Option[ClickAction] = let submitaction = submitForm(input.form, input) return submitaction else: - discard + restore_focus else: - discard + restore_focus proc drawBuffer*(buffer: Buffer) = var format = newFormat() |