mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-12 00:46:57 -06:00
Window title: mark unsaved changes, and set it on the web (#3640)
The title now reads "<name> • — PdfCraft" while the active document has unsaved changes, as the other Craft apps write it, and goes back to "<name> — PdfCraft" once saved. eframe's web runner ignores ViewportCommand::Title, so the web build never named the open document. It now also sets the page's document.title, which an embedding host reads to confirm which document opened and whether it has unsaved changes.
This commit is contained in:
@@ -546,14 +546,23 @@ impl eframe::App for PdfCraftApp {
|
||||
for view in &mut self.views {
|
||||
view.begin_render_frame();
|
||||
}
|
||||
// The window shows the active document's name (or title, if it asks for that).
|
||||
// The window shows the active document's name (or title, if it asks for that), with •
|
||||
// while it has unsaved changes, as the other Craft apps write it (#3640).
|
||||
let view = self.active.and_then(|i| self.views.get(i));
|
||||
let dirty = view.and_then(|v| self.session.get(v.id)).is_some_and(|d| d.dirty);
|
||||
let mark = if dirty { " •" } else { "" };
|
||||
let title = self
|
||||
.active
|
||||
.and_then(|i| crate::canvas::tab_label(self, i))
|
||||
.or_else(|| self.combine_showing().then(|| tl!("Combine files").to_owned()))
|
||||
.map_or_else(|| "PdfCraft".to_owned(), |name| format!("{name} — PdfCraft"));
|
||||
.map_or_else(|| "PdfCraft".to_owned(), |name| format!("{name}{mark} — PdfCraft"));
|
||||
if title != self.window_title {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Title(title.clone()));
|
||||
// eframe's web runner ignores Title: set the page's own, which an embedding host reads.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Some(document) = web_sys::window().and_then(|w| w.document()) {
|
||||
document.set_title(&title);
|
||||
}
|
||||
self.window_title = title;
|
||||
}
|
||||
// The accessible window takes the same name, so a screen reader (AT-SPI on Linux, UIA on
|
||||
|
||||
@@ -91,7 +91,7 @@ fn checking_fixing_skipping_and_reporting() {
|
||||
assert_eq!(status(&h, Rule::Title), Status::Passed);
|
||||
assert_eq!(h.state().a11y.previous.as_ref().unwrap().1.result(Rule::Title).unwrap().status, Status::Failed);
|
||||
assert!(matches!(h.state().dialog, Some(Dialog::Properties(_))));
|
||||
assert_eq!(h.state().window_title, "notes — PdfCraft");
|
||||
assert_eq!(h.state().window_title, "notes • — PdfCraft");
|
||||
h.state_mut().dialog = None;
|
||||
h.run_steps(2);
|
||||
h.get_by_label("Compare");
|
||||
|
||||
@@ -974,10 +974,36 @@ fn tab_and_window_show_the_document_title_when_asked() {
|
||||
s.session.apply(id, Edit::SetInitialView(Box::new(v))).unwrap();
|
||||
}
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().window_title, "Quarterly report — PdfCraft");
|
||||
// The edits are unsaved, so the title says so (#3640).
|
||||
assert_eq!(h.state().window_title, "Quarterly report • — PdfCraft");
|
||||
h.get_by_label_contains("Quarterly report");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_window_title_marks_unsaved_changes_until_saved() {
|
||||
use pdfcraft_engine::Edit;
|
||||
let mut h = harness();
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().window_title, "b.pdf — PdfCraft");
|
||||
{
|
||||
let s = h.state_mut();
|
||||
let id = s.views[s.active.unwrap()].id;
|
||||
s.session.apply(id, Edit::SetInfo { key: "Subject".into(), value: "Budget".into() }).unwrap();
|
||||
}
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().window_title, "b.pdf • — PdfCraft", "unsaved changes (#3640)");
|
||||
// Saved under its own name, so the title changes only by the mark.
|
||||
let dir = std::env::temp_dir().join(format!("pdfcraft-title-dirty-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
h.state_mut().save_override = Some(dir.join("b.pdf").to_string_lossy().into_owned());
|
||||
assert!(h.state_mut().execute("file.save"));
|
||||
h.run_steps(2);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let s = h.state();
|
||||
assert!(!s.session.get(s.views[s.active.unwrap()].id).unwrap().dirty);
|
||||
assert_eq!(s.window_title, "b.pdf — PdfCraft", "saved");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_placeholder_title_leaves_the_file_name_on_the_tab_and_window() {
|
||||
// A browser's "Save as PDF" of a blank page or pop-up titles the document "about:blank"
|
||||
@@ -993,7 +1019,7 @@ fn a_placeholder_title_leaves_the_file_name_on_the_tab_and_window() {
|
||||
s.session.apply(id, Edit::SetInitialView(Box::new(v))).unwrap();
|
||||
}
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().window_title, "b.pdf — PdfCraft");
|
||||
assert_eq!(h.state().window_title, "b.pdf • — PdfCraft");
|
||||
assert!(h.query_by_label_contains("about:blank").is_none());
|
||||
}
|
||||
|
||||
@@ -2265,6 +2291,7 @@ fn the_accessible_window_has_the_window_title_as_its_name() {
|
||||
s.session.apply(id, Edit::SetInitialView(Box::new(v))).unwrap();
|
||||
}
|
||||
h.run_steps(2);
|
||||
assert_eq!(name(&h).as_deref(), Some("Quarterly report — PdfCraft"));
|
||||
// Unsaved, so it carries the window title's mark too (#3640).
|
||||
assert_eq!(name(&h).as_deref(), Some("Quarterly report • — PdfCraft"));
|
||||
assert_eq!(name(&h), Some(h.state().window_title.clone()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user