From 2ad8fd6f43f9465e495cabb3bee75defa7e078f5 Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sat, 13 Jul 2024 21:03:16 +0900 Subject: [PATCH 1/6] Support query string Wasm example --- examples/wasm/Cargo.toml | 22 +++++++++++----------- examples/wasm/src/lib.rs | 24 ++++++++++++++++++------ vaporetto/src/dict_model.rs | 1 + 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index b4bea139..067bccb8 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -4,20 +4,20 @@ version = "0.1.0" edition = "2021" [dependencies] -gloo-worker = "0.2.1" # MIT or Apache-2.0 -i18n-embed = { version = "0.13.8", features = ["fluent-system", "web-sys-requester"]} # MIT -i18n-embed-fl = "0.6.5" # MIT -once_cell = "1.17.0" # MIT or Apache-2.0 -ouroboros = "0.17.2" # MIT or Apache-2.0 -rust-embed = "6.4.2" # MIT -ruzstd = "0.5.0" # MIT +gloo-worker = "0.5.0" # MIT or Apache-2.0 +i18n-embed = { version = "0.14.1", features = ["fluent-system", "web-sys-requester"]} # MIT +i18n-embed-fl = "0.8.0" # MIT +once_cell = "1.19.0" # MIT or Apache-2.0 +ouroboros = "0.18.4" # MIT or Apache-2.0 +rust-embed = "8.5.0" # MIT +ruzstd = "0.7.0" # MIT serde = "1" # MIT or Apache-2.0 -unic-langid = { version = "0.9.1", features = ["macros"] } # MIT or Apache-2.0 +unic-langid = { version = "0.9.5", features = ["macros"] } # MIT or Apache-2.0 vaporetto = { path = "../../vaporetto", default-features = false, features = ["std", "cache-type-score", "fix-weight-length", "tag-prediction"] } # MIT or Apache-2.0 vaporetto_rules = { path = "../../vaporetto_rules" } # MIT or Apache-2.0 -wasm-bindgen = "0.2.83" # MIT or Apache-2.0 -web-sys = { version = "0.3.61", features = ["Event", "EventTarget", "InputEvent"] } # MIT or Apache-2.0 -yew = { version = "0.20", features = ["csr"] } # MIT or Apache-2.0 +wasm-bindgen = "0.2.92" # MIT or Apache-2.0 +web-sys = { version = "0.3.69", features = ["Event", "EventTarget", "InputEvent"] } # MIT or Apache-2.0 +yew = { version = "0.21", features = ["csr"] } # MIT or Apache-2.0 [profile.release] panic = "abort" diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 7cece264..f7ca8654 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -3,6 +3,7 @@ pub mod i18n; pub mod text_input; pub mod token_view; +use std::borrow::Cow; use std::io::Read; use std::rc::Rc; @@ -14,6 +15,7 @@ use vaporetto_rules::{ string_filters::KyteaFullwidthFilter, SentenceFilter, StringFilter, }; +use web_sys::UrlSearchParams; use yew::{html, Component, Context, Html}; use crate::text_input::TextInput; @@ -97,10 +99,14 @@ impl Worker for VaporettoWorker { .boundaries_mut() .copy_from_slice(fields.sentence_filtered.boundaries()); fields.sentence_orig.reset_tags(n_tags); - fields + for (d, s) in fields .sentence_orig .tags_mut() - .clone_from_slice(fields.sentence_filtered.tags()); + .iter_mut() + .zip(fields.sentence_filtered.tags()) + { + *d = s.as_ref().map(|x| Cow::Owned(x.to_string())); + } }); let tokens = self @@ -150,13 +156,19 @@ impl Component for App { }) .spawn("./vaporetto_worker.js"); - // Sends a dummy message. - // The first response indicates that the worker is ready. - bridge.send(String::new()); + let text = web_sys::window() + .unwrap() + .location() + .search() + .ok() + .and_then(|s| UrlSearchParams::new_with_str(&s).ok()) + .and_then(|q| q.get("text")) + .unwrap_or_else(String::new); + bridge.send(text.clone()); Self { bridge, - text: String::new().into(), + text: text.into(), tokens: None, n_tags: 0, } diff --git a/vaporetto/src/dict_model.rs b/vaporetto/src/dict_model.rs index 23b43a21..9c81be03 100644 --- a/vaporetto/src/dict_model.rs +++ b/vaporetto/src/dict_model.rs @@ -5,6 +5,7 @@ use bincode::{Decode, Encode}; use crate::errors::{Result, VaporettoError}; +#[cfg(feature = "kytea")] #[derive(Clone, Copy, Default)] pub struct DictWeight { pub right: i32, From 46923bb9464a820b38c962f02a59d7d72d649c21 Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sun, 14 Jul 2024 00:11:10 +0900 Subject: [PATCH 2/6] Add copy link button --- examples/wasm/Cargo.toml | 5 +- examples/wasm/index.html | 25 +++++++++ examples/wasm/src/lib.rs | 22 +++----- examples/wasm/src/text_input.rs | 94 ++++++++++++++++++++++++++------- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 067bccb8..3156717f 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -4,9 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] +gloo-timers = "0.3.0" # MIT or Apache-2.0 gloo-worker = "0.5.0" # MIT or Apache-2.0 i18n-embed = { version = "0.14.1", features = ["fluent-system", "web-sys-requester"]} # MIT i18n-embed-fl = "0.8.0" # MIT +js-sys = "0.3.69" # MIT or Apache-2.0 once_cell = "1.19.0" # MIT or Apache-2.0 ouroboros = "0.18.4" # MIT or Apache-2.0 rust-embed = "8.5.0" # MIT @@ -16,7 +18,8 @@ unic-langid = { version = "0.9.5", features = ["macros"] } # MIT or Apache-2.0 vaporetto = { path = "../../vaporetto", default-features = false, features = ["std", "cache-type-score", "fix-weight-length", "tag-prediction"] } # MIT or Apache-2.0 vaporetto_rules = { path = "../../vaporetto_rules" } # MIT or Apache-2.0 wasm-bindgen = "0.2.92" # MIT or Apache-2.0 -web-sys = { version = "0.3.69", features = ["Event", "EventTarget", "InputEvent"] } # MIT or Apache-2.0 +wasm-bindgen-futures = "0.4.42" # MIT or Apache-2.0 +web-sys = { version = "0.3.69", features = ["Clipboard", "Event", "EventTarget", "InputEvent"] } # MIT or Apache-2.0 yew = { version = "0.21", features = ["csr"] } # MIT or Apache-2.0 [profile.release] diff --git a/examples/wasm/index.html b/examples/wasm/index.html index cf73ed40..9ca034e6 100644 --- a/examples/wasm/index.html +++ b/examples/wasm/index.html @@ -29,6 +29,11 @@ color: #fff; } +html { + max-width: 1000px; + margin: 0 auto; +} + body { width: calc(100% - 20px); margin: 10px; @@ -39,6 +44,26 @@ text-align: right; } +.input-bar { + display: flex; + flex-direction: row; +} + +.input-bar button { + font-size: 14pt; + align-self: center; + background-color: #ffffff; + border: 1px solid #000000; +} + +.input-bar button:hover { + background-color: #dddddd; +} + +.input-bar button.copied { + background-color: #008800; +} + a { color: #000; } diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index f7ca8654..5982da45 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -198,22 +198,14 @@ impl Component for App {

