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(key: &str) -> Option<String> {
24 let window: Window = window().expect("no global window exists");
25 let storage: Storage = window.local_storage().ok()??;
26 storage.get_item(key).ok()?
27 }
28
29 pub fn local_storage_set(key: &str, value: &str) {
36 let window: Window = window().expect("no global window exists");
37 let storage: Storage = match window.local_storage() {
38 Ok(Some(local_storage)) => local_storage,
39 _ => return,
40 };
41 let _ = storage.set_item(key, value);
42 }
43
44 pub(crate) fn local_storage_remove(key: &str) {
50 let window: Window = window().expect("no global window exists");
51 let storage: Storage = match window.local_storage() {
52 Ok(Some(local_storage)) => local_storage,
53 _ => return,
54 };
55 let _ = storage.remove_item(key);
56 }
57
58 pub(crate) fn session_storage_get(key: &str) -> Option<String> {
68 let window: Window = window().expect("no global window exists");
69 let storage: Storage = window.session_storage().ok()??;
70 storage.get_item(key).ok()?
71 }
72
73 pub(crate) fn session_storage_set(key: &str, value: &str) {
80 let window: Window = window().expect("no global window exists");
81 let storage: Storage = match window.session_storage() {
82 Ok(Some(session_storage)) => session_storage,
83 _ => return,
84 };
85 let _ = storage.set_item(key, value);
86 }
87
88 pub(crate) fn session_storage_remove(key: &str) {
94 let window: Window = window().expect("no global window exists");
95 let storage: Storage = match window.session_storage() {
96 Ok(Some(session_storage)) => session_storage,
97 _ => return,
98 };
99 let _ = storage.remove_item(key);
100 }
101
102 pub(crate) async fn clipboard_read_text() -> String {
108 let window: Window = window().expect("no global window exists");
109 let navigator: Navigator = window.navigator();
110 match Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
111 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
112 let clipboard: Clipboard = navigator.clipboard();
113 let promise: Promise = clipboard.read_text();
114 let future: JsFuture = JsFuture::from(promise);
115 match future.await {
116 Ok(value) => value
117 .as_string()
118 .unwrap_or_else(|| "No text content".to_string()),
119 Err(_) => "Failed to read clipboard".to_string(),
120 }
121 }
122 _ => "Clipboard API not available (requires secure context)".to_string(),
123 }
124 }
125
126 pub(crate) async fn clipboard_write_text(text: &str) -> bool {
136 let window: Window = window().expect("no global window exists");
137 let navigator: Navigator = window.navigator();
138 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
139 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
140 let clipboard: Clipboard = navigator.clipboard();
141 let promise: Promise = clipboard.write_text(text);
142 let future: JsFuture = JsFuture::from(promise);
143 future.await.is_ok()
144 }
145 _ => false,
146 }
147 }
148
149 pub(crate) fn window_inner_size() -> (i32, i32) {
155 let window: Window = window().expect("no global window exists");
156 let width: i32 = window
157 .inner_width()
158 .ok()
159 .map(|value: JsValue| Number::from(value).value_of() as i32)
160 .unwrap_or_default();
161 let height: i32 = window
162 .inner_height()
163 .ok()
164 .map(|value: JsValue| Number::from(value).value_of() as i32)
165 .unwrap_or_default();
166 (width, height)
167 }
168
169 pub(crate) fn navigator_user_agent() -> String {
175 let window: Window = window().expect("no global window exists");
176 window
177 .navigator()
178 .user_agent()
179 .unwrap_or_else(|_: JsValue| "Unknown".to_string())
180 }
181
182 pub(crate) fn navigator_language() -> String {
188 let window: Window = window().expect("no global window exists");
189 window
190 .navigator()
191 .language()
192 .unwrap_or_else(|| "Unknown".to_string())
193 }
194
195 pub(crate) fn location_href() -> String {
201 let window: Window = window().expect("no global window exists");
202 window
203 .location()
204 .href()
205 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
206 }
207
208 pub(crate) fn location_origin() -> String {
214 let window: Window = window().expect("no global window exists");
215 window
216 .location()
217 .origin()
218 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
219 }
220
221 pub(crate) fn location_pathname() -> String {
227 let window: Window = window().expect("no global window exists");
228 window
229 .location()
230 .pathname()
231 .unwrap_or_else(|_error: JsValue| "Unknown".to_string())
232 }
233
234 pub fn on_local_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
244 Some(Rc::new(move |_: Event| {
245 let key: String = self.get_local_key().get();
246 let value: String = self.get_local_value().get();
247 if !key.is_empty() {
248 Self::local_storage_set(&key, &value);
249 self.get_local_result()
250 .set(format!("Set: {} = {}", key, value));
251 }
252 }))
253 }
254
255 pub fn on_local_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
265 Some(Rc::new(move |_: Event| {
266 let key: String = self.get_local_key().get();
267 let value: Option<String> = Self::local_storage_get(&key);
268 match value {
269 Some(v) => self.get_local_result().set(format!("Get: {} = {}", key, v)),
270 None => self
271 .get_local_result()
272 .set(format!("Key '{}' not found", key)),
273 }
274 }))
275 }
276
277 pub fn on_local_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
287 Some(Rc::new(move |_: Event| {
288 let key: String = self.get_local_key().get();
289 Self::local_storage_remove(&key);
290 self.get_local_result().set(format!("Removed key: {}", key));
291 }))
292 }
293
294 pub fn on_session_storage_set(self) -> Option<Rc<dyn Fn(Event)>> {
304 Some(Rc::new(move |_: Event| {
305 let key: String = self.get_session_key().get();
306 let value: String = self.get_session_value().get();
307 if !key.is_empty() {
308 Self::session_storage_set(&key, &value);
309 self.get_session_result()
310 .set(format!("Set: {} = {}", key, value));
311 }
312 }))
313 }
314
315 pub fn on_session_storage_get(self) -> Option<Rc<dyn Fn(Event)>> {
325 Some(Rc::new(move |_: Event| {
326 let key: String = self.get_session_key().get();
327 let value: Option<String> = Self::session_storage_get(&key);
328 match value {
329 Some(v) => self
330 .get_session_result()
331 .set(format!("Get: {} = {}", key, v)),
332 None => self
333 .get_session_result()
334 .set(format!("Key '{}' not found", key)),
335 }
336 }))
337 }
338
339 pub fn on_session_storage_remove(self) -> Option<Rc<dyn Fn(Event)>> {
349 Some(Rc::new(move |_: Event| {
350 let key: String = self.get_session_key().get();
351 Self::session_storage_remove(&key);
352 self.get_session_result()
353 .set(format!("Removed key: {}", key));
354 }))
355 }
356
357 pub fn on_clipboard_copy(self) -> Option<Rc<dyn Fn(Event)>> {
367 Some(Rc::new(move |_: Event| {
368 let text: String = self.get_clipboard_text().get();
369 let text_clone: String = text.clone();
370 let result: Signal<String> = self.get_clipboard_result();
371 if text.is_empty() {
372 result.set("Please enter text to copy".to_string());
373 return;
374 }
375 let window: Window = window().expect("no global window exists");
376 let navigator: Navigator = window.navigator();
377 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
378 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
379 spawn_local(async move {
380 let success: bool = Self::clipboard_write_text(&text_clone).await;
381 if success {
382 result.set("Copied to clipboard!".to_string());
383 } else {
384 result.set("Failed to copy".to_string());
385 }
386 });
387 }
388 _ => {
389 result.set("Clipboard API not available (requires secure context)".to_string());
390 }
391 }
392 }))
393 }
394
395 pub fn on_clipboard_paste(self) -> Option<Rc<dyn Fn(Event)>> {
405 Some(Rc::new(move |_: Event| {
406 let result: Signal<String> = self.get_clipboard_result();
407 let window: Window = window().expect("no global window exists");
408 let navigator: Navigator = window.navigator();
409 match js_sys::Reflect::get(&navigator, &JsValue::from_str("clipboard")) {
410 Ok(clipboard_obj) if !clipboard_obj.is_undefined() => {
411 spawn_local(async move {
412 let text: String = Self::clipboard_read_text().await;
413 result.set(format!("Pasted: {}", text));
414 });
415 }
416 _ => {
417 result.set("Clipboard API not available (requires secure context)".to_string());
418 }
419 }
420 }))
421 }
422
423 pub fn on_window_refresh_size(self) -> Option<Rc<dyn Fn(Event)>> {
433 Some(Rc::new(move |_: Event| {
434 let (width, height): (i32, i32) = Self::window_inner_size();
435 self.get_window_size()
436 .set(format!("{} x {}", width, height));
437 }))
438 }
439
440 pub fn on_console_log(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
450 Some(Rc::new(move |_: Event| {
451 let raw: String = console_input.get();
452 let message: &str = if raw.is_empty() {
453 CONSOLE_LOG_DEFAULT_MESSAGE
454 } else {
455 &raw
456 };
457 Console::log(message);
458 }))
459 }
460
461 pub fn on_console_warn(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
471 Some(Rc::new(move |_: Event| {
472 let raw: String = console_input.get();
473 let message: &str = if raw.is_empty() {
474 CONSOLE_WARN_DEFAULT_MESSAGE
475 } else {
476 &raw
477 };
478 Console::warn(message);
479 }))
480 }
481
482 pub fn on_console_error(console_input: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
492 Some(Rc::new(move |_: Event| {
493 let raw: String = console_input.get();
494 let message: &str = if raw.is_empty() {
495 CONSOLE_ERROR_DEFAULT_MESSAGE
496 } else {
497 &raw
498 };
499 Console::error(message);
500 }))
501 }
502}
503
504impl Default for UseEuvBrowser {
506 fn default() -> Self {
507 let window_size_val: String = {
508 let (width, height): (i32, i32) = UseEuvBrowser::window_inner_size();
509 format!("{} x {}", width, height)
510 };
511 UseEuvBrowser {
512 local_key: App::use_signal(String::new),
513 local_value: App::use_signal(String::new),
514 local_result: App::use_signal(String::new),
515 session_key: App::use_signal(String::new),
516 session_value: App::use_signal(String::new),
517 session_result: App::use_signal(String::new),
518 clipboard_text: App::use_signal(String::new),
519 clipboard_result: App::use_signal(String::new),
520 window_size: App::use_signal(move || window_size_val.clone()),
521 user_agent: App::use_signal(UseEuvBrowser::navigator_user_agent),
522 language: App::use_signal(UseEuvBrowser::navigator_language),
523 location_url: App::use_signal(UseEuvBrowser::location_href),
524 location_origin_val: App::use_signal(UseEuvBrowser::location_origin),
525 location_pathname_val: App::use_signal(UseEuvBrowser::location_pathname),
526 console_input: App::use_signal(String::new),
527 }
528 }
529}