From 9e51210075c2b2742f9b79a4770cb7b45367995d Mon Sep 17 00:00:00 2001 From: VAN BOSSUYT Nicolas Date: Tue, 26 Nov 2024 10:07:28 +0100 Subject: [PATCH] vaev-browser: Simple navigation. --- src/libs/karm-kira/context-menu.cpp | 10 ++-- src/web/vaev-browser/app.cpp | 74 +++++++++++++++++++++++------ src/web/vaev-driver/fetcher.cpp | 69 ++++++++++++++++++++++++--- src/web/vaev-driver/fetcher.h | 2 + 4 files changed, 131 insertions(+), 24 deletions(-) diff --git a/src/libs/karm-kira/context-menu.cpp b/src/libs/karm-kira/context-menu.cpp index 36dc7187972..d810a67a2a9 100644 --- a/src/libs/karm-kira/context-menu.cpp +++ b/src/libs/karm-kira/context-menu.cpp @@ -105,11 +105,15 @@ Ui::Child contextMenuDock(Ui::Children children) { } Ui::Child contextMenuIcon(Ui::OnPress onPress, Mdi::Icon i) { - return Ui::button( - [onPress = std::move(onPress)](auto &n) { + if (onPress) { + onPress = [onPress = std::move(onPress)](auto &n) { onPress(n); Ui::closePopover(n); - }, + }; + } + + return Ui::button( + std::move(onPress), Ui::ButtonStyle::subtle(), i ); diff --git a/src/web/vaev-browser/app.cpp b/src/web/vaev-browser/app.cpp index 8b4efaf7f21..0b0b7fb8f90 100644 --- a/src/web/vaev-browser/app.cpp +++ b/src/web/vaev-browser/app.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -45,18 +46,31 @@ enum struct SidePanel { DEVELOPER_TOOLS, }; -struct State { +struct Navigate { Mime::Url url; + Mime::Uti action = Mime::Uti::PUBLIC_OPEN; +}; + +struct State { + usize currentIndex = 0; + Vec history; Res> dom; SidePanel sidePanel = SidePanel::CLOSE; InspectState inspect = {}; + State(Navigate nav, Res> dom) + : history{nav}, dom{dom} {} + bool canGoBack() const { - return false; + return currentIndex > 0; } bool canGoForward() const { - return false; + return currentIndex < history.len() - 1; + } + + Navigate const ¤tUrl() const { + return history[currentIndex]; } }; @@ -66,23 +80,43 @@ struct GoBack {}; struct GoForward {}; -using Action = Union; +using Action = Union< + Reload, + GoBack, + GoForward, + SidePanel, + InspectorAction, + Navigate>; void reduce(State &s, Action a) { a.visit(Visitor{ [&](Reload) { - s.dom = Vaev::Driver::fetchDocument(s.url); + auto const &object = s.currentUrl(); + if (object.action == Mime::Uti::PUBLIC_MODIFY) { + s.dom = Vaev::Driver::viewSource(object.url); + } else { + s.dom = Vaev::Driver::fetchDocument(object.url); + } }, [&](GoBack) { + s.currentIndex--; + reduce(s, Reload{}); }, [&](GoForward) { + s.currentIndex++; + reduce(s, Reload{}); }, [&](SidePanel p) { s.sidePanel = p; }, [&](InspectorAction a) { s.inspect.apply(a); - } + }, + [&](Navigate n) { + s.history.pushBack(n); + s.currentIndex++; + reduce(s, Reload{}); + }, }); } @@ -109,7 +143,11 @@ Ui::Child mainMenu([[maybe_unused]] State const &s) { ), #ifdef __ck_host__ Kr::contextMenuItem([&](auto &n) { - auto res = Sys::launch(Mime::Uti::PUBLIC_OPEN, s.url); + auto res = Sys::launch({ + .action = Mime::Uti::PUBLIC_OPEN, + .objects = {s.currentUrl().url}, + }); + if (not res) Ui::showDialog( n, @@ -163,17 +201,22 @@ Ui::Child addressBar(Mime::Url const &url) { Ui::Child contextMenu(State const &s) { return Kr::contextMenuContent({ Kr::contextMenuDock({ - Kr::contextMenuIcon(Ui::NOP, Mdi::ARROW_LEFT), - Kr::contextMenuIcon(Ui::NOP, Mdi::REFRESH), + Kr::contextMenuIcon(Model::bindIf(s.canGoBack()), Mdi::ARROW_LEFT), + Kr::contextMenuIcon(Model::bindIf(s.canGoForward()), Mdi::ARROW_RIGHT), + Kr::contextMenuIcon(Model::bind(), Mdi::REFRESH), }), Ui::separator(), Kr::contextMenuItem( - [s](auto &) { - (void)Sys::launch(Mime::Uti::PUBLIC_MODIFY, s.url); - }, + Model::bind( + s.currentUrl().url, + Mime::Uti::PUBLIC_MODIFY + ), Mdi::CODE_TAGS, "View Source..." ), - Kr::contextMenuItem(Model::bind(SidePanel::DEVELOPER_TOOLS), Mdi::BUTTON_CURSOR, "Inspect"), + Kr::contextMenuItem( + Model::bind(SidePanel::DEVELOPER_TOOLS), + Mdi::BUTTON_CURSOR, "Inspect" + ), }); } @@ -250,7 +293,7 @@ Ui::Child appContent(State const &s) { Ui::Child app(Mime::Url url, Res> dom) { return Ui::reducer( { - url, + Navigate{url}, dom, }, [](State const &s) { @@ -259,8 +302,9 @@ Ui::Child app(Mime::Url url, Res> dom) { .title = "Vaev"s, .startTools = slots$( Ui::button(Model::bindIf(s.canGoBack()), Ui::ButtonStyle::subtle(), Mdi::ARROW_LEFT), + Ui::button(Model::bindIf(s.canGoForward()), Ui::ButtonStyle::subtle(), Mdi::ARROW_RIGHT), ), - .midleTools = slots$(addressBar(s.url) | Ui::grow()), + .midleTools = slots$(addressBar(s.currentUrl().url) | Ui::grow()), .endTools = slots$( Ui::button( [&](Ui::Node &n) { diff --git a/src/web/vaev-driver/fetcher.cpp b/src/web/vaev-driver/fetcher.cpp index ec1be5a58a0..657c865683c 100644 --- a/src/web/vaev-driver/fetcher.cpp +++ b/src/web/vaev-driver/fetcher.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -35,6 +36,58 @@ Res> loadDocument(Mime::Url const &, Mime::Mime const & } } +Res> viewSource(Mime::Url const &url) { + auto file = try$(Sys::File::open(url)); + auto buf = try$(Io::readAllUtf8(file)); + + auto dom = makeStrong(); + + auto body = makeStrong(Html::BODY); + dom->appendChild(body); + + auto pre = makeStrong(Html::PRE); + body->appendChild(pre); + + auto text = makeStrong(buf); + pre->appendChild(text); + + return Ok(dom); +} + +Res> indexOf(Mime::Url const &url) { + auto dom = makeStrong(); + + auto body = makeStrong(Html::BODY); + dom->appendChild(body); + + auto h1 = makeStrong(Html::H1); + body->appendChild(h1); + + auto text = makeStrong(Io::format("Index of {}", url.path).unwrapOr(""s)); + h1->appendChild(text); + + auto ul = makeStrong(Html::UL); + body->appendChild(ul); + + auto dir = try$(Sys::Dir::open(url)); + + for (auto const &entry : dir.entries()) { + auto li = makeStrong(Html::LI); + ul->appendChild(li); + + auto a = makeStrong(Html::A); + li->appendChild(a); + + auto href = url.join(entry.name); + a->setAttribute(Html::HREF_ATTR, href.str()); + + auto text = makeStrong(entry.name); + a->appendChild(text); + } + + return Ok(dom); +} + Res> fetchDocument(Mime::Url const &url) { if (url.scheme == "about") { if (url.path.str() == "blank") @@ -45,14 +98,18 @@ Res> fetchDocument(Mime::Url const &url) { return Error::invalidInput("unsupported about page"); } else if (url.scheme == "file" or url.scheme == "bundle") { - auto mime = Mime::sniffSuffix(url.path.suffix()); + if (try$(Sys::isDir(url))) { + return indexOf(url); + } else { + auto mime = Mime::sniffSuffix(url.path.suffix()); - if (not mime.has()) - return Error::invalidInput("cannot determine MIME type"); + if (not mime.has()) + return Error::invalidInput("cannot determine MIME type"); - auto dom = makeStrong(); - auto file = try$(Sys::File::open(url)); - return loadDocument(url, *mime, file); + auto dom = makeStrong(); + auto file = try$(Sys::File::open(url)); + return loadDocument(url, *mime, file); + } } else { return Error::invalidInput("unsupported url scheme"); } diff --git a/src/web/vaev-driver/fetcher.h b/src/web/vaev-driver/fetcher.h index 7cb93f27113..7f94033128c 100644 --- a/src/web/vaev-driver/fetcher.h +++ b/src/web/vaev-driver/fetcher.h @@ -12,4 +12,6 @@ Res> fetchDocument(Mime::Url const &url); Res> loadDocument(Mime::Url const &url, Mime::Mime const &mime, Io::Reader &reader); +Res> viewSource(Mime::Url const &url); + } // namespace Vaev::Driver