186 lines
6 KiB
Rust
186 lines
6 KiB
Rust
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(())
|
|
}
|