mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-02 22:50:27 -06:00
Conflict: crates/engine/src/tests.rs: both sides append tests; kept next's then #171's
This commit is contained in:
@@ -118,6 +118,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
has_doc,
|
||||
edit_char
|
||||
),
|
||||
cmd!("style.character.delete", "Delete Character Style", [], None, "{name, replaceWith?}", has_doc, delete_char),
|
||||
cmd!(query "style.list", "List Styles", [], None, "{} → paragraph and character style names", has_doc, |s, _| {
|
||||
let st = s.doc()?;
|
||||
Ok(json!({
|
||||
@@ -685,6 +686,27 @@ fn edit_char(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_char(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let name = str_param(p, "name").unwrap_or("").to_string();
|
||||
let repl = str_param(p, "replaceWith").unwrap_or(designcraft_doc::NO_CHAR_STYLE).to_string();
|
||||
if name.starts_with('[') {
|
||||
return Err(bad("style.character.delete", "built-in styles can't be deleted"));
|
||||
}
|
||||
s.edit(|d, _| {
|
||||
d.styles_mut().character.retain(|x| x.name != name);
|
||||
for sid in d.stories.keys().copied().collect::<Vec<_>>() {
|
||||
if let Some(story) = d.story_mut(sid) {
|
||||
story.for_each_text_mut(&mut |st| {
|
||||
for r in st.chars.iter_mut().filter(|r| r.format.style == name) {
|
||||
r.format.style = repl.clone();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
ok()
|
||||
})
|
||||
}
|
||||
|
||||
fn create_swatch(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let c = p.get("color").ok_or_else(|| bad("swatch.create", "missing color"))?;
|
||||
let color = parse_color(c).ok_or_else(|| bad("swatch.create", "bad color"))?;
|
||||
|
||||
@@ -703,3 +703,114 @@ fn preflight_mojikumi_uses_the_same_supported_rules_as_composition() {
|
||||
assert_eq!(!warnings.is_empty(), unsupported, "{name}: {warnings:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_style_edit_persists_attrs_and_rename() {
|
||||
let mut s = session();
|
||||
let name =
|
||||
s.execute("style.paragraph.create", &json!({"name": "Body Copy", "para": {"align": "left"}})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
s.execute("style.paragraph.edit", &json!({"name": name, "para": {"align": "center"}})).unwrap();
|
||||
{
|
||||
let st = s.doc().unwrap();
|
||||
let style = st.doc.styles.para(&name).expect("style still exists");
|
||||
assert_eq!(style.para.align, Some(designcraft_doc::Align::Center), "edited attribute persisted");
|
||||
}
|
||||
// Renaming updates the style definition itself, and every place it's referenced.
|
||||
s.execute("style.paragraph.edit", &json!({"name": name, "rename": "Body Text"})).unwrap();
|
||||
let st = s.doc().unwrap();
|
||||
assert!(st.doc.styles.para("Body Text").is_some(), "renamed style exists under the new name");
|
||||
assert!(st.doc.styles.para(&name).is_none(), "old name is gone");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_style_edit_rejects_based_on_cycle() {
|
||||
let mut s = session();
|
||||
let a = s.execute("style.paragraph.create", &json!({"name": "A"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let b = s.execute("style.paragraph.create", &json!({"name": "B", "basedOn": a})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let r = s.execute("style.paragraph.edit", &json!({"name": a, "basedOn": b}));
|
||||
assert!(r.is_err(), "A based on B based on A must be rejected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_style_delete_reassigns_affected_text() {
|
||||
let mut s = session();
|
||||
let name = s.execute("style.paragraph.create", &json!({"name": "Caption"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let sid = s.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text"})).unwrap()["story"].as_u64().unwrap();
|
||||
s.execute("text.insert", &json!({"text": "Hello, world"})).unwrap();
|
||||
s.execute("text.select", &json!({"story": sid, "anchor": 0, "focus": 0})).unwrap();
|
||||
s.execute("style.paragraph.apply", &json!({"name": name})).unwrap();
|
||||
{
|
||||
let st = s.doc().unwrap();
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).expect("story exists");
|
||||
assert_eq!(story.paras[0].style, name, "style applied before delete");
|
||||
}
|
||||
s.execute("style.paragraph.delete", &json!({"name": name, "replaceWith": designcraft_doc::BASIC_PARAGRAPH})).unwrap();
|
||||
let st = s.doc().unwrap();
|
||||
assert!(st.doc.styles.para(&name).is_none(), "deleted style is gone");
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).expect("story exists");
|
||||
assert_eq!(story.paras[0].style, designcraft_doc::BASIC_PARAGRAPH, "affected paragraph reassigned to the replacement style");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_style_delete_rejects_builtin_styles() {
|
||||
let mut s = session();
|
||||
let r = s.execute("style.paragraph.delete", &json!({"name": designcraft_doc::BASIC_PARAGRAPH}));
|
||||
assert!(r.is_err(), "built-in styles can't be deleted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_style_edit_persists_attrs_and_rename() {
|
||||
let mut s = session();
|
||||
let name = s.execute("style.character.create", &json!({"name": "Key Term", "chars": {"fontStyle": "Bold"}})).unwrap()["name"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
s.execute("style.character.edit", &json!({"name": name, "chars": {"tracking": 20.0}})).unwrap();
|
||||
{
|
||||
let st = s.doc().unwrap();
|
||||
let style = st.doc.styles.char_style(&name).expect("style still exists");
|
||||
assert_eq!(style.chars.tracking, Some(20.0), "edited attribute persisted");
|
||||
}
|
||||
// Renaming updates the style definition itself, and every place it's referenced.
|
||||
s.execute("style.character.edit", &json!({"name": name, "rename": "Emphasis"})).unwrap();
|
||||
let st = s.doc().unwrap();
|
||||
assert!(st.doc.styles.char_style("Emphasis").is_some(), "renamed style exists under the new name");
|
||||
assert!(st.doc.styles.char_style(&name).is_none(), "old name is gone");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_style_edit_rejects_based_on_cycle() {
|
||||
let mut s = session();
|
||||
let a = s.execute("style.character.create", &json!({"name": "A"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let b = s.execute("style.character.create", &json!({"name": "B", "basedOn": a})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let r = s.execute("style.character.edit", &json!({"name": a, "basedOn": b}));
|
||||
assert!(r.is_err(), "A based on B based on A must be rejected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_style_delete_reassigns_affected_text() {
|
||||
let mut s = session();
|
||||
let name = s.execute("style.character.create", &json!({"name": "Key Term"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let r = s.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text"})).unwrap();
|
||||
let sid = r["story"].as_u64().unwrap();
|
||||
s.execute("text.insert", &json!({"text": "Hello, world"})).unwrap();
|
||||
s.execute("text.select", &json!({"story": sid, "anchor": 0, "focus": 5})).unwrap();
|
||||
s.execute("style.character.apply", &json!({"name": name})).unwrap();
|
||||
{
|
||||
let st = s.doc().unwrap();
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).expect("story exists");
|
||||
assert_eq!(story.chars[0].format.style, name, "style applied before delete");
|
||||
}
|
||||
s.execute("style.character.delete", &json!({"name": name, "replaceWith": designcraft_doc::NO_CHAR_STYLE})).unwrap();
|
||||
let st = s.doc().unwrap();
|
||||
assert!(st.doc.styles.char_style(&name).is_none(), "deleted style is gone");
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).expect("story exists");
|
||||
assert_eq!(story.chars[0].format.style, designcraft_doc::NO_CHAR_STYLE, "affected run reassigned to the replacement style");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_style_delete_rejects_builtin_styles() {
|
||||
let mut s = session();
|
||||
let r = s.execute("style.character.delete", &json!({"name": designcraft_doc::NO_CHAR_STYLE}));
|
||||
assert!(r.is_err(), "built-in styles can't be deleted");
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ impl Dialog {
|
||||
if id == "paragraphStyleOptions" || id == "characterStyleOptions" {
|
||||
fields.entry("section".to_string()).or_insert(json!("general"));
|
||||
}
|
||||
if id == "characterStyleOptions" {
|
||||
fields.entry("section".to_string()).or_insert(json!("general"));
|
||||
}
|
||||
if id == "frameSize" {
|
||||
for k in ["width", "height"] {
|
||||
if let Some(v) = fields.get(k).and_then(Value::as_f64) {
|
||||
@@ -1129,7 +1132,9 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
"documentSetup" => crate::i18n::tr(&app.ui.language, "Document Setup"),
|
||||
"findChange" => crate::i18n::tr(&app.ui.language, "Find/Change"),
|
||||
"paragraphStyleOptions" => crate::i18n::tr(&app.ui.language, "Paragraph Style Options"),
|
||||
"deleteParagraphStyle" => crate::i18n::tr(&app.ui.language, "Delete Paragraph Style"),
|
||||
"characterStyleOptions" => crate::i18n::tr(&app.ui.language, "Character Style Options"),
|
||||
"deleteCharacterStyle" => crate::i18n::tr(&app.ui.language, "Delete Character Style"),
|
||||
"footnoteOptions" => crate::i18n::tr(&app.ui.language, "Footnote Options"),
|
||||
"paragraphRules" => crate::i18n::tr(&app.ui.language, "Paragraph Rules"),
|
||||
"insertXref" => crate::i18n::tr(&app.ui.language, "New Cross-Reference"),
|
||||
@@ -1387,7 +1392,9 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
}
|
||||
}
|
||||
"paragraphStyleOptions" => paragraph_style_options(app, ui, &mut d),
|
||||
"deleteParagraphStyle" => delete_paragraph_style(app, ui, &mut d),
|
||||
"characterStyleOptions" => character_style_options(app, ui, &mut d),
|
||||
"deleteCharacterStyle" => delete_character_style(app, ui, &mut d),
|
||||
"footnoteOptions" => footnote_options(app, ui, &mut d),
|
||||
"paragraphRules" => {
|
||||
let current = d.fields.get("current").cloned().unwrap_or_default();
|
||||
@@ -1859,6 +1866,14 @@ pub fn confirm(app: &mut DesignApp) -> Result<Value, String> {
|
||||
}
|
||||
Ok(r)
|
||||
}
|
||||
"deleteParagraphStyle" => {
|
||||
let name = d.s("name");
|
||||
let replace = d.s("replaceWith");
|
||||
app.run(
|
||||
"style.paragraph.delete",
|
||||
json!({"name": name, "replaceWith": if replace.is_empty() { json!(designcraft_doc::BASIC_PARAGRAPH) } else { json!(replace) }}),
|
||||
)
|
||||
}
|
||||
"paragraphRules" => {
|
||||
let attrs = rule_edits(&d, "");
|
||||
if attrs.is_empty() {
|
||||
@@ -1903,6 +1918,14 @@ pub fn confirm(app: &mut DesignApp) -> Result<Value, String> {
|
||||
}
|
||||
r
|
||||
}
|
||||
"deleteCharacterStyle" => {
|
||||
let name = d.s("name");
|
||||
let replace = d.s("replaceWith");
|
||||
app.run(
|
||||
"style.character.delete",
|
||||
json!({"name": name, "replaceWith": if replace.is_empty() { json!(designcraft_doc::NO_CHAR_STYLE) } else { json!(replace) }}),
|
||||
)
|
||||
}
|
||||
"colorPicker" => {
|
||||
let hex = d.s("hex");
|
||||
app.run("object.color", json!({"color": hex, "target": d.s("target"), "text": d.b("text")}))
|
||||
@@ -2707,7 +2730,51 @@ fn paragraph_style_options(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialo
|
||||
});
|
||||
}
|
||||
|
||||
/// The section list on the left of the style options dialogs.
|
||||
fn delete_paragraph_style(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
let name = d.s("name");
|
||||
ui.set_min_width(380.0);
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(
|
||||
crate::i18n::tr(&app.ui.language, "Delete the paragraph style \"{name}\"?")
|
||||
.replace("{name}", crate::i18n::style_name(&app.ui.language, &name)),
|
||||
)
|
||||
.size(12.5),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
let Some(st) = app.session.active() else { return };
|
||||
let in_use = st.doc.stories.values().any(|s| s.paras.iter().any(|f| f.style == name));
|
||||
let names: Vec<String> = st.doc.styles.paragraph.iter().map(|p| p.name.clone()).filter(|n| *n != name).collect();
|
||||
if in_use {
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(crate::i18n::tr(&app.ui.language, "This style is in use. Text using it will be reassigned to:"))
|
||||
.size(11.0)
|
||||
.color(crate::theme::Tokens::get(ui.ctx()).text_dim),
|
||||
);
|
||||
} else {
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(crate::i18n::tr(&app.ui.language, "Replace with:")).size(11.0).color(crate::theme::Tokens::get(ui.ctx()).text_dim),
|
||||
);
|
||||
}
|
||||
ui.add_space(4.0);
|
||||
if !d.fields.contains_key("replaceWith") {
|
||||
d.fields.insert("replaceWith".into(), json!(designcraft_doc::BASIC_PARAGRAPH));
|
||||
}
|
||||
let replace = d.s("replaceWith");
|
||||
egui::ComboBox::from_id_salt("del_para_replace")
|
||||
.selected_text(crate::rtl::widget(ui, crate::i18n::style_name(&app.ui.language, &replace)))
|
||||
.width(260.0)
|
||||
.show_ui(ui, |ui| {
|
||||
for n in &names {
|
||||
if ui.selectable_label(*n == replace, crate::rtl::widget(ui, crate::i18n::style_name(&app.ui.language, n))).clicked() {
|
||||
d.fields.insert("replaceWith".into(), json!(n));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn section_list(lang: &str, ui: &mut egui::Ui, d: &mut Dialog, sections: &[(&str, &str)]) {
|
||||
ui.vertical(|ui| {
|
||||
ui.set_width(170.0);
|
||||
@@ -3190,6 +3257,51 @@ fn line_options(lang: &str, ui: &mut egui::Ui, d: &mut Dialog, cf: &CharFields,
|
||||
});
|
||||
}
|
||||
|
||||
fn delete_character_style(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
let name = d.s("name");
|
||||
ui.set_min_width(380.0);
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(
|
||||
crate::i18n::tr(&app.ui.language, "Delete the character style \"{name}\"?")
|
||||
.replace("{name}", crate::i18n::style_name(&app.ui.language, &name)),
|
||||
)
|
||||
.size(12.5),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
let Some(st) = app.session.active() else { return };
|
||||
let in_use = st.doc.stories.values().any(|s| s.chars.iter().any(|r| r.format.style == name));
|
||||
let names: Vec<String> = st.doc.styles.character.iter().map(|c| c.name.clone()).filter(|n| *n != name).collect();
|
||||
if in_use {
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(crate::i18n::tr(&app.ui.language, "This style is in use. Text using it will be reassigned to:"))
|
||||
.size(11.0)
|
||||
.color(crate::theme::Tokens::get(ui.ctx()).text_dim),
|
||||
);
|
||||
} else {
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(crate::i18n::tr(&app.ui.language, "Replace with:")).size(11.0).color(crate::theme::Tokens::get(ui.ctx()).text_dim),
|
||||
);
|
||||
}
|
||||
ui.add_space(4.0);
|
||||
if !d.fields.contains_key("replaceWith") {
|
||||
d.fields.insert("replaceWith".into(), json!(designcraft_doc::NO_CHAR_STYLE));
|
||||
}
|
||||
let replace = d.s("replaceWith");
|
||||
egui::ComboBox::from_id_salt("del_char_replace")
|
||||
.selected_text(crate::rtl::widget(ui, crate::i18n::style_name(&app.ui.language, &replace)))
|
||||
.width(260.0)
|
||||
.show_ui(ui, |ui| {
|
||||
for n in [designcraft_doc::NO_CHAR_STYLE].into_iter().chain(names.iter().map(String::as_str)) {
|
||||
if ui.selectable_label(n == replace, crate::rtl::widget(ui, crate::i18n::style_name(&app.ui.language, n))).clicked() {
|
||||
d.fields.insert("replaceWith".into(), json!(n));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn combo(ui: &mut egui::Ui, d: &mut Dialog, key: &str, opts: &[(&str, &str)]) {
|
||||
let cur = d.s(key);
|
||||
let shown = opts.iter().find(|o| o.0 == cur).map_or(cur.as_str(), |o| o.1).to_string();
|
||||
@@ -4320,6 +4432,86 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn test_app() -> crate::DesignApp {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.session.execute("file.new", &json!({"pages": 1})).unwrap();
|
||||
app
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_style_options_dialog_saves_edits() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.paragraph.create", &json!({"name": "Body Copy"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
app.ui.dialog = Some(Dialog::new("paragraphStyleOptions", json!({"name": name, "p.align": "center"})));
|
||||
confirm(&mut app).expect("OK saves the style edit");
|
||||
let st = app.session.active().unwrap();
|
||||
assert_eq!(st.doc.styles.para(&name).unwrap().para.align, Some(designcraft_doc::Align::Center));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_paragraph_style_dialog_removes_the_style_and_reassigns_text() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.paragraph.create", &json!({"name": "Caption"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let sid = app.session.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text"})).unwrap()["story"].as_u64().unwrap();
|
||||
app.session.execute("text.insert", &json!({"text": "Hello"})).unwrap();
|
||||
app.session.execute("text.select", &json!({"story": sid, "anchor": 0, "focus": 0})).unwrap();
|
||||
app.session.execute("style.paragraph.apply", &json!({"name": name})).unwrap();
|
||||
app.ui.dialog = Some(Dialog::new("deleteParagraphStyle", json!({"name": name, "replaceWith": designcraft_doc::BASIC_PARAGRAPH})));
|
||||
confirm(&mut app).expect("OK deletes the style");
|
||||
let st = app.session.active().unwrap();
|
||||
assert!(st.doc.styles.para(&name).is_none(), "style removed");
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).unwrap();
|
||||
assert_eq!(story.paras[0].style, designcraft_doc::BASIC_PARAGRAPH, "text reassigned to the replacement style");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_paragraph_style_dialog_defaults_replacement_to_basic_paragraph() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.paragraph.create", &json!({"name": "Caption"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
// No `replaceWith` set — the dialog's default field.
|
||||
app.ui.dialog = Some(Dialog::new("deleteParagraphStyle", json!({"name": name})));
|
||||
confirm(&mut app).expect("OK deletes the style with the default replacement");
|
||||
let st = app.session.active().unwrap();
|
||||
assert!(st.doc.styles.para(&name).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_style_options_dialog_saves_edits() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.character.create", &json!({"name": "Key Term"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
app.ui.dialog = Some(Dialog::new("characterStyleOptions", json!({"name": name, "c.tracking": 20.0})));
|
||||
confirm(&mut app).expect("OK saves the style edit");
|
||||
let st = app.session.active().unwrap();
|
||||
assert_eq!(st.doc.styles.char_style(&name).unwrap().chars.tracking, Some(20.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_character_style_dialog_removes_the_style_and_reassigns_text() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.character.create", &json!({"name": "Key Term"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
let sid = app.session.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text"})).unwrap()["story"].as_u64().unwrap();
|
||||
app.session.execute("text.insert", &json!({"text": "Hello"})).unwrap();
|
||||
app.session.execute("text.select", &json!({"story": sid, "anchor": 0, "focus": 5})).unwrap();
|
||||
app.session.execute("style.character.apply", &json!({"name": name})).unwrap();
|
||||
app.ui.dialog = Some(Dialog::new("deleteCharacterStyle", json!({"name": name, "replaceWith": designcraft_doc::NO_CHAR_STYLE})));
|
||||
confirm(&mut app).expect("OK deletes the style");
|
||||
let st = app.session.active().unwrap();
|
||||
assert!(st.doc.styles.char_style(&name).is_none(), "style removed");
|
||||
let story = st.doc.stories.get(&designcraft_doc::StoryId(sid)).unwrap();
|
||||
assert_eq!(story.chars[0].format.style, designcraft_doc::NO_CHAR_STYLE, "text reassigned to the replacement style");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_character_style_dialog_defaults_replacement_to_none() {
|
||||
let mut app = test_app();
|
||||
let name = app.session.execute("style.character.create", &json!({"name": "Key Term"})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
// No `replaceWith` set — the dialog's default field.
|
||||
app.ui.dialog = Some(Dialog::new("deleteCharacterStyle", json!({"name": name})));
|
||||
confirm(&mut app).expect("OK deletes the style with the default replacement");
|
||||
let st = app.session.active().unwrap();
|
||||
assert!(st.doc.styles.char_style(&name).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pdf_export_defaults() {
|
||||
let d = Dialog::new("pdfExport", json!({}));
|
||||
|
||||
@@ -148,5 +148,19 @@ fn style_row(app: &mut DesignApp, ui: &mut egui::Ui, para: bool, n: &str, curren
|
||||
ui.data_mut(|d| d.insert_temp(id, name));
|
||||
});
|
||||
}
|
||||
if para && !n.starts_with('[') {
|
||||
ui.separator();
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Delete Paragraph Style…"))).clicked() {
|
||||
app.ui.dialog = Some(crate::dialogs::Dialog::new("deleteParagraphStyle", json!({"name": n})));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
if !para && !n.starts_with('[') {
|
||||
ui.separator();
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Delete Character Style…"))).clicked() {
|
||||
app.ui.dialog = Some(crate::dialogs::Dialog::new("deleteCharacterStyle", json!({"name": n})));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user