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().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 _: Result<(), JsValue> = 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 _: Result<(), JsValue> = 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 _: Result<(), JsValue> = 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 _: Result<(), JsValue> = 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().set(format!("Set: {key} = {value}"));
273 }
274 }))
275 }
276
277 pub fn on_local_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
287 Some(Rc::new(move |_: Event| {
288 let key: String = self.get_local_key().get();
289 let value: Option<String> = Self::local_storage_get(&key);
290 match value {
291 Some(v) => self.get_local_result().set(format!("Get: {key} = {v}")),
292 None => self
293 .get_local_result()
294 .set(format!("Key '{key}' not found")),
295 }
296 }))
297 }
298
299 pub fn on_local_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
309 Some(Rc::new(move |_: Event| {
310 let key: String = self.get_local_key().get();
311 Self::local_storage_remove(&key);
312 self.get_local_result().set(format!("Removed key: {key}"));
313 }))
314 }
315
316 pub fn on_session_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
326 Some(Rc::new(move |_: Event| {
327 let key: String = self.get_session_key().get();
328 let value: String = self.get_session_value().get();
329 if !key.is_empty() {
330 Self::session_storage_set(&key, &value);
331 self.get_session_result()
332 .set(format!("Set: {key} = {value}"));
333 }
334 }))
335 }
336
337 pub fn on_session_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
347 Some(Rc::new(move |_: Event| {
348 let key: String = self.get_session_key().get();
349 let value: Option<String> = Self::session_storage_get(&key);
350 match value {
351 Some(v) => self.get_session_result().set(format!("Get: {key} = {v}")),
352 None => self
353 .get_session_result()
354 .set(format!("Key '{key}' not found")),
355 }
356 }))
357 }
358
359 pub fn on_session_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
369 Some(Rc::new(move |_: Event| {
370 let key: String = self.get_session_key().get();
371 Self::session_storage_remove(&key);
372 self.get_session_result().set(format!("Removed key: {key}"));
373 }))
374 }
375
376 pub fn on_clipboard_copy(self) -> Option<Rc<dyn Fn(Event)>> {
386 Some(Rc::new(move |_: Event| {
387 let text: String = self.get_clipboard_text().get();
388 let text_clone: String = text.clone();
389 let result: Signal<String> = self.get_clipboard_result();
390 if text.is_empty() {
391 result.set("Please enter text to copy".to_string());
392 return;
393 }
394 let window: Window = window().expect("no global window exists");
395 let navigator: Navigator = window.navigator();
396 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
397 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
398 spawn_local(async move {
399 let success: bool = Self::clipboard_write_text(&text_clone).await;
400 if success {
401 result.set("Copied to clipboard!".to_string());
402 } else {
403 result.set("Failed to copy".to_string());
404 }
405 });
406 }
407 _ => {
408 result.set("Clipboard API not available (requires secure context)".to_string());
409 }
410 }
411 }))
412 }
413
414 pub fn on_clipboard_paste(self) -> Option<Rc<dyn Fn(Event)>> {
424 Some(Rc::new(move |_: Event| {
425 let result: Signal<String> = self.get_clipboard_result();
426 let window: Window = window().expect("no global window exists");
427 let navigator: Navigator = window.navigator();
428 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
429 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
430 spawn_local(async move {
431 let text: String = Self::clipboard_read_text().await;
432 result.set(format!("Pasted: {text}"));
433 });
434 }
435 _ => {
436 result.set("Clipboard API not available (requires secure context)".to_string());
437 }
438 }
439 }))
440 }
441
442 pub fn on_window_refresh_size(self) -> Option<Rc<dyn Fn(Event)>> {
452 Some(Rc::new(move |_: Event| {
453 let (width, height): (i32, i32) = Self::window_inner_size();
454 self.get_window_size().set(format!("{width} x {height}"));
455 }))
456 }
457
458 pub fn on_console_log(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
468 Some(Rc::new(move |_: Event| {
469 let raw: String = console_input.get();
470 let message: &str = if raw.is_empty() {
471 CONSOLE_LOG_DEFAULT_MESSAGE
472 } else {
473 &raw
474 };
475 Console::log(message);
476 }))
477 }
478
479 pub fn on_console_warn(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
489 Some(Rc::new(move |_: Event| {
490 let raw: String = console_input.get();
491 let message: &str = if raw.is_empty() {
492 CONSOLE_WARN_DEFAULT_MESSAGE
493 } else {
494 &raw
495 };
496 Console::warn(message);
497 }))
498 }
499
500 pub fn on_console_error(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
510 Some(Rc::new(move |_: Event| {
511 let raw: String = console_input.get();
512 let message: &str = if raw.is_empty() {
513 CONSOLE_ERROR_DEFAULT_MESSAGE
514 } else {
515 &raw
516 };
517 Console::error(message);
518 }))
519 }
520}
521
522impl Default for UseEuvBrowser {
524 fn default() -> Self {
525 let window_size_val: String = {
526 let (width, height): (i32, i32) = UseEuvBrowser::window_inner_size();
527 format!("{width} x {height}")
528 };
529 UseEuvBrowser {
530 local_key: App::use_signal(String::new),
531 local_value: App::use_signal(String::new),
532 local_result: App::use_signal(String::new),
533 session_key: App::use_signal(String::new),
534 session_value: App::use_signal(String::new),
535 session_result: App::use_signal(String::new),
536 clipboard_text: App::use_signal(String::new),
537 clipboard_result: App::use_signal(String::new),
538 window_size: App::use_signal(move || window_size_val.clone()),
539 user_agent: App::use_signal(UseEuvBrowser::navigator_user_agent),
540 language: App::use_signal(UseEuvBrowser::navigator_language),
541 location_url: App::use_signal(UseEuvBrowser::location_href),
542 location_origin_val: App::use_signal(UseEuvBrowser::location_origin),
543 location_pathname_val: App::use_signal(UseEuvBrowser::location_pathname),
544 console_input: App::use_signal(String::new),
545 }
546 }
547}