1use crate::core::engine::EngineType;
21use std::fmt;
22use std::sync::{Arc, Mutex};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum DialogType {
27 Alert,
29 Confirm,
31 Prompt,
33 BeforeUnload,
35 Unknown,
37}
38
39impl fmt::Display for DialogType {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 DialogType::Alert => write!(f, "alert"),
43 DialogType::Confirm => write!(f, "confirm"),
44 DialogType::Prompt => write!(f, "prompt"),
45 DialogType::BeforeUnload => write!(f, "beforeunload"),
46 DialogType::Unknown => write!(f, "unknown"),
47 }
48 }
49}
50
51impl From<&str> for DialogType {
52 fn from(s: &str) -> Self {
53 match s.to_lowercase().as_str() {
54 "alert" => DialogType::Alert,
55 "confirm" => DialogType::Confirm,
56 "prompt" => DialogType::Prompt,
57 "beforeunload" => DialogType::BeforeUnload,
58 _ => DialogType::Unknown,
59 }
60 }
61}
62
63#[derive(Debug, Clone)]
68pub struct DialogEvent {
69 pub dialog_type: DialogType,
71 pub message: String,
73 pub default_value: Option<String>,
75}
76
77impl DialogEvent {
78 pub fn new(
80 dialog_type: DialogType,
81 message: impl Into<String>,
82 default_value: Option<String>,
83 ) -> Self {
84 Self {
85 dialog_type,
86 message: message.into(),
87 default_value,
88 }
89 }
90
91 pub fn from_str_type(
93 dialog_type: &str,
94 message: impl Into<String>,
95 default_value: Option<String>,
96 ) -> Self {
97 Self::new(DialogType::from(dialog_type), message, default_value)
98 }
99}
100
101pub type DialogHandler = Arc<dyn Fn(&DialogEvent) + Send + Sync>;
103
104#[derive(Clone)]
131pub struct DialogManager {
132 handlers: Arc<Mutex<Vec<DialogHandler>>>,
133 engine: EngineType,
134}
135
136impl fmt::Debug for DialogManager {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 let count = self.handlers.lock().map(|h| h.len()).unwrap_or(0);
139 f.debug_struct("DialogManager")
140 .field("engine", &self.engine)
141 .field("handler_count", &count)
142 .finish()
143 }
144}
145
146impl DialogManager {
147 pub fn new_with_engine(engine: EngineType) -> Self {
149 Self {
150 handlers: Arc::new(Mutex::new(Vec::new())),
151 engine,
152 }
153 }
154
155 pub fn new() -> Self {
157 Self::new_with_engine(EngineType::Chromiumoxide)
158 }
159
160 pub fn on_dialog<F>(&mut self, handler: F)
170 where
171 F: Fn(&DialogEvent) + Send + Sync + 'static,
172 {
173 let mut handlers = self.handlers.lock().expect("lock poisoned");
174 handlers.push(Arc::new(handler));
175 }
176
177 pub fn clear_dialog_handlers(&mut self) {
179 let mut handlers = self.handlers.lock().expect("lock poisoned");
180 handlers.clear();
181 }
182
183 pub fn handler_count(&self) -> usize {
185 self.handlers.lock().map(|h| h.len()).unwrap_or(0)
186 }
187
188 pub fn dispatch(&self, event: &DialogEvent) {
198 let handlers = self.handlers.lock().expect("lock poisoned");
199 for handler in handlers.iter() {
200 handler(event);
201 }
202 }
203
204 pub fn engine(&self) -> EngineType {
206 self.engine
207 }
208}
209
210impl Default for DialogManager {
211 fn default() -> Self {
212 Self::new()
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn dialog_type_from_str() {
222 assert_eq!(DialogType::from("alert"), DialogType::Alert);
223 assert_eq!(DialogType::from("confirm"), DialogType::Confirm);
224 assert_eq!(DialogType::from("prompt"), DialogType::Prompt);
225 assert_eq!(DialogType::from("beforeunload"), DialogType::BeforeUnload);
226 assert_eq!(DialogType::from("unknown_type"), DialogType::Unknown);
227 }
228
229 #[test]
230 fn dialog_type_display() {
231 assert_eq!(DialogType::Alert.to_string(), "alert");
232 assert_eq!(DialogType::Confirm.to_string(), "confirm");
233 assert_eq!(DialogType::Prompt.to_string(), "prompt");
234 assert_eq!(DialogType::BeforeUnload.to_string(), "beforeunload");
235 assert_eq!(DialogType::Unknown.to_string(), "unknown");
236 }
237
238 #[test]
239 fn dialog_type_case_insensitive() {
240 assert_eq!(DialogType::from("ALERT"), DialogType::Alert);
241 assert_eq!(DialogType::from("Confirm"), DialogType::Confirm);
242 }
243
244 #[test]
245 fn dialog_event_new() {
246 let event = DialogEvent::new(DialogType::Alert, "Hello!", None);
247 assert_eq!(event.dialog_type, DialogType::Alert);
248 assert_eq!(event.message, "Hello!");
249 assert!(event.default_value.is_none());
250 }
251
252 #[test]
253 fn dialog_event_from_str_type() {
254 let event = DialogEvent::from_str_type("confirm", "Are you sure?", None);
255 assert_eq!(event.dialog_type, DialogType::Confirm);
256 assert_eq!(event.message, "Are you sure?");
257 }
258
259 #[test]
260 fn dialog_event_with_default_value() {
261 let event = DialogEvent::new(
262 DialogType::Prompt,
263 "Enter name:",
264 Some("default".to_string()),
265 );
266 assert_eq!(event.dialog_type, DialogType::Prompt);
267 assert_eq!(event.default_value, Some("default".to_string()));
268 }
269
270 #[test]
271 fn dialog_manager_new() {
272 let manager = DialogManager::new();
273 assert_eq!(manager.handler_count(), 0);
274 }
275
276 #[test]
277 fn dialog_manager_on_dialog() {
278 let mut manager = DialogManager::new();
279 manager.on_dialog(|_event| {});
280 assert_eq!(manager.handler_count(), 1);
281
282 manager.on_dialog(|_event| {});
283 assert_eq!(manager.handler_count(), 2);
284 }
285
286 #[test]
287 fn dialog_manager_clear_handlers() {
288 let mut manager = DialogManager::new();
289 manager.on_dialog(|_event| {});
290 manager.on_dialog(|_event| {});
291 assert_eq!(manager.handler_count(), 2);
292
293 manager.clear_dialog_handlers();
294 assert_eq!(manager.handler_count(), 0);
295 }
296
297 #[test]
298 fn dialog_manager_dispatch_calls_handlers() {
299 let mut manager = DialogManager::new();
300 let called = Arc::new(Mutex::new(false));
301 let called_clone = called.clone();
302
303 manager.on_dialog(move |event| {
304 *called_clone.lock().unwrap() = true;
305 assert_eq!(event.message, "Test dialog");
306 assert_eq!(event.dialog_type, DialogType::Alert);
307 });
308
309 let event = DialogEvent::from_str_type("alert", "Test dialog", None);
310 manager.dispatch(&event);
311
312 assert!(*called.lock().unwrap());
313 }
314
315 #[test]
316 fn dialog_manager_dispatch_calls_multiple_handlers() {
317 let mut manager = DialogManager::new();
318 let count = Arc::new(Mutex::new(0u32));
319
320 let count1 = count.clone();
321 manager.on_dialog(move |_| {
322 *count1.lock().unwrap() += 1;
323 });
324
325 let count2 = count.clone();
326 manager.on_dialog(move |_| {
327 *count2.lock().unwrap() += 1;
328 });
329
330 let event = DialogEvent::from_str_type("confirm", "Are you sure?", None);
331 manager.dispatch(&event);
332
333 assert_eq!(*count.lock().unwrap(), 2);
334 }
335
336 #[test]
337 fn dialog_manager_dispatch_with_no_handlers() {
338 let manager = DialogManager::new();
339 let event = DialogEvent::from_str_type("alert", "Hello!", None);
341 manager.dispatch(&event);
342 }
343
344 #[test]
345 fn dialog_manager_is_cloneable() {
346 let mut manager = DialogManager::new();
347 manager.on_dialog(|_| {});
348
349 let cloned = manager.clone();
350 assert_eq!(cloned.handler_count(), 1);
351 }
352
353 #[test]
354 fn dialog_manager_engine() {
355 let manager = DialogManager::new_with_engine(EngineType::Fantoccini);
356 assert_eq!(manager.engine(), EngineType::Fantoccini);
357 }
358
359 #[test]
360 fn dialog_manager_debug() {
361 let manager = DialogManager::new();
362 let debug_str = format!("{:?}", manager);
363 assert!(debug_str.contains("DialogManager"));
364 }
365}