mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-29 20:56:47 -06:00
TUT4.2: reject malformed previews and cancel replaced dialogs
This commit is contained in:
@@ -339,6 +339,9 @@ fn handle_request(app: &mut DesignApp, ctx: &egui::Context, req: &ControlRequest
|
||||
},
|
||||
"ui.dialog.open" => {
|
||||
let Some(id) = s("id") else { return err("missing `id`") };
|
||||
// Replacing a modal cancels its transaction just like its Cancel button.
|
||||
// In particular, an uncommitted style preview must not leak into the new dialog.
|
||||
crate::dialogs::cancel(app);
|
||||
if id == "findChange" || app.ui.dialog.as_ref().is_some_and(|d| d.id == "findChange") {
|
||||
app.session.reset_find_scope();
|
||||
}
|
||||
@@ -440,6 +443,30 @@ pub(crate) fn page_index(p: &Value, default: usize, count: usize) -> Result<usiz
|
||||
#[cfg(test)]
|
||||
mod automation_contract_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn replacing_a_style_preview_dialog_restores_the_document_and_undo_recording() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
let before = app.session.doc().unwrap().doc.clone();
|
||||
let history = app.session.doc().unwrap().history.undo.len();
|
||||
app.session.begin_interaction("Style Options").unwrap();
|
||||
app.session.preview("style.paragraph.edit", json!({"name":designcraft_doc::BASIC_PARAGRAPH,"chars":{"size":24}})).unwrap();
|
||||
app.ui.dialog = Some(crate::dialogs::Dialog::new(
|
||||
"paragraphStyleOptions",
|
||||
json!({
|
||||
"name":designcraft_doc::BASIC_PARAGRAPH,"preview":true,"_previewed":{"chars":{"size":24}}
|
||||
}),
|
||||
));
|
||||
assert_ne!(app.session.doc().unwrap().doc, before);
|
||||
let response = call(&mut app, &ctx, "ui.dialog.open", json!({"id":"characterStyleOptions","fields":{"new":true}}));
|
||||
assert_eq!(response["ok"], true);
|
||||
assert_eq!(app.session.doc().unwrap().doc, before);
|
||||
assert!(app.session.doc().unwrap().interaction.is_none());
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), history);
|
||||
app.run("style.paragraph.edit", json!({"name":designcraft_doc::BASIC_PARAGRAPH,"chars":{"size":18}})).unwrap();
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), history + 1);
|
||||
}
|
||||
fn app() -> DesignApp {
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.session.execute("file.new", &json!({"pages":2})).unwrap();
|
||||
|
||||
@@ -2834,7 +2834,9 @@ fn style_options_preview(app: &mut DesignApp, d: &mut Dialog) {
|
||||
if params["para"][attr].is_null() {
|
||||
params["para"][attr] = json!({});
|
||||
}
|
||||
params["para"][attr][field] = value.clone();
|
||||
if let Some(fields) = params["para"][attr].as_object_mut() {
|
||||
fields.insert(field.into(), value.clone());
|
||||
}
|
||||
} else {
|
||||
params["para"][attr] = value.clone();
|
||||
}
|
||||
@@ -4954,6 +4956,26 @@ mod tests {
|
||||
assert!(app.session.doc().unwrap().interaction.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn style_preview_rejects_conflicting_scalar_and_nested_rule_fields_without_panicking() {
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({})).unwrap();
|
||||
let before = app.session.doc().unwrap().doc.clone();
|
||||
let mut dialog = Dialog::new(
|
||||
"paragraphStyleOptions",
|
||||
json!({
|
||||
"name": designcraft_doc::BASIC_PARAGRAPH, "preview": true,
|
||||
"p.ruleAbove": false, "p.ruleAbove.weight": 2
|
||||
}),
|
||||
);
|
||||
style_options_preview(&mut app, &mut dialog);
|
||||
assert!(dialog.fields.contains_key("status"));
|
||||
assert_eq!(app.session.doc().unwrap().doc, before);
|
||||
app.ui.dialog = Some(dialog);
|
||||
cancel(&mut app);
|
||||
assert!(app.session.doc().unwrap().interaction.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn step_and_repeat_dialog_previews_and_makes_the_copies_as_one_undo_step() {
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
|
||||
@@ -61,6 +61,10 @@ context menus, typing at a caret) are things a layout artist does every minute,
|
||||
|
||||
## Remaining effort
|
||||
|
||||
Style Preview rejects conflicting scalar/nested automation fields without a panic. Replacing a
|
||||
previewing dialog through the control channel cancels its transaction, restoring the original
|
||||
document and normal undo recording before the replacement opens.
|
||||
|
||||
Paragraph and Character Style Options now preview edits to existing styles. Preview updates
|
||||
every use, remains outside undo history, and restores the starting document when disabled or
|
||||
cancelled. OK applies the final edit once. The color-preview step at about 4:00 in
|
||||
|
||||
Reference in New Issue
Block a user