euv_ui/component/browser/hook/
impl.rs1use super::*;
2
3impl UseEuvBrowser {
5 pub fn use_browser_state() -> UseEuvBrowser {
11 UseEuvBrowser::default()
12 }
13
14 pub fn local_storage_get<K>(key: K) -> Option<String>
24 where
25 K: AsRef<str>,
26 {
27 let window: Window = window()?;
28 let storage: Storage = window.local_storage().ok()??;
29 storage.get_item(key.as_ref()).ok()?
30 }
31
32 pub fn local_storage_set<K, V>(key: K, value: V)
39 where
40 K: AsRef<str>,
41 V: AsRef<str>,
42 {
43 let Some(window) = window() else {
44 return;
45 };
46 let storage: Storage = match window.local_storage() {
47 Ok(Some(local_storage)) => local_storage,
48 _ => return,
49 };
50 let _: Result<(), JsValue> = storage.set_item(key.as_ref(), value.as_ref());
51 }
52
53 pub(crate) fn local_storage_remove<K>(key: K)
59 where
60 K: AsRef<str>,
61 {
62 let Some(window) = window() else {
63 return;
64 };
65 let storage: Storage = match window.local_storage() {
66 Ok(Some(local_storage)) => local_storage,
67 _ => return,
68 };
69 let _: Result<(), JsValue> = storage.remove_item(key.as_ref());
70 }
71
72 pub(crate) fn session_storage_get<K>(key: K) -> Option<String>
82 where
83 K: AsRef<str>,
84 {
85 let window: Window = window()?;
86 let storage: Storage = window.session_storage().ok()??;
87 storage.get_item(key.as_ref()).ok()?
88 }
89
90 pub(crate) fn session_storage_set<K, V>(key: K, value: V)
97 where
98 K: AsRef<str>,
99 V: AsRef<str>,
100 {
101 let Some(window) = window() else {
102 return;
103 };
104 let storage: Storage = match window.session_storage() {
105 Ok(Some(session_storage)) => session_storage,
106 _ => return,
107 };
108 let _: Result<(), JsValue> = storage.set_item(key.as_ref(), value.as_ref());
109 }
110
111 pub(crate) fn session_storage_remove<K>(key: K)
117 where
118 K: AsRef<str>,
119 {
120 let Some(window) = window() else {
121 return;
122 };
123 let storage: Storage = match window.session_storage() {
124 Ok(Some(session_storage)) => session_storage,
125 _ => return,
126 };
127 let _: Result<(), JsValue> = storage.remove_item(key.as_ref());
128 }
129
130 pub(crate) async fn clipboard_read_text() -> String {
136 let Some(window) = window() else {
137 return String::new();
138 };
139 let navigator: Navigator = window.navigator();
140 match Reflect::get(
141 &navigator,
142 &JsValue::from_str(BROWSER_NAVIGATOR_CLIPBOARD_KEY),
143 ) {
144 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
145 let clipboard: Clipboard = navigator.clipboard();
146 let promise: Promise = clipboard.read_text();
147 let future: JsFuture = JsFuture::from(promise);
148 match future.await {
149 Ok(value) => value
150 .as_string()
151 .unwrap_or_else(|| BROWSER_CLIPBOARD_NO_TEXT_CONTENT.to_string()),
152 Err(_) => BROWSER_CLIPBOARD_READ_FAILED.to_string(),
153 }
154 }
155 _ => BROWSER_CLIPBOARD_UNAVAILABLE.to_string(),
156 }
157 }
158
159 pub(crate) async fn clipboard_write_text<T>(text: T) -> bool
169 where
170 T: AsRef<str>,
171 {
172 let Some(window) = window() else {
173 return false;
174 };
175 let navigator: Navigator = window.navigator();
176 match js_sys::Reflect::get(
177 &navigator,
178 &JsValue::from_str(BROWSER_NAVIGATOR_CLIPBOARD_KEY),
179 ) {
180 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
181 let clipboard: Clipboard = navigator.clipboard();
182 let promise: Promise = clipboard.write_text(text.as_ref());
183 let future: JsFuture = JsFuture::from(promise);
184 future.await.is_ok()
185 }
186 _ => false,
187 }
188 }
189
190 pub(crate) fn window_inner_size() -> (i32, i32) {
196 let Some(window) = window() else {
197 return (0, 0);
198 };
199 let width: i32 = window
200 .inner_width()
201 .ok()
202 .map(|value: JsValue| Number::from(value).value_of() as i32)
203 .unwrap_or_default();
204 let height: i32 = window
205 .inner_height()
206 .ok()
207 .map(|value: JsValue| Number::from(value).value_of() as i32)
208 .unwrap_or_default();
209 (width, height)
210 }
211
212 pub(crate) fn navigator_user_agent() -> String {
218 let Some(window) = window() else {
219 return String::new();
220 };
221 window
222 .navigator()
223 .user_agent()
224 .unwrap_or_else(|_: JsValue| BROWSER_VALUE_UNKNOWN.to_string())
225 }
226
227 pub(crate) fn navigator_language() -> String {
233 let Some(window) = window() else {
234 return String::new();
235 };
236 window
237 .navigator()
238 .language()
239 .unwrap_or_else(|| BROWSER_VALUE_UNKNOWN.to_string())
240 }
241
242 pub(crate) fn location_href() -> String {
248 let Some(window) = window() else {
249 return String::new();
250 };
251 window
252 .location()
253 .href()
254 .unwrap_or_else(|_error: JsValue| BROWSER_VALUE_UNKNOWN.to_string())
255 }
256
257 pub(crate) fn location_origin() -> String {
263 let Some(window) = window() else {
264 return String::new();
265 };
266 window
267 .location()
268 .origin()
269 .unwrap_or_else(|_error: JsValue| BROWSER_VALUE_UNKNOWN.to_string())
270 }
271
272 pub(crate) fn location_pathname() -> String {
278 let Some(window) = window() else {
279 return String::new();
280 };
281 window
282 .location()
283 .pathname()
284 .unwrap_or_else(|_error: JsValue| BROWSER_VALUE_UNKNOWN.to_string())
285 }
286
287 pub fn on_local_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
293 Some(Rc::new(move |_: Event| {
294 let key: String = self.get_local_key().get();
295 let value: String = self.get_local_value().get();
296 if !key.is_empty() {
297 Self::local_storage_set(&key, &value);
298 self.get_local_result().set(format!("Set: {key} = {value}"));
299 }
300 }))
301 }
302
303 pub fn on_local_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
309 Some(Rc::new(move |_: Event| {
310 let key: String = self.get_local_key().get();
311 let value: Option<String> = Self::local_storage_get(&key);
312 match value {
313 Some(v) => self.get_local_result().set(format!("Get: {key} = {v}")),
314 None => self
315 .get_local_result()
316 .set(format!("Key '{key}' not found")),
317 }
318 }))
319 }
320
321 pub fn on_local_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
327 Some(Rc::new(move |_: Event| {
328 let key: String = self.get_local_key().get();
329 Self::local_storage_remove(&key);
330 self.get_local_result().set(format!("Removed key: {key}"));
331 }))
332 }
333
334 pub fn on_session_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
340 Some(Rc::new(move |_: Event| {
341 let key: String = self.get_session_key().get();
342 let value: String = self.get_session_value().get();
343 if !key.is_empty() {
344 Self::session_storage_set(&key, &value);
345 self.get_session_result()
346 .set(format!("Set: {key} = {value}"));
347 }
348 }))
349 }
350
351 pub fn on_session_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
357 Some(Rc::new(move |_: Event| {
358 let key: String = self.get_session_key().get();
359 let value: Option<String> = Self::session_storage_get(&key);
360 match value {
361 Some(v) => self.get_session_result().set(format!("Get: {key} = {v}")),
362 None => self
363 .get_session_result()
364 .set(format!("Key '{key}' not found")),
365 }
366 }))
367 }
368
369 pub fn on_session_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
375 Some(Rc::new(move |_: Event| {
376 let key: String = self.get_session_key().get();
377 Self::session_storage_remove(&key);
378 self.get_session_result().set(format!("Removed key: {key}"));
379 }))
380 }
381
382 pub fn on_clipboard_copy(self) -> Option<Rc<dyn Fn(Event)>> {
388 Some(Rc::new(move |_: Event| {
389 let text: String = self.get_clipboard_text().get();
390 let text_clone: String = text.clone();
391 let result: Signal<String> = self.get_clipboard_result();
392 if text.is_empty() {
393 result.set(BROWSER_COPY_EMPTY_TEXT.to_string());
394 return;
395 }
396 let Some(window) = window() else {
397 return;
398 };
399 let navigator: Navigator = window.navigator();
400 match js_sys::Reflect::get(
401 &navigator,
402 &JsValue::from_str(BROWSER_NAVIGATOR_CLIPBOARD_KEY),
403 ) {
404 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
405 spawn_local(async move {
406 let success: bool = Self::clipboard_write_text(&text_clone).await;
407 if success {
408 result.set(BROWSER_COPY_SUCCEEDED.to_string());
409 } else {
410 result.set(BROWSER_COPY_FAILED.to_string());
411 }
412 });
413 }
414 _ => {
415 result.set(BROWSER_CLIPBOARD_UNAVAILABLE.to_string());
416 }
417 }
418 }))
419 }
420
421 pub fn on_clipboard_paste(self) -> Option<Rc<dyn Fn(Event)>> {
427 Some(Rc::new(move |_: Event| {
428 let result: Signal<String> = self.get_clipboard_result();
429 let Some(window) = window() else {
430 return;
431 };
432 let navigator: Navigator = window.navigator();
433 match js_sys::Reflect::get(
434 &navigator,
435 &JsValue::from_str(BROWSER_NAVIGATOR_CLIPBOARD_KEY),
436 ) {
437 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
438 spawn_local(async move {
439 let text: String = Self::clipboard_read_text().await;
440 result.set(format!("Pasted: {text}"));
441 });
442 }
443 _ => {
444 result.set(BROWSER_CLIPBOARD_UNAVAILABLE.to_string());
445 }
446 }
447 }))
448 }
449
450 pub fn on_window_refresh_size(self) -> Option<Rc<dyn Fn(Event)>> {
456 Some(Rc::new(move |_: Event| {
457 let (width, height): (i32, i32) = Self::window_inner_size();
458 self.get_window_size().set(format!("{width} x {height}"));
459 }))
460 }
461
462 pub fn on_console_log(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
472 Some(Rc::new(move |_: Event| {
473 let raw: String = console_input.get();
474 let message: &str = if raw.is_empty() {
475 CONSOLE_LOG_DEFAULT_MESSAGE
476 } else {
477 &raw
478 };
479 Console::log(message);
480 }))
481 }
482
483 pub fn on_console_warn(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
493 Some(Rc::new(move |_: Event| {
494 let raw: String = console_input.get();
495 let message: &str = if raw.is_empty() {
496 CONSOLE_WARN_DEFAULT_MESSAGE
497 } else {
498 &raw
499 };
500 Console::warn(message);
501 }))
502 }
503
504 pub fn on_console_error(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
514 Some(Rc::new(move |_: Event| {
515 let raw: String = console_input.get();
516 let message: &str = if raw.is_empty() {
517 CONSOLE_ERROR_DEFAULT_MESSAGE
518 } else {
519 &raw
520 };
521 Console::error(message);
522 }))
523 }
524}
525
526impl Default for UseEuvBrowser {
528 fn default() -> Self {
530 let window_size_val: String = {
531 let (width, height): (i32, i32) = UseEuvBrowser::window_inner_size();
532 format!("{width} x {height}")
533 };
534 UseEuvBrowser {
535 local_key: App::use_signal(String::new),
536 local_value: App::use_signal(String::new),
537 local_result: App::use_signal(String::new),
538 session_key: App::use_signal(String::new),
539 session_value: App::use_signal(String::new),
540 session_result: App::use_signal(String::new),
541 clipboard_text: App::use_signal(String::new),
542 clipboard_result: App::use_signal(String::new),
543 window_size: App::use_signal(move || window_size_val.clone()),
544 user_agent: App::use_signal(UseEuvBrowser::navigator_user_agent),
545 language: App::use_signal(UseEuvBrowser::navigator_language),
546 location_url: App::use_signal(UseEuvBrowser::location_href),
547 location_origin_val: App::use_signal(UseEuvBrowser::location_origin),
548 location_pathname_val: App::use_signal(UseEuvBrowser::location_pathname),
549 console_input: App::use_signal(String::new),
550 }
551 }
552}