diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config/config.nim | 1 | ||||
-rw-r--r-- | src/html/catom.nim | 1 | ||||
-rw-r--r-- | src/html/dom.nim | 6 | ||||
-rw-r--r-- | src/io/serversocket.nim | 3 | ||||
-rw-r--r-- | src/local/container.nim | 47 | ||||
-rw-r--r-- | src/local/pager.nim | 76 | ||||
-rw-r--r-- | src/server/buffer.nim | 96 |
7 files changed, 129 insertions, 101 deletions
diff --git a/src/config/config.nim b/src/config/config.nim index 50173057..311d52e8 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -64,6 +64,7 @@ type proxy*: Option[URL] default_headers*: TableRef[string, string] insecure_ssl_no_verify*: Option[bool] + autofocus*: Option[bool] OmniRule* = ref object match*: Regex diff --git a/src/html/catom.nim b/src/html/catom.nim index 9180ecd6..7c61e23e 100644 --- a/src/html/catom.nim +++ b/src/html/catom.nim @@ -16,6 +16,7 @@ macro makeStaticAtom = satAlign = "align" satAlt = "alt" satAsync = "async" + satAutofocus = "autofocus" satBgcolor = "bgcolor" satBlocking = "blocking" satCharset = "charset" diff --git a/src/html/dom.nim b/src/html/dom.nim index 6eb1079f..d09849c7 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -2336,6 +2336,12 @@ func findAnchor*(document: Document; id: string): Element = return child return nil +func findAutoFocus*(document: Document): Element = + for child in document.elements: + if child.attrb(satAutofocus): + return child + return nil + # Forward declaration hack isDefaultPassive = func (eventTarget: EventTarget): bool = if eventTarget of Window: diff --git a/src/io/serversocket.nim b/src/io/serversocket.nim index dff6de70..abb3491a 100644 --- a/src/io/serversocket.nim +++ b/src/io/serversocket.nim @@ -14,6 +14,9 @@ const SocketPathPrefix = "cha_sock_" proc getSocketName*(pid: int): string = SocketPathPrefix & $pid +func getFd*(ssock: ServerSocket): SocketHandle = + return ssock.sock.getFd() + proc getSocketPath*(socketDir: string; pid: int): string = socketDir / getSocketName(pid) diff --git a/src/local/container.nim b/src/local/container.nim index 90e00ebb..b64606a1 100644 --- a/src/local/container.nim +++ b/src/local/container.nim @@ -1,5 +1,4 @@ import std/deques -import std/net import std/options import std/os import std/posix @@ -208,8 +207,8 @@ proc clone*(container: Container; newurl: URL; loader: FileLoader): let ssock = initServerSocket(loader.sockDir, loader.sockDirFd, loader.clientPid) SocketStream(container.iface.stream.source) - .sendFileHandle(FileHandle(ssock.sock.getFd())) - ssock.sock.close() + .sendFileHandle(FileHandle(ssock.getFd())) + ssock.close(unlink = false) return p.then(proc(pid: int): Container = if pid == -1: return nil @@ -1371,6 +1370,23 @@ proc setLoadInfo(container: Container; msg: string) = container.loadinfo = msg container.triggerEvent(cetSetLoadInfo) +proc onReadLine(container: Container; rl: ReadLineResult) = + case rl.t + of rltText: + container.triggerEvent(ContainerEvent( + t: cetReadLine, + prompt: rl.prompt, + value: rl.value, + password: rl.hide + )) + of rltArea: + container.triggerEvent(ContainerEvent( + t: cetReadArea, + tvalue: rl.value + )) + of rltFile: + container.triggerEvent(ContainerEvent(t: cetReadFile)) + #TODO this should be called with a timeout. proc onload(container: Container; res: int) = if container.loadState == lsCanceled: @@ -1380,13 +1396,15 @@ proc onload(container: Container; res: int) = container.setLoadInfo("") container.triggerEvent(cetStatus) container.triggerEvent(cetLoaded) - if cfHasStart notin container.flags and container.url.anchor != "": + if cfHasStart notin container.flags and (container.url.anchor != "" or + container.config.autofocus): container.requestLines().then(proc(): Promise[GotoAnchorResult] = return container.iface.gotoAnchor() ).then(proc(res: GotoAnchorResult) = - if res.isSome: - let res = res.get + if res.found: container.setCursorXYCenter(res.x, res.y) + if res.focus != nil: + container.onReadLine(res.focus) ) else: container.needslines = true @@ -1522,22 +1540,7 @@ proc onclick(container: Container; res: ClickResult; save: bool) = if res.select.isSome and not save: container.displaySelect(res.select.get) if res.readline.isSome: - let rl = res.readline.get - case rl.t - of rltText: - container.triggerEvent(ContainerEvent( - t: cetReadLine, - prompt: rl.prompt, - value: rl.value, - password: rl.hide - )) - of rltArea: - container.triggerEvent(ContainerEvent( - t: cetReadArea, - tvalue: rl.value - )) - of rltFile: - container.triggerEvent(ContainerEvent(t: cetReadFile)) + container.onReadLine(res.readline.get) proc click*(container: Container) {.jsfunc.} = if container.select.open: diff --git a/src/local/pager.nim b/src/local/pager.nim index 48856837..16cd20a0 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -952,16 +952,28 @@ proc windowChange*(pager: Pager) = proc applySiteconf(pager: Pager; url: var URL; charsetOverride: Charset; loaderConfig: var LoaderClientConfig): BufferConfig = let host = url.host - var referer_from = false - var cookieJar: CookieJar = nil - var headers = newHeaders(pager.config.network.default_headers) - var scripting = false - var images = false - var charsets = pager.config.encoding.document_charset - var userstyle = pager.config.css.stylesheet - var proxy = pager.config.network.proxy let ctx = pager.jsctx - var insecureSSLNoVerify = false + var res = BufferConfig( + userstyle: pager.config.css.stylesheet, + referer_from: false, + scripting: false, + charsets: pager.config.encoding.document_charset, + images: false, + isdump: pager.config.start.headless, + charsetOverride: charsetOverride, + protocol: pager.config.protocol + ) + loaderConfig = LoaderClientConfig( + defaultHeaders: newHeaders(pager.config.network.default_headers), + cookiejar: nil, + proxy: pager.config.network.proxy, + filter: newURLFilter( + scheme = some(url.scheme), + allowschemes = @["data", "cache"], + default = true + ), + insecureSSLNoVerify: false + ) for sc in pager.config.siteconf: if sc.url.isSome and not sc.url.get.match($url): continue @@ -987,47 +999,29 @@ proc applySiteconf(pager: Pager; url: var URL; charsetOverride: Charset; if jarid notin pager.cookiejars: pager.cookiejars[jarid] = newCookieJar(url, sc.third_party_cookie) - cookieJar = pager.cookiejars[jarid] + loaderConfig.cookieJar = pager.cookiejars[jarid] else: - cookieJar = nil # override + loaderConfig.cookieJar = nil # override if sc.scripting.isSome: - scripting = sc.scripting.get + res.scripting = sc.scripting.get if sc.referer_from.isSome: - referer_from = sc.referer_from.get + res.referer_from = sc.referer_from.get if sc.document_charset.len > 0: - charsets = sc.document_charset + res.charsets = sc.document_charset if sc.images.isSome: - images = sc.images.get + res.images = sc.images.get if sc.stylesheet.isSome: - userstyle &= "\n" - userstyle &= sc.stylesheet.get + res.userstyle &= "\n" + res.userstyle &= sc.stylesheet.get if sc.proxy.isSome: - proxy = sc.proxy.get + loaderConfig.proxy = sc.proxy.get if sc.default_headers != nil: - headers = newHeaders(sc.default_headers[]) + loaderConfig.defaultHeaders = newHeaders(sc.default_headers[]) if sc.insecure_ssl_no_verify.isSome: - insecureSSLNoVerify = sc.insecure_ssl_no_verify.get - loaderConfig = LoaderClientConfig( - defaultHeaders: headers, - cookiejar: cookieJar, - proxy: proxy, - filter: newURLFilter( - scheme = some(url.scheme), - allowschemes = @["data", "cache"], - default = true - ), - insecureSSLNoVerify: insecureSSLNoVerify - ) - return BufferConfig( - userstyle: userstyle, - referer_from: referer_from, - scripting: scripting, - charsets: charsets, - images: images, - isdump: pager.config.start.headless, - charsetOverride: charsetOverride, - protocol: pager.config.protocol - ) + loaderConfig.insecureSSLNoVerify = sc.insecure_ssl_no_verify.get + if sc.autofocus.isSome: + res.autofocus = sc.autofocus.get + return res # Load request in a new buffer. proc gotoURL(pager: Pager; request: Request; prevurl = none(URL); diff --git a/src/server/buffer.nim b/src/server/buffer.nim index c2ed2fb7..8b31fb64 100644 --- a/src/server/buffer.nim +++ b/src/server/buffer.nim @@ -145,6 +145,7 @@ type charsets*: seq[Charset] charsetOverride*: Charset protocol*: Table[string, ProtocolConfig] + autofocus*: bool proc getFromOpaque[T](opaque: pointer; res: var T) = let opaque = cast[InterfaceOpaque](opaque) @@ -156,7 +157,7 @@ proc getFromOpaque[T](opaque: pointer; res: var T) = proc newBufferInterface*(stream: SocketStream; registerFun: proc(fd: int)): BufferInterface = let opaque = InterfaceOpaque(stream: stream) - result = BufferInterface( + return BufferInterface( map: newPromiseMap(cast[pointer](opaque)), packetid: 1, # ids below 1 are invalid opaque: opaque, @@ -653,21 +654,61 @@ proc findNextMatch*(buffer: Buffer; regex: Regex; cursorx, cursory: int; break inc y -type GotoAnchorResult* = Opt[tuple[x, y: int]] +type + ReadLineType* = enum + rltText, rltArea, rltFile + + ReadLineResult* = ref object + t*: ReadLineType + prompt*: string + value*: string + hide*: bool + + SelectResult* = object + multiple*: bool + options*: seq[string] + selected*: seq[int] + + ClickResult* = object + open*: Request + readline*: Option[ReadLineResult] + repaint*: bool + select*: Option[SelectResult] + +proc click(buffer: Buffer; clickable: Element): ClickResult + +type GotoAnchorResult* = object + found*: bool + x*: int + y*: int + focus*: ReadLineResult proc gotoAnchor*(buffer: Buffer): GotoAnchorResult {.proxy.} = if buffer.document == nil: - return err() - let anchor = buffer.document.findAnchor(buffer.url.anchor) + return GotoAnchorResult(found: false) + var anchor = buffer.document.findAnchor(buffer.url.anchor) + var focus: ReadLineResult = nil + if buffer.config.autofocus: + let autofocus = buffer.document.findAutoFocus() + if autofocus != nil: + if anchor == nil: + anchor = autofocus # jump to autofocus instead + let res = buffer.click(autofocus) + focus = res.readline.get(nil) if anchor == nil: - return err() + return GotoAnchorResult(found: false) for y in 0 ..< buffer.lines.len: let line = buffer.lines[y] for i in 0 ..< line.formats.len: let format = line.formats[i] if format.node != nil and format.node.node in anchor: - return ok((format.pos, y)) - return err() + return GotoAnchorResult( + found: true, + x: format.pos, + y: y, + focus: focus + ) + return GotoAnchorResult(found: false) proc do_reshape(buffer: Buffer) = if buffer.document == nil: @@ -1268,6 +1309,7 @@ proc serializeMultipartFormData(entries: seq[FormDataEntry]): FormData = return formData proc serializePlainTextFormData(kvs: seq[(string, string)]): string = + result = "" for it in kvs: let (name, value) = it result &= name @@ -1422,6 +1464,7 @@ proc implicitSubmit(buffer: Buffer; input: HTMLInputElement): Request = proc readSuccess*(buffer: Buffer; s: string; hasFd: bool): ReadSuccessResult {.proxy.} = var fd: FileHandle = -1 + var res = ReadSuccessResult() if hasFd: fd = buffer.pstream.recvFileHandle() if buffer.document.focus != nil: @@ -1433,48 +1476,25 @@ proc readSuccess*(buffer: Buffer; s: string; hasFd: bool): ReadSuccessResult input.file = newWebFile(s, fd) input.invalid = true buffer.do_reshape() - result.repaint = true - result.open = buffer.implicitSubmit(input) + res.repaint = true + res.open = buffer.implicitSubmit(input) else: input.value = s input.invalid = true buffer.do_reshape() - result.repaint = true - result.open = buffer.implicitSubmit(input) + res.repaint = true + res.open = buffer.implicitSubmit(input) of TAG_TEXTAREA: let textarea = HTMLTextAreaElement(buffer.document.focus) textarea.value = s textarea.invalid = true buffer.do_reshape() - result.repaint = true + res.repaint = true else: discard let r = buffer.restoreFocus() - if not result.repaint: - result.repaint = r - -type - ReadLineType* = enum - rltText, rltArea, rltFile - - ReadLineResult* = object - t*: ReadLineType - prompt*: string - value*: string - hide*: bool - -type - SelectResult* = object - multiple*: bool - options*: seq[string] - selected*: seq[int] - - ClickResult* = object - open*: Request - readline*: Option[ReadLineResult] - repaint*: bool - select*: Option[SelectResult] - -proc click(buffer: Buffer; clickable: Element): ClickResult + if not res.repaint: + res.repaint = r + return res proc click(buffer: Buffer; label: HTMLLabelElement): ClickResult = let control = label.control |