-
- { - if self.tokens.is_some() { - html! { - - } - } else { - html!{ - - } - } + { + html! { + } -
+ } { if let Some(tokens) = &self.tokens { html! { diff --git a/examples/wasm/src/text_input.rs b/examples/wasm/src/text_input.rs index abbf546a..37f324a5 100644 --- a/examples/wasm/src/text_input.rs +++ b/examples/wasm/src/text_input.rs @@ -1,19 +1,21 @@ use std::rc::Rc; -use wasm_bindgen::{JsCast, UnwrapThrowExt}; -use web_sys::{Event, HtmlInputElement, InputEvent}; -use yew::{html, Callback, Component, Context, Html, NodeRef, Properties}; +use gloo_timers::callback::Timeout; +use wasm_bindgen_futures::JsFuture; +use web_sys::HtmlInputElement; +use yew::{html, platform::spawn_local, Callback, Component, Context, Html, NodeRef, Properties}; use crate::fl; #[derive(Clone, PartialEq, Properties)] pub struct Props { - pub value: Rc, + pub value: Option>, pub callback: Callback, } pub struct TextInput { - node_ref: NodeRef, + input_ref: NodeRef, + button_ref: NodeRef, } impl Component for TextInput { @@ -22,7 +24,8 @@ impl Component for TextInput { fn create(_ctx: &Context) -> Self { Self { - node_ref: NodeRef::default(), + input_ref: NodeRef::default(), + button_ref: NodeRef::default(), } } @@ -30,21 +33,72 @@ impl Component for TextInput { let Props { value, callback } = ctx.props(); let callback = callback.clone(); - let oninput = Callback::from(move |e: InputEvent| { - let event: Event = e.dyn_into().unwrap_throw(); - let event_target = event.target().unwrap_throw(); - let target: HtmlInputElement = event_target.dyn_into().unwrap_throw(); - callback.emit(target.value()); + let input_ref = self.input_ref.clone(); + let oninput = Callback::from(move |_| { + let input = input_ref.cast::().unwrap(); + callback.emit(input.value()); }); - html! { - + let input_ref = self.input_ref.clone(); + let button_ref = self.button_ref.clone(); + let clipboard_click = Callback::from(move |_| { + let input = input_ref.cast::().unwrap(); + if let Some(clipboard) = web_sys::window().unwrap().navigator().clipboard() { + let loc = web_sys::window().unwrap().location(); + let content = format!( + "{}{}?text={}", + loc.origin().unwrap(), + loc.pathname().unwrap(), + js_sys::encode_uri_component(&input.value()) + ); + let promise = clipboard.write_text(&content); + let button_ref = button_ref.clone(); + spawn_local(async move { + JsFuture::from(promise).await.unwrap(); + let button = button_ref.cast::().unwrap(); + button.set_class_name("copied"); + let button_ref = button_ref.clone(); + let timeout = Timeout::new(1000, move || { + let button = button_ref.cast::().unwrap(); + button.set_class_name(""); + }); + timeout.forget(); + }); + } + }); + if let Some(value) = value.as_ref() { + html! { +
+ + +
+ } + } else { + html! { +
+ + +
+ } } } @@ -54,7 +108,7 @@ impl Component for TextInput { fn rendered(&mut self, _ctx: &Context, first_render: bool) { if first_render { - if let Some(input) = self.node_ref.cast::() { + if let Some(input) = self.input_ref.cast::() { input.focus().unwrap(); } } From b1a251203499d18ee1626e566cb23eddb7a4fd95 Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sun, 14 Jul 2024 00:15:55 +0900 Subject: [PATCH 3/6] Add cargo settings --- examples/wasm/.cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/wasm/.cargo/config.toml diff --git a/examples/wasm/.cargo/config.toml b/examples/wasm/.cargo/config.toml new file mode 100644 index 00000000..84671750 --- /dev/null +++ b/examples/wasm/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["--cfg=web_sys_unstable_apis"] From 6577001b957d1ac82396e86ef72709ce2b96a7f3 Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sun, 14 Jul 2024 13:38:59 +0900 Subject: [PATCH 4/6] Downgrade ouroboros to 0.17.2 --- examples/wasm/Cargo.toml | 2 +- examples/wasm/src/lib.rs | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 3156717f..fc1e84e3 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,7 +10,7 @@ i18n-embed = { version = "0.14.1", features = ["fluent-system", "web-sys-request i18n-embed-fl = "0.8.0" # MIT js-sys = "0.3.69" # MIT or Apache-2.0 once_cell = "1.19.0" # MIT or Apache-2.0 -ouroboros = "0.18.4" # MIT or Apache-2.0 +ouroboros = "0.17.2" # MIT or Apache-2.0 rust-embed = "8.5.0" # MIT ruzstd = "0.7.0" # MIT serde = "1" # MIT or Apache-2.0 diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 5982da45..d7481d5c 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -3,7 +3,6 @@ pub mod i18n; pub mod text_input; pub mod token_view; -use std::borrow::Cow; use std::io::Read; use std::rc::Rc; @@ -93,20 +92,14 @@ impl Worker for VaporettoWorker { fields.sentence_orig.update_raw(msg).unwrap(); - let n_tags = fields.sentence_filtered.n_tags(); fields .sentence_orig .boundaries_mut() .copy_from_slice(fields.sentence_filtered.boundaries()); - fields.sentence_orig.reset_tags(n_tags); - for (d, s) in fields + fields .sentence_orig .tags_mut() - .iter_mut() - .zip(fields.sentence_filtered.tags()) - { - *d = s.as_ref().map(|x| Cow::Owned(x.to_string())); - } + .clone_from_slice(fields.sentence_filtered.tags()); }); let tokens = self From db5e45af903173779652fe24d8c9286af6e77c7a Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sun, 14 Jul 2024 13:54:35 +0900 Subject: [PATCH 5/6] Upgrade ouroboros to 0.18.4 with changing variable order --- examples/wasm/Cargo.toml | 2 +- examples/wasm/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index fc1e84e3..3156717f 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,7 +10,7 @@ i18n-embed = { version = "0.14.1", features = ["fluent-system", "web-sys-request i18n-embed-fl = "0.8.0" # MIT js-sys = "0.3.69" # MIT or Apache-2.0 once_cell = "1.19.0" # MIT or Apache-2.0 -ouroboros = "0.17.2" # MIT or Apache-2.0 +ouroboros = "0.18.4" # MIT or Apache-2.0 rust-embed = "8.5.0" # MIT ruzstd = "0.7.0" # MIT serde = "1" # MIT or Apache-2.0 diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index d7481d5c..458396f5 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -39,10 +39,10 @@ pub struct VaporettoWorker { #[borrows(predictor)] #[covariant] - sentence_orig: Sentence<'static, 'this>, + sentence_filtered: Sentence<'static, 'this>, #[borrows(predictor)] #[covariant] - sentence_filtered: Sentence<'static, 'this>, + sentence_orig: Sentence<'static, 'this>, } impl Worker for VaporettoWorker { From f0ee242007a4f4d05ba8d7524ff1010a58ec4230 Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Sun, 14 Jul 2024 13:56:04 +0900 Subject: [PATCH 6/6] fix --- examples/wasm/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 458396f5..be6fbef7 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -92,10 +92,12 @@ impl Worker for VaporettoWorker { fields.sentence_orig.update_raw(msg).unwrap(); + let n_tags = fields.sentence_filtered.n_tags(); fields .sentence_orig .boundaries_mut() .copy_from_slice(fields.sentence_filtered.boundaries()); + fields.sentence_orig.reset_tags(n_tags); fields .sentence_orig .tags_mut()