From fd721c53d89433956799cb1a8305986b53503d93 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Mon, 13 Mar 2023 20:49:35 -0700 Subject: [PATCH] Use instead of event handlers for functioning history. --- web/src/lib.rs | 129 +++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/web/src/lib.rs b/web/src/lib.rs index 2628d50..0094179 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -22,46 +22,69 @@ const SEARCH_RESULTS_PER_PAGE: usize = 20; // `init` describes what should happen when your app started. fn init(url: Url, orders: &mut impl Orders) -> Model { - warn!("init called"); - log!(url); - let mut url = url.clone(); - let mut query = "".to_string(); - let hpp = url.next_hash_path_part(); - log!(hpp); - match hpp { - Some("t") => { - let tid = url.next_hash_path_part().unwrap_or("").to_string(); - orders.send_msg(Msg::ShowPrettyRequest(tid)); - } - Some("s") => { - query = url - .next_hash_path_part() - .map(|q| Url::decode_uri_component(q).unwrap_or("".to_string())) - .unwrap_or("".to_string()); - orders.send_msg(Msg::SearchRequest { - query: query.to_string(), + orders + .subscribe(on_url_changed) + .notify(subs::UrlChanged(url.clone())); + + Model { + context: Context::None, + query: "".to_string(), + refreshing_state: RefreshingState::None, + } +} + +fn on_url_changed(uc: subs::UrlChanged) -> Msg { + let mut url = uc.0; + info!( + "url changed '{}', history {}", + url, + history().length().unwrap_or(0) + ); + let hpp = url.remaining_hash_path_parts(); + match hpp.as_slice() { + ["t", tid] => Msg::ShowPrettyRequest(tid.to_string()), + ["s", query] => { + let query = Url::decode_uri_component(query).unwrap_or("".to_string()); + Msg::SearchRequest { + query, page: 0, results_per_page: SEARCH_RESULTS_PER_PAGE, - }); + } + } + ["s", query, page] => { + let query = Url::decode_uri_component(query).unwrap_or("".to_string()); + let page = page[1..].parse().unwrap_or(0); + Msg::SearchRequest { + query, + page, + results_per_page: SEARCH_RESULTS_PER_PAGE, + } } p => { - log!(p); - orders.send_msg(Msg::SearchRequest { + if !p.is_empty() { + info!("Unhandled path '{p:?}'"); + } + Msg::SearchRequest { query: "".to_string(), page: 0, results_per_page: SEARCH_RESULTS_PER_PAGE, - }); + } } - }; - orders.subscribe(|uc: subs::UrlChanged| { - info!("uc {}", uc.0); - }); + } +} - info!("init query '{}'", query); - Model { - context: Context::None, - query, - refreshing_state: RefreshingState::None, +mod urls { + use seed::Url; + pub fn search(query: &str, page: usize) -> Url { + let query = Url::encode_uri_component(query); + if page > 0 { + Url::new().set_hash_path(["s", &query, &format!("p{page}")]) + } else { + Url::new().set_hash_path(["s", &query]) + } + } + pub fn thread(tid: &str) -> Url { + Url::new().set_hash_path(["t", tid]) } } @@ -135,8 +158,6 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } => { info!("searching for '{query}' pg {page} # / pg {results_per_page}"); model.query = query.clone(); - let url = Url::new().set_hash_path(["s", &query]); - orders.request_url(url); orders.skip().perform_cmd(async move { Msg::SearchResult(search_request(&query, page, results_per_page).await) }); @@ -150,8 +171,6 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } Msg::ShowRequest(tid) => { - let url = Url::new().set_hash_path(["t", &tid]); - orders.request_url(url); orders .skip() .perform_cmd(async move { Msg::ShowResult(show_request(&tid).await) }); @@ -165,8 +184,6 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } Msg::ShowPrettyRequest(tid) => { - let url = Url::new().set_hash_path(["t", &tid]); - orders.request_url(url); orders .skip() .perform_cmd(async move { Msg::ShowPrettyResult(show_pretty_request(&tid).await) }); @@ -181,11 +198,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::NextPage => { match &model.context { Context::Search(sr) => { - orders.send_msg(Msg::SearchRequest { - query: sr.query.clone(), - page: sr.page + 1, - results_per_page: sr.results_per_page, - }); + orders.request_url(urls::search(&sr.query, sr.page + 1)); } Context::Thread(_) => (), // do nothing (yet?) Context::None => (), // do nothing (yet?) @@ -194,11 +207,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::PreviousPage => { match &model.context { Context::Search(sr) => { - orders.send_msg(Msg::SearchRequest { - query: sr.query.clone(), - page: sr.page.saturating_sub(1), - results_per_page: sr.results_per_page, - }); + orders.request_url(urls::search(&sr.query, sr.page.saturating_sub(1))); } Context::Thread(_) => (), // do nothing (yet?) Context::None => (), // do nothing (yet?) @@ -421,6 +430,9 @@ fn tags_chiclet(tags: &[String], is_mobile: bool) -> impl Iterator "is-small")]; let tag = tag.clone(); a![ + attrs! { + At::Href => urls::search(&format!("tag:{tag}"), 0) + }, match tag.as_str() { "attachment" => span![classes, style, "📎"], "replied" => span![classes, style, i![C!["fa-solid", "fa-reply"]]], @@ -523,9 +535,12 @@ fn view_search_results(query: &str, search_results: &shared::SearchResult) -> No C!["subject"], tags_chiclet(&r.tags, false), " ", - span![ + a![ + C!["has-text-light"], + attrs! { + At::Href => urls::thread(&tid) + }, &r.subject, - ev(Ev::Click, move |_| Msg::ShowPrettyRequest(tid)) ] ], td![C!["date"], &r.date_relative] @@ -648,21 +663,17 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node { ], a![ C!["navbar-item", "button"], + attrs! { + At::Href => urls::search("is:unread", 0) + }, "Unread", - ev(Ev::Click, |_| Msg::SearchRequest { - query: "is:unread".to_string(), - page: 0, - results_per_page: SEARCH_RESULTS_PER_PAGE, - }), ], a![ C!["navbar-item", "button"], + attrs! { + At::Href => urls::search("", 0) + }, "All", - ev(Ev::Click, |_| Msg::SearchRequest { - query: "".to_string(), - page: 0, - results_per_page: SEARCH_RESULTS_PER_PAGE, - }), ], input![ C!["navbar-item", "input"],