use crate::core::engine::EngineType;
use std::fmt;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DialogType {
Alert,
Confirm,
Prompt,
BeforeUnload,
Unknown,
}
impl fmt::Display for DialogType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DialogType::Alert => write!(f, "alert"),
DialogType::Confirm => write!(f, "confirm"),
DialogType::Prompt => write!(f, "prompt"),
DialogType::BeforeUnload => write!(f, "beforeunload"),
DialogType::Unknown => write!(f, "unknown"),
}
}
}
impl From<&str> for DialogType {
fn from(s: &str) -> Self {
match s.to_lowercase().as_str() {
"alert" => DialogType::Alert,
"confirm" => DialogType::Confirm,
"prompt" => DialogType::Prompt,
"beforeunload" => DialogType::BeforeUnload,
_ => DialogType::Unknown,
}
}
}
#[derive(Debug, Clone)]
pub struct DialogEvent {
pub dialog_type: DialogType,
pub message: String,
pub default_value: Option<String>,
}
impl DialogEvent {
pub fn new(
dialog_type: DialogType,
message: impl Into<String>,
default_value: Option<String>,
) -> Self {
Self {
dialog_type,
message: message.into(),
default_value,
}
}
pub fn from_str_type(
dialog_type: &str,
message: impl Into<String>,
default_value: Option<String>,
) -> Self {
Self::new(DialogType::from(dialog_type), message, default_value)
}
}
pub type DialogHandler = Arc<dyn Fn(&DialogEvent) + Send + Sync>;
#[derive(Clone)]
pub struct DialogManager {
handlers: Arc<Mutex<Vec<DialogHandler>>>,
engine: EngineType,
}
impl fmt::Debug for DialogManager {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let count = self.handlers.lock().map(|h| h.len()).unwrap_or(0);
f.debug_struct("DialogManager")
.field("engine", &self.engine)
.field("handler_count", &count)
.finish()
}
}
impl DialogManager {
pub fn new_with_engine(engine: EngineType) -> Self {
Self {
handlers: Arc::new(Mutex::new(Vec::new())),
engine,
}
}
pub fn new() -> Self {
Self::new_with_engine(EngineType::Chromiumoxide)
}
pub fn on_dialog<F>(&mut self, handler: F)
where
F: Fn(&DialogEvent) + Send + Sync + 'static,
{
let mut handlers = self.handlers.lock().expect("lock poisoned");
handlers.push(Arc::new(handler));
}
pub fn clear_dialog_handlers(&mut self) {
let mut handlers = self.handlers.lock().expect("lock poisoned");
handlers.clear();
}
pub fn handler_count(&self) -> usize {
self.handlers.lock().map(|h| h.len()).unwrap_or(0)
}
pub fn dispatch(&self, event: &DialogEvent) {
let handlers = self.handlers.lock().expect("lock poisoned");
for handler in handlers.iter() {
handler(event);
}
}
pub fn engine(&self) -> EngineType {
self.engine
}
}
impl Default for DialogManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dialog_type_from_str() {
assert_eq!(DialogType::from("alert"), DialogType::Alert);
assert_eq!(DialogType::from("confirm"), DialogType::Confirm);
assert_eq!(DialogType::from("prompt"), DialogType::Prompt);
assert_eq!(DialogType::from("beforeunload"), DialogType::BeforeUnload);
assert_eq!(DialogType::from("unknown_type"), DialogType::Unknown);
}
#[test]
fn dialog_type_display() {
assert_eq!(DialogType::Alert.to_string(), "alert");
assert_eq!(DialogType::Confirm.to_string(), "confirm");
assert_eq!(DialogType::Prompt.to_string(), "prompt");
assert_eq!(DialogType::BeforeUnload.to_string(), "beforeunload");
assert_eq!(DialogType::Unknown.to_string(), "unknown");
}
#[test]
fn dialog_type_case_insensitive() {
assert_eq!(DialogType::from("ALERT"), DialogType::Alert);
assert_eq!(DialogType::from("Confirm"), DialogType::Confirm);
}
#[test]
fn dialog_event_new() {
let event = DialogEvent::new(DialogType::Alert, "Hello!", None);
assert_eq!(event.dialog_type, DialogType::Alert);
assert_eq!(event.message, "Hello!");
assert!(event.default_value.is_none());
}
#[test]
fn dialog_event_from_str_type() {
let event = DialogEvent::from_str_type("confirm", "Are you sure?", None);
assert_eq!(event.dialog_type, DialogType::Confirm);
assert_eq!(event.message, "Are you sure?");
}
#[test]
fn dialog_event_with_default_value() {
let event = DialogEvent::new(
DialogType::Prompt,
"Enter name:",
Some("default".to_string()),
);
assert_eq!(event.dialog_type, DialogType::Prompt);
assert_eq!(event.default_value, Some("default".to_string()));
}
#[test]
fn dialog_manager_new() {
let manager = DialogManager::new();
assert_eq!(manager.handler_count(), 0);
}
#[test]
fn dialog_manager_on_dialog() {
let mut manager = DialogManager::new();
manager.on_dialog(|_event| {});
assert_eq!(manager.handler_count(), 1);
manager.on_dialog(|_event| {});
assert_eq!(manager.handler_count(), 2);
}
#[test]
fn dialog_manager_clear_handlers() {
let mut manager = DialogManager::new();
manager.on_dialog(|_event| {});
manager.on_dialog(|_event| {});
assert_eq!(manager.handler_count(), 2);
manager.clear_dialog_handlers();
assert_eq!(manager.handler_count(), 0);
}
#[test]
fn dialog_manager_dispatch_calls_handlers() {
let mut manager = DialogManager::new();
let called = Arc::new(Mutex::new(false));
let called_clone = called.clone();
manager.on_dialog(move |event| {
*called_clone.lock().unwrap() = true;
assert_eq!(event.message, "Test dialog");
assert_eq!(event.dialog_type, DialogType::Alert);
});
let event = DialogEvent::from_str_type("alert", "Test dialog", None);
manager.dispatch(&event);
assert!(*called.lock().unwrap());
}
#[test]
fn dialog_manager_dispatch_calls_multiple_handlers() {
let mut manager = DialogManager::new();
let count = Arc::new(Mutex::new(0u32));
let count1 = count.clone();
manager.on_dialog(move |_| {
*count1.lock().unwrap() += 1;
});
let count2 = count.clone();
manager.on_dialog(move |_| {
*count2.lock().unwrap() += 1;
});
let event = DialogEvent::from_str_type("confirm", "Are you sure?", None);
manager.dispatch(&event);
assert_eq!(*count.lock().unwrap(), 2);
}
#[test]
fn dialog_manager_dispatch_with_no_handlers() {
let manager = DialogManager::new();
let event = DialogEvent::from_str_type("alert", "Hello!", None);
manager.dispatch(&event);
}
#[test]
fn dialog_manager_is_cloneable() {
let mut manager = DialogManager::new();
manager.on_dialog(|_| {});
let cloned = manager.clone();
assert_eq!(cloned.handler_count(), 1);
}
#[test]
fn dialog_manager_engine() {
let manager = DialogManager::new_with_engine(EngineType::Fantoccini);
assert_eq!(manager.engine(), EngineType::Fantoccini);
}
#[test]
fn dialog_manager_debug() {
let manager = DialogManager::new();
let debug_str = format!("{:?}", manager);
assert!(debug_str.contains("DialogManager"));
}
}