euv_ui/component/browser/hook/
impl.rs1use crate::*;
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().expect("no global window exists");
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 window: Window = window().expect("no global window exists");
44 let storage: Storage = match window.local_storage() {
45 Ok(Some(local_storage)) => local_storage,
46 _ => return,
47 };
48 let _ = storage.set_item(key.as_ref(), value.as_ref());
49 }
50
51 pub(crate) fn local_storage_remove<K>(key: K)
57 where
58 K: AsRef<str>,
59 {
60 let window: Window = window().expect("no global window exists");
61 let storage: Storage = match window.local_storage() {
62 Ok(Some(local_storage)) => local_storage,
63 _ => return,
64 };
65 let _ = storage.remove_item(key.as_ref());
66 }
67
68 pub(crate) fn session_storage_get<K>(key: K) -> Option<String>
78 where
79 K: AsRef<str>,
80 {
81 let window: Window = window().expect("no global window exists");
82 let storage: Storage = window.session_storage().ok()??;
83 storage.get_item(key.as_ref()).ok()?
84 }
85
86 pub(crate) fn session_storage_set<K, V>(key: K, value: V)
93 where
94 K: AsRef<str>,
95 V: AsRef<str>,
96 {
97 let window: Window = window().expect("no global window exists");
98 let storage: Storage = match window.session_storage() {
99 Ok(Some(session_storage)) => session_storage,
100 _ => return,
101 };
102 let _ = storage.set_item(key.as_ref(), value.as_ref());
103 }
104
105 pub(crate) fn session_storage_remove<K>(key: K)
111 where
112 K: AsRef<str>,
113 {
114 let window: Window = window().expect("no global window exists");
115 let storage: Storage = match window.session_storage() {
116 Ok(Some(session_storage)) => session_storage,
117 _ => return,
118 };
119 let _ = storage.remove_item(key.as_ref());
120 }
121
122 pub(crate) async fn clipboard_read_text() -> String {
128 let window: Window = window().expect("no global window exists");
129 let navigator: Navigator = window.navigator();
130 match Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
131 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
132 let clipboard: Clipboard = navigator.clipboard();
133 let promise: Promise = clipboard.read_text();
134 let future: JsFuture = JsFuture::from(promise);
135 match future.await {
136 Ok(value) => value
137 .as_string()
138 .unwrap_or_else(|| "No text content".to_string()),
139 Err(_) => "Failed to read clipboard".to_string(),
140 }
141 }
142 _ => "Clipboard API not available (requires secure context)".to_string(),
143 }
144 }
145
146 pub(crate) async fn clipboard_write_text<T>(text: T) -> bool
156 where
157 T: AsRef<str>,
158 {
159 let window: Window = window().expect("no global window exists");
160 let navigator: Navigator = window.navigator();
161 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
162 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
163 let clipboard: Clipboard = navigator.clipboard();
164 let promise: Promise = clipboard.write_text(text.as_ref());
165 let future: JsFuture = JsFuture::from(promise);
166 future.await.is_ok()
167 }
168 _ => false,
169 }
170 }
171
172 pub(crate) fn window_inner_size() -> (i32, i32) {
178 let window: Window = window().expect("no global window exists");
179 let width: i32 = window
180 .inner_width()
181 .ok()
182 .map(|value: JsValue| Number::from(value).value_of() as i32)
183 .unwrap_or_default();
184 let height: i32 = window
185 .inner_height()
186 .ok()
187 .map(|value: JsValue| Number::from(value).value_of() as i32)
188 .unwrap_or_default();
189 (width, height)
190 }
191
192 pub(crate) fn navigator_user_agent() -> String {
198 let window: Window = window().expect("no global window exists");
199 window
200 .navigator()
201 .user_agent()
202 .unwrap_or_else(|_: JsValue| "Unknown".to_string())
203 }
204
205 pub(crate) fn navigator_language() -> String {
211 let window: Window = window().expect("no global window exists");
212 window
213 .navigator()
214 .language()
215 .unwrap_or_else(|| "Unknown".to_string())
216 }
217
218 pub(crate) fn location_href() -> String {
224 let window: Window = window().expect("no global window exists");
225 window
226 .location()
227 .href()
228 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
229 }
230
231 pub(crate) fn location_origin() -> String {
237 let window: Window = window().expect("no global window exists");
238 window
239 .location()
240 .origin()
241 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
242 }
243
244 pub(crate) fn location_pathname() -> String {
250 let window: Window = window().expect("no global window exists");
251 window
252 .location()
253 .pathname()
254 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
255 }
256
257 pub fn on_local_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
267 Some(Rc::new(move |_: Event| {
268 let key: String = self.get_local_key().get();
269 let value: String = self.get_local_value().get();
270 if !key.is_empty() {
271 Self::local_storage_set(&key, &value);
272 self.get_local_result()
273 .set(format!("Set: {} = {}", key, value));
274 }
275 }))
276 }
277
278 pub fn on_local_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
288 Some(Rc::new(move |_: Event| {
289 let key: String = self.get_local_key().get();
290 let value: Option<String> = Self::local_storage_get(&key);
291 match value {
292 Some(v) => self.get_local_result().set(format!("Get: {} = {}", key, v)),
293 None => self
294 .get_local_result()
295 .set(format!("Key '{}' not found", key)),
296 }
297 }))
298 }
299
300 pub fn on_local_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
310 Some(Rc::new(move |_: Event| {
311 let key: String = self.get_local_key().get();
312 Self::local_storage_remove(&key);
313 self.get_local_result().set(format!("Removed key: {}", key));
314 }))
315 }
316
317 pub fn on_session_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
327 Some(Rc::new(move |_: Event| {
328 let key: String = self.get_session_key().get();
329 let value: String = self.get_session_value().get();
330 if !key.is_empty() {
331 Self::session_storage_set(&key, &value);
332 self.get_session_result()
333 .set(format!("Set: {} = {}", key, value));
334 }
335 }))
336 }
337
338 pub fn on_session_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
348 Some(Rc::new(move |_: Event| {
349 let key: String = self.get_session_key().get();
350 let value: Option<String> = Self::session_storage_get(&key);
351 match value {
352 Some(v) => self
353 .get_session_result()
354 .set(format!("Get: {} = {}", key, v)),
355 None => self
356 .get_session_result()
357 .set(format!("Key '{}' not found", key)),
358 }
359 }))
360 }
361
362 pub fn on_session_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
372 Some(Rc::new(move |_: Event| {
373 let key: String = self.get_session_key().get();
374 Self::session_storage_remove(&key);
375 self.get_session_result()
376 .set(format!("Removed key: {}", key));
377 }))
378 }
379
380 pub fn on_clipboard_copy(self) -> Option<Rc<dyn Fn(Event)>> {
390 Some(Rc::new(move |_: Event| {
391 let text: String = self.get_clipboard_text().get();
392 let text_clone: String = text.clone();
393 let result: Signal<String> = self.get_clipboard_result();
394 if text.is_empty() {
395 result.set("Please enter text to copy".to_string());
396 return;
397 }
398 let window: Window = window().expect("no global window exists");
399 let navigator: Navigator = window.navigator();
400 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
401 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
402 spawn_local(async move {
403 let success: bool = Self::clipboard_write_text(&text_clone).await;
404 if success {
405 result.set("Copied to clipboard!".to_string());
406 } else {
407 result.set("Failed to copy".to_string());
408 }
409 });
410 }
411 _ => {
412 result.set("Clipboard API not available (requires secure context)".to_string());
413 }
414 }
415 }))
416 }
417
418 pub fn on_clipboard_paste(self) -> Option<Rc<dyn Fn(Event)>> {
428 Some(Rc::new(move |_: Event| {
429 let result: Signal<String> = self.get_clipboard_result();
430 let window: Window = window().expect("no global window exists");
431 let navigator: Navigator = window.navigator();
432 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
433 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
434 spawn_local(async move {
435 let text: String = Self::clipboard_read_text().await;
436 result.set(format!("Pasted: {}", text));
437 });
438 }
439 _ => {
440 result.set("Clipboard API not available (requires secure context)".to_string());
441 }
442 }
443 }))
444 }
445
446 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()
459 .set(format!("{} x {}", width, height));
460 }))
461 }
462
463 pub fn on_console_log(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
473 Some(Rc::new(move |_: Event| {
474 let raw: String = console_input.get();
475 let message: &str = if raw.is_empty() {
476 CONSOLE_LOG_DEFAULT_MESSAGE
477 } else {
478 &raw
479 };
480 Console::log(message);
481 }))
482 }
483
484 pub fn on_console_warn(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
494 Some(Rc::new(move |_: Event| {
495 let raw: String = console_input.get();
496 let message: &str = if raw.is_empty() {
497 CONSOLE_WARN_DEFAULT_MESSAGE
498 } else {
499 &raw
500 };
501 Console::warn(message);
502 }))
503 }
504
505 pub fn on_console_error(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
515 Some(Rc::new(move |_: Event| {
516 let raw: String = console_input.get();
517 let message: &str = if raw.is_empty() {
518 CONSOLE_ERROR_DEFAULT_MESSAGE
519 } else {
520 &raw
521 };
522 Console::error(message);
523 }))
524 }
525}
526
527impl Default for UseEuvBrowser {
529 fn default() -> Self {
530 let window_size_val: String = {
531 let (width, height): (i32, i32) = UseEuvBrowser::window_inner_size();
532 format!("{} x {}", width, 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}