diff --git a/src/web/vaev-driver/fetcher.cpp b/src/web/vaev-driver/fetcher.cpp index 0b5fe96a..7e88ebff 100644 --- a/src/web/vaev-driver/fetcher.cpp +++ b/src/web/vaev-driver/fetcher.cpp @@ -9,8 +9,8 @@ namespace Vaev::Driver { -Res> loadDocument(Mime::Url const &, Mime::Mime const &mime, Io::Reader &reader) { - auto dom = makeStrong(); +Res> loadDocument(Mime::Url const &url, Mime::Mime const &mime, Io::Reader &reader) { + auto dom = makeStrong(url); auto buf = try$(Io::readAllUtf8(reader)); if (mime.is("text/html"_mime)) { @@ -21,13 +21,13 @@ Res> loadDocument(Mime::Url const &, Mime::Mime const & } else if (mime.is("application/xhtml+xml"_mime)) { Io::SScan scan{buf}; Markup::XmlParser parser; - dom = try$(parser.parse(scan, HTML)); + try$(parser.parse(scan, HTML, *dom)); return Ok(dom); } else if (mime.is("image/svg+xml"_mime)) { Io::SScan scan{buf}; Markup::XmlParser parser; - dom = try$(parser.parse(scan, SVG)); + try$(parser.parse(scan, SVG, *dom)); return Ok(dom); } else { @@ -40,7 +40,7 @@ Res> viewSource(Mime::Url const &url) { auto file = try$(Sys::File::open(url)); auto buf = try$(Io::readAllUtf8(file)); - auto dom = makeStrong(); + auto dom = makeStrong(url); auto body = makeStrong(Html::BODY); dom->appendChild(body); @@ -55,7 +55,7 @@ Res> viewSource(Mime::Url const &url) { } Res> indexOf(Mime::Url const &url) { - auto dom = makeStrong(); + auto dom = makeStrong(url); auto body = makeStrong(Html::BODY); dom->appendChild(body); @@ -106,7 +106,7 @@ Res> fetchDocument(Mime::Url const &url) { if (not mime.has()) return Error::invalidInput("cannot determine MIME type"); - auto dom = makeStrong(); + auto dom = makeStrong(url); auto file = try$(Sys::File::open(url)); return loadDocument(url, *mime, file); } diff --git a/src/web/vaev-markup/dom.cpp b/src/web/vaev-markup/dom.cpp new file mode 100644 index 00000000..ccfc1ef1 --- /dev/null +++ b/src/web/vaev-markup/dom.cpp @@ -0,0 +1,21 @@ +#include "dom.h" + +namespace Vaev::Markup { + +// MARK: Document -------------------------------------------------------------- + +String Document::title() const { + String res = ""s; + iterDepthFirst([&](auto &node) { + if (auto element = node.template is()) { + if (element->tagName == Html::TITLE) { + res = element->textContent(); + return Iter::BREAK; + } + } + return Iter::CONTINUE; + }); + return res; +} + +} // namespace Vaev::Markup diff --git a/src/web/vaev-markup/dom.h b/src/web/vaev-markup/dom.h index 92406c4b..6f03bd6b 100644 --- a/src/web/vaev-markup/dom.h +++ b/src/web/vaev-markup/dom.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "tags.h" @@ -30,6 +31,11 @@ enum struct NodeType { _LEN, }; +enum struct Iter { + CONTINUE, + BREAK, +}; + // https://dom.spec.whatwg.org/#interface-node struct Node : Meta::Static { @@ -140,6 +146,20 @@ struct Node : return _parentIndex() < parentNode()._children.len() - 1; } + // MARK: Iter + + Iter iterDepthFirst(this auto &self, auto f) { + if (f(self) == Iter::BREAK) + return Iter::BREAK; + for (auto &child : self._children) { + if (child->iterDepthFirst(f) == Iter::BREAK) + return Iter::BREAK; + } + return Iter::CONTINUE; + } + + // MARK: Repr + virtual void _repr(Io::Emit &) const {} void repr(Io::Emit &e) const { @@ -178,11 +198,22 @@ enum struct QuirkMode { struct Document : public Node { static constexpr auto TYPE = NodeType::DOCUMENT; + Mime::Url _url; QuirkMode quirkMode{QuirkMode::NO}; + Document(Mime::Url url) + : _url(url) { + } + NodeType nodeType() const override { return TYPE; } + + String title() const; + + Mime::Url const &url() const { + return _url; + } }; // MARK: DocumentType ---------------------------------------------------------- @@ -298,7 +329,7 @@ struct TokenList { } void add(Str token) { - if (not ::contains(_tokens, token)) + if (not::contains(_tokens, token)) _tokens.pushBack(token); } @@ -316,7 +347,7 @@ struct TokenList { } bool replace(Str oldToken, Str newToken) { - if (not ::contains(_tokens, oldToken)) + if (not::contains(_tokens, oldToken)) return false; _tokens.removeAll(oldToken); _tokens.pushBack(newToken); @@ -356,9 +387,8 @@ struct Element : public Node { panic("textContent is not implemented for elements with multiple children"); auto const &child = *_children[0]; - if (auto text = child.is()) { + if (auto text = child.is()) return text->data; - } panic("textContent is not implemented for elements with children other than text nodes"); } diff --git a/src/web/vaev-markup/xml.cpp b/src/web/vaev-markup/xml.cpp index b1bfb082..73a1bf84 100644 --- a/src/web/vaev-markup/xml.cpp +++ b/src/web/vaev-markup/xml.cpp @@ -8,16 +8,14 @@ namespace Vaev::Markup { // 2 MARK: Documents // https://www.w3.org/TR/xml/#sec-documents -Res> XmlParser::parse(Io::SScan &s, Ns ns) { +Res<> XmlParser::parse(Io::SScan &s, Ns ns, Markup::Document &doc) { // document :: = prolog element Misc * - auto doc = makeStrong(); - try$(_parseProlog(s, *doc)); - doc->appendChild(try$(_parseElement(s, ns))); - while (_parseMisc(s, *doc)) + try$(_parseProlog(s, doc)); + doc.appendChild(try$(_parseElement(s, ns))); + while (_parseMisc(s, doc)) ; - - return Ok(doc); + return Ok(); } // 2.2 MARK: Characters diff --git a/src/web/vaev-markup/xml.h b/src/web/vaev-markup/xml.h index 4dbc1d09..b5dec78c 100644 --- a/src/web/vaev-markup/xml.h +++ b/src/web/vaev-markup/xml.h @@ -5,7 +5,7 @@ namespace Vaev::Markup { struct XmlParser { - Res> parse(Io::SScan &s, Ns ns); + Res<> parse(Io::SScan &s, Ns ns, Markup::Document &doc); Res<> _parseS(Io::SScan &s);