143 lines
4.5 KiB
Rust
143 lines
4.5 KiB
Rust
use common::web_api;
|
|
use futures::{
|
|
StreamExt,
|
|
channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded},
|
|
};
|
|
use gloo::{events::EventListener, utils::document};
|
|
use wasm_bindgen::prelude::*;
|
|
use wasm_bindgen_futures::spawn_local;
|
|
use web_sys::{Element, HtmlDivElement, HtmlInputElement, HtmlSpanElement, KeyboardEvent};
|
|
|
|
use crate::{
|
|
ron_request,
|
|
utils::{SelectorExt, get_current_lang, selector, selector_and_clone},
|
|
};
|
|
|
|
const MAX_NB_SEARCH_RESULT: u32 = 10;
|
|
|
|
pub fn setup() {
|
|
// Here we check if the search input exists.
|
|
// Otherwise the search elements are considered as not present.
|
|
let input_search = match document().query_selector("#search input") {
|
|
Ok(Some(e)) => e.dyn_into::<HtmlInputElement>().unwrap(),
|
|
_ => return,
|
|
};
|
|
|
|
let (sender, mut receiver): (UnboundedSender<String>, UnboundedReceiver<String>) = unbounded();
|
|
|
|
spawn_local(async move {
|
|
while let Some(search_term) = receiver.next().await {
|
|
perform_search(search_term).await;
|
|
}
|
|
});
|
|
|
|
EventListener::new(&input_search, "input", move |event| {
|
|
let input_search: HtmlInputElement = event.target().unwrap().dyn_into().unwrap();
|
|
let search_term = input_search.value().trim().to_string();
|
|
sender.unbounded_send(search_term).unwrap();
|
|
})
|
|
.forget();
|
|
|
|
EventListener::new(&input_search, "keydown", move |event| {
|
|
let key_event: &KeyboardEvent = event.dyn_ref().unwrap();
|
|
if key_event.key() == "Escape" {
|
|
let input_search: HtmlInputElement = key_event.target().unwrap().dyn_into().unwrap();
|
|
input_search.set_value("");
|
|
selector::<HtmlDivElement>("#search .results")
|
|
.style()
|
|
.set_property("display", "none")
|
|
.unwrap();
|
|
}
|
|
})
|
|
.forget();
|
|
}
|
|
|
|
async fn perform_search(search_term: String) {
|
|
let results_element: HtmlDivElement = selector("#search .results");
|
|
|
|
if search_term.is_empty() {
|
|
results_element
|
|
.style()
|
|
.set_property("display", "none")
|
|
.unwrap();
|
|
return;
|
|
}
|
|
|
|
results_element
|
|
.selector::<Element>("ul")
|
|
.set_text_content(None);
|
|
|
|
if search_term.len() < common::consts::MIN_SEARCH_STRING_LENGTH {
|
|
display_message(Message::TooFewCharacters);
|
|
} else {
|
|
display_message(Message::None);
|
|
let search_result: Vec<web_api::RecipeSearchResult> = ron_request::get_with_params(
|
|
"/ron-api/recipe/search",
|
|
web_api::SearchByTitleParams {
|
|
search_term,
|
|
max_nb_results: MAX_NB_SEARCH_RESULT,
|
|
},
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
if search_result.is_empty() {
|
|
display_message(Message::NoResults);
|
|
} else {
|
|
let ul_element = results_element.selector::<Element>("ul");
|
|
for recipe in search_result {
|
|
let li_element: Element = selector_and_clone("#hidden-templates-search li");
|
|
let a_element = li_element.selector::<Element>("a");
|
|
a_element
|
|
.set_attribute(
|
|
"href",
|
|
&format!("/{}/recipe/view/{}", get_current_lang(), recipe.recipe_id),
|
|
)
|
|
.unwrap();
|
|
a_element.set_inner_html(&recipe.title_highlighted);
|
|
ul_element.append_child(&li_element).unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
results_element
|
|
.style()
|
|
.set_property("display", "block")
|
|
.unwrap();
|
|
}
|
|
|
|
enum Message {
|
|
None,
|
|
TooFewCharacters,
|
|
NoResults,
|
|
}
|
|
|
|
fn display_message(message: Message) {
|
|
let message_element: HtmlDivElement = selector("#search .message");
|
|
|
|
for m in message_element.selector_all::<HtmlSpanElement>("span") {
|
|
m.style().set_property("display", "none").unwrap();
|
|
}
|
|
|
|
message_element
|
|
.style()
|
|
.set_property("display", "block")
|
|
.unwrap();
|
|
|
|
match message {
|
|
Message::TooFewCharacters => message_element
|
|
.selector::<HtmlSpanElement>(".to-small")
|
|
.style()
|
|
.set_property("display", "inline")
|
|
.unwrap(),
|
|
Message::NoResults => message_element
|
|
.selector::<HtmlSpanElement>(".no-results")
|
|
.style()
|
|
.set_property("display", "inline")
|
|
.unwrap(),
|
|
Message::None => message_element
|
|
.style()
|
|
.set_property("display", "none")
|
|
.unwrap(),
|
|
}
|
|
}
|