diff options
-rw-r--r-- | src/client.nim | 31 | ||||
-rw-r--r-- | src/css/cascade.nim | 13 | ||||
-rw-r--r-- | src/css/mediaquery.nim | 2 | ||||
-rw-r--r-- | src/html/dom.nim | 13 | ||||
-rw-r--r-- | src/html/parser.nim | 3 | ||||
-rw-r--r-- | src/io/buffer.nim | 17 | ||||
-rw-r--r-- | src/io/loader.nim | 33 | ||||
-rw-r--r-- | src/types/mime.nim | 1 | ||||
-rw-r--r-- | src/types/url.nim | 5 |
9 files changed, 90 insertions, 28 deletions
diff --git a/src/client.nim b/src/client.nim index 1a18bc56..2cce60a7 100644 --- a/src/client.nim +++ b/src/client.nim @@ -1,26 +1,25 @@ -import httpclient import streams import terminal import options import os +import css/sheet +import config/config import io/buffer import io/lineedit -import config/config -import utils/twtstr -import css/sheet -import types/mime +import io/loader import types/url +import utils/twtstr type Client* = ref object - http: HttpClient buffer: Buffer feednext: bool s: string iserror: bool errormessage: string userstyle: CSSStylesheet + loader: FileLoader ActionError = object of IOError LoadError = object of ActionError @@ -28,7 +27,7 @@ type proc newClient*(): Client = new(result) - result.http = newHttpClient() + result.loader = newFileLoader() proc loadError(s: string) = raise newException(LoadError, s) @@ -39,20 +38,6 @@ proc actionError(s: string) = proc interruptError() = raise newException(InterruptError, "Interrupted") -proc getPage(client: Client, url: Url): tuple[s: Stream, contenttype: string] = - if url.scheme == "file": - let path = url.path.serialize_unicode() - result.contenttype = guessContentType(path) - result.s = newFileStream(path, fmRead) - elif url.scheme == "http" or url.scheme == "https": - let resp = client.http.get(url.serialize(true)) - let ct = resp.contentType() - if ct != "": - result.contenttype = ct.until(';') - else: - result.contenttype = guessContentType(url.path.serialize()) - result.s = resp.bodyStream - proc addBuffer(client: Client) = if client.buffer == nil: client.buffer = newBuffer() @@ -64,6 +49,7 @@ proc addBuffer(client: Client) = client.buffer.next.prev = client.buffer client.buffer.next.next = oldnext client.buffer = client.buffer.next + client.buffer.loader = client.loader proc prevBuffer(client: Client) = if client.buffer.prev != nil: @@ -99,6 +85,7 @@ proc setupBuffer(client: Client) = proc readPipe(client: Client, ctype: string) = client.buffer = newBuffer() + client.buffer.loader = client.loader client.buffer.contenttype = if ctype != "": ctype else: "text/plain" client.buffer.ispipe = true client.buffer.istream = newFileStream(stdin) @@ -115,7 +102,7 @@ proc gotoUrl(client: Client, url: Url, prevurl = none(Url), force = false, newbu raise newException(InterruptError, "Interrupted")) if force or prevurl.issome or not prevurl.get.equals(url, true): try: - let page = client.getPage(url) + let page = client.loader.getPage(url) if page.s != nil: if newbuf: client.addBuffer() diff --git a/src/css/cascade.nim b/src/css/cascade.nim index 223a3ec5..dc11628f 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -167,9 +167,20 @@ proc applyRules*(document: Document, ua, user: CSSStylesheet) = var rules_head: CSSStylesheet for child in document.head.children: - if child.tagType == TAG_STYLE: + case child.tagType + of TAG_STYLE: let style = HTMLStyleElement(child) rules_head.add(style.sheet) + of TAG_LINK: + let link = HTMLLinkElement(child) + if link.s != nil: + let content = link.s.readAll() + link.sheet = parseStylesheet(content) + link.s.close() + link.s = nil + rules_head.add(link.sheet) + else: + discard if rules_head.len > 0: embedded_rules.add(rules_head) diff --git a/src/css/mediaquery.nim b/src/css/mediaquery.nim index cea35c36..4e8c1e9f 100644 --- a/src/css/mediaquery.nim +++ b/src/css/mediaquery.nim @@ -186,7 +186,7 @@ proc parseMediaCondition(parser: var MediaQueryParser, non = false, noor = false var non = non if not non: let cval = parser.consume() - if cval of CSSToken: + if cval of CSSToken and CSSToken(cval).tokenType == CSS_IDENT_TOKEN: if $CSSToken(cval).value == "not": non = true else: diff --git a/src/html/dom.nim b/src/html/dom.nim index 0105b72f..5537491c 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -1,11 +1,12 @@ -import uri import tables import options +import streams import strutils import css/values import css/sheet import html/tags +import types/url type EventTarget* = ref EventTargetObj @@ -35,7 +36,7 @@ type Document* = ref DocumentObj DocumentObj = object of NodeObj - location*: Uri + location*: Url type_elements*: array[TagType, seq[Element]] id_elements*: Table[string, seq[Element]] class_elements*: Table[string, seq[Element]] @@ -117,6 +118,12 @@ type HTMLStyleElement* = ref object of HTMLElement sheet*: CSSStylesheet + HTMLLinkElement* = ref object of HTMLElement + href*: string + rel*: string + sheet*: CSSStylesheet + s*: Stream + iterator textNodes*(node: Node): Text {.inline.} = for node in node.childNodes: if node.nodeType == TEXT_NODE: @@ -295,6 +302,8 @@ func newHtmlElement*(document: Document, tagType: TagType): HTMLElement = result = new(HTMLLIElement) of TAG_STYLE: result = new(HTMLStyleElement) + of TAG_LINK: + result = new(HTMLLinkElement) else: result = new(HTMLElement) diff --git a/src/html/parser.nim b/src/html/parser.nim index 7488534a..febe3bce 100644 --- a/src/html/parser.nim +++ b/src/html/parser.nim @@ -284,6 +284,9 @@ proc processDocumentStartElement(state: var HTMLParseState, element: Element, ta HTMLHeadingElement(element).rank = 5 of TAG_H6: HTMLHeadingElement(element).rank = 6 + of TAG_LINK: + HTMLLinkElement(element).href = element.attr("href") + HTMLLinkElement(element).rel = element.attr("rel") else: discard if not state.in_body and not (element.tagType in HeadTagTypes): diff --git a/src/io/buffer.nim b/src/io/buffer.nim index f219fe2c..a082cfe3 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -8,8 +8,9 @@ import css/sheet import html/dom import html/tags import html/parser -import io/term import io/cell +import io/loader +import io/term import layout/box import render/renderdocument import render/rendertext @@ -49,6 +50,7 @@ type prev*: Buffer next* {.cursor.}: Buffer userstyle*: CSSStylesheet + loader*: FileLoader proc newBuffer*(): Buffer = new(result) @@ -711,6 +713,17 @@ proc updateHover(buffer: Buffer) = elem.refreshStyle() buffer.prevnodes = nodes +proc loadResources(buffer: Buffer, document: Document) = + for elem in document.head.children: + if elem.tagType == TAG_LINK: + let elem = HTMLLinkElement(elem) + if elem.rel == "stylesheet": + let url = parseUrl(elem.href, document.location.some) + if url.issome: + let res = buffer.loader.getPage(url.get) + if res.s != nil and res.contenttype == "text/css": + elem.s = res.s + proc load*(buffer: Buffer) = case buffer.contenttype of "text/html": @@ -723,6 +736,8 @@ proc load*(buffer: Buffer) = buffer.istream.close() buffer.streamclosed = true buffer.document = parseHtml(newStringStream(buffer.source)) + buffer.document.location = buffer.location + buffer.loadResources(buffer.document) else: if not buffer.streamclosed: buffer.source = buffer.istream.readAll() diff --git a/src/io/loader.nim b/src/io/loader.nim new file mode 100644 index 00000000..3ef5320e --- /dev/null +++ b/src/io/loader.nim @@ -0,0 +1,33 @@ +import httpclient +import options +import streams + +import types/mime +import types/url +import utils/twtstr + +type + FileLoader* = ref object + http: HttpClient + + LoadResult* = object + s*: Stream + contenttype*: string + +proc newFileLoader*(): FileLoader = + new(result) + result.http = newHttpClient() + +proc getPage*(loader: FileLoader, url: Url): LoadResult = + if url.scheme == "file": + let path = url.path.serialize_unicode() + result.contenttype = guessContentType(path) + result.s = newFileStream(path, fmRead) + elif url.scheme == "http" or url.scheme == "https": + let resp = loader.http.get(url.serialize(true)) + let ct = resp.contentType() + if ct != "": + result.contenttype = ct.until(';') + else: + result.contenttype = guessContentType(url.path.serialize()) + result.s = resp.bodyStream diff --git a/src/types/mime.nim b/src/types/mime.nim index 5c48c896..fb3f4b2c 100644 --- a/src/types/mime.nim +++ b/src/types/mime.nim @@ -7,6 +7,7 @@ const DefaultGuess = [ ("xhtm", "application/xhtml+xml"), ("xht", "application/xhtml+xml"), ("txt", "text/plain"), + ("css", "text/css"), ("", "text/plain") ].toTable() diff --git a/src/types/url.nim b/src/types/url.nim index 2356fb73..00a5fd51 100644 --- a/src/types/url.nim +++ b/src/types/url.nim @@ -317,7 +317,10 @@ proc shorten_path(url: var Url) {.inline.} = discard url.path.ss.pop() proc append(path: var UrlPath, s: string) = - path.ss.add(s) + if path.opaque: + path.s &= s + else: + path.ss.add(s) template includes_credentials(url: Url): bool = url.username != "" or url.password != "" |