anagrams/web_gui/src/lib.rs

186 lines
6 KiB
Rust
Raw Normal View History

2023-02-24 09:32:06 +01:00
use std::sync::Mutex;
use wasm_bindgen::prelude::*;
use web_sys::{console, Event, HtmlElement, HtmlInputElement};
use anagrams::{AnagramDict, Dict};
static DICTIONNARY: Mutex<Option<AnagramDict>> = Mutex::new(None);
fn window() -> web_sys::Window {
web_sys::window().expect("no global `window` exists")
}
fn document() -> web_sys::Document {
window()
.document()
.expect("should have a document on window")
}
fn display_spinner() {
let result = document()
.get_element_by_id("spinner")
.expect("#spinner not found");
let style = result
.dyn_ref::<HtmlElement>()
.expect("Failed to cast #spinner to HtmlElement")
.style();
style
.set_property("display", "inline-block")
.expect("Failed to edit #spinner's CSS");
}
fn hide_spinner() {
let result = document()
.get_element_by_id("spinner")
.expect("#spinner not found");
let style = result
.dyn_ref::<HtmlElement>()
.expect("Failed to cast #spinner to HtmlElement")
.style();
style
.set_property("display", "none")
.expect("Failed to edit #spinner's CSS");
}
fn hide_ask_dict() {
let result = document()
.get_element_by_id("ask_dict")
.expect("#ask_dic not found");
let style = result
.dyn_ref::<HtmlElement>()
.expect("Failed to cast #ask_dict to HtmlElement")
.style();
console::log_1(&style);
style
.set_property("display", "none")
.expect("Failed to edit #ask_dict's CSS");
}
fn update_letters() {
let el = document()
.get_element_by_id("select_word")
.expect("#select_word not found");
let val = el
.dyn_ref::<HtmlInputElement>()
.expect("Failed to dyn cast to HtmlInputElement")
.value();
let result = document()
.get_element_by_id("result")
.expect("#result not found");
while let Some(child) = result.first_element_child() {
child.remove();
}
DICTIONNARY
.lock()
.expect("Failed to access DICTIONNARY")
.as_ref()
.map(|dict| dict.find(&val))
.flatten()
.map(|anagrms| {
for anagram in anagrms {
let val = document().create_element("li").unwrap();
val.set_text_content(Some(&anagram));
result.append_child(&val).unwrap();
}
});
}
fn load_dict(text: JsValue) {
display_spinner();
let text = text.as_string().expect("Failed to get content of the file");
let el = document()
.get_element_by_id("nb_wild_card")
.expect("#nb_wild_card not found");
let nb_wild_card = el
.dyn_ref::<HtmlInputElement>()
.expect("Failed to dyn cast #nb_wild_card to HtmlInputElement")
.value();
console::log_1(&(&nb_wild_card).into());
let dict = Dict::load_from_str(
&text,
nb_wild_card
.parse()
.expect("#nb_wild_card should be an interger"),
'?',
);
*DICTIONNARY.lock().expect("Failed to access DICTIONNARY") = Some((&dict).into());
hide_spinner();
hide_ask_dict();
update_letters();
}
// Called when the wasm module is instantiated
#[wasm_bindgen(start)]
fn main() -> Result<(), JsValue> {
let load_dict_c1 = Closure::<dyn FnMut(_)>::new(move |text: JsValue| load_dict(text));
let load_dict_c2 = Closure::<dyn FnMut(_)>::new(move |text: JsValue| load_dict(text));
let update_dict = Closure::<dyn FnMut(_)>::new(move |event: Event| {
display_spinner();
let target = event.target().expect("No target");
let _ = target
.dyn_ref::<HtmlInputElement>()
.expect("Failed to dyn cast to HtmlInputElement")
.files()
.expect("Failed to get files")
.get(0)
.expect("Failed to get first file")
.text()
.then(&load_dict_c1);
});
let update_nb_wild_card = Closure::<dyn FnMut(_)>::new(move |_: Event| {
let el = document()
.get_element_by_id("upload_dict")
.expect("#upload_dict not found");
let files = el
.dyn_ref::<HtmlInputElement>()
.expect("Failed to dyn cast to HtmlInputElement")
.files()
.expect("Failed to get files");
if files.length() > 0 {
display_spinner();
let _ = files
.get(0)
.expect("Failed to get first file")
.text()
.then(&load_dict_c2);
}
});
let update_letters_closure = Closure::<dyn FnMut(_)>::new(|_: Event| update_letters());
let input_dict = document()
.get_element_by_id("upload_dict")
.expect("#upload_dict not found");
input_dict
.dyn_ref::<HtmlInputElement>()
.expect("#upload_dict must be an <input type='file'>")
.add_event_listener_with_callback("change", update_dict.as_ref().unchecked_ref())
.expect("Failed to register event listener to #upload_dict");
let input_text = document()
.get_element_by_id("select_word")
.expect("#select_word not found");
input_text
.dyn_ref::<HtmlInputElement>()
.expect("#select_word must be an <input type='text'>")
.add_event_listener_with_callback("input", update_letters_closure.as_ref().unchecked_ref())
.expect("Failed to register event listener to #select_word");
let nb_wild_card = document()
.get_element_by_id("nb_wild_card")
.expect("#nb_wild_card not found");
nb_wild_card
.dyn_ref::<HtmlInputElement>()
.expect("#nb_wild_card must be an <input type='numver'>")
.add_event_listener_with_callback("change", update_nb_wild_card.as_ref().unchecked_ref())
.expect("Failed to register event listener to #nb_wild_card");
update_dict.forget(); // The callback will invalidate when the closure is dropped, this prevent it,
// at the cost of a "memory leak"
update_letters_closure.forget();
update_nb_wild_card.forget();
Ok(())
}