From 5bb8f85ee4d1c0e13ef8a965651f8700b47e3a2a Mon Sep 17 00:00:00 2001
From: Koichi Akabe
Date: Sun, 14 Jul 2024 16:19:26 +0900
Subject: [PATCH] Support query string in Wasm example (#128)
* Support query string Wasm example
* Add copy link button
* Add cargo settings
---
examples/wasm/.cargo/config.toml | 2 +
examples/wasm/Cargo.toml | 25 +++++----
examples/wasm/index.html | 25 +++++++++
examples/wasm/src/lib.rs | 41 +++++++-------
examples/wasm/src/text_input.rs | 94 +++++++++++++++++++++++++-------
vaporetto/src/dict_model.rs | 1 +
6 files changed, 136 insertions(+), 52 deletions(-)
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"]
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index b4bea139..3156717f 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -4,20 +4,23 @@ 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-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
+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
+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]
panic = "abort"
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 7cece264..be6fbef7 100644
--- a/examples/wasm/src/lib.rs
+++ b/examples/wasm/src/lib.rs
@@ -14,6 +14,7 @@ use vaporetto_rules::{
string_filters::KyteaFullwidthFilter,
SentenceFilter, StringFilter,
};
+use web_sys::UrlSearchParams;
use yew::{html, Component, Context, Html};
use crate::text_input::TextInput;
@@ -38,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 {
@@ -150,13 +151,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,
}
@@ -186,22 +193,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();
}
}
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,