Fix unable to save field dialog if certain fields are deleted (#2663)
* Fix unable to save field dialog if certain fields are deleted Implemented solution suggested in issue #2556 * Fix unable to save field dialog if certain fields are deleted fixed code formating * Fix unable to save field dialog if certain fields are deleted Made new functions to check referencelessness. Added unit test.
This commit is contained in:
parent
a7b4c90146
commit
e7bf248a62
|
@ -139,6 +139,7 @@ Nil Admirari <https://github.com/nihil-admirari>
|
|||
Michael Winkworth <github.com/SteelColossus>
|
||||
Mateusz Wojewoda <kawa1.11@o2.pl>
|
||||
Jarrett Ye <jarrett.ye@outlook.com>
|
||||
Sam Waechter <github.com/swektr>
|
||||
|
||||
********************
|
||||
|
||||
|
|
|
@ -551,13 +551,21 @@ impl Notetype {
|
|||
fields: HashMap<String, Option<String>>,
|
||||
parsed: &mut [(Option<ParsedTemplate>, Option<ParsedTemplate>)],
|
||||
) {
|
||||
let first_remaining_field_name = &self.fields.get(0).unwrap().name;
|
||||
let is_cloze = self.is_cloze();
|
||||
for (idx, (q_opt, a_opt)) in parsed.iter_mut().enumerate() {
|
||||
if let Some(q) = q_opt {
|
||||
q.rename_and_remove_fields(&fields);
|
||||
if !q.contains_field_replacement() || is_cloze && !q.contains_cloze_replacement() {
|
||||
q.add_missing_field_replacement(first_remaining_field_name, is_cloze);
|
||||
}
|
||||
self.templates[idx].config.q_format = q.template_to_string();
|
||||
}
|
||||
if let Some(a) = a_opt {
|
||||
a.rename_and_remove_fields(&fields);
|
||||
if is_cloze && !a.contains_cloze_replacement() {
|
||||
a.add_missing_field_replacement(first_remaining_field_name, is_cloze);
|
||||
}
|
||||
self.templates[idx].config.a_format = a.template_to_string();
|
||||
}
|
||||
}
|
||||
|
@ -745,3 +753,73 @@ impl Collection {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests
|
||||
//---------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn update_templates_after_removing_crucial_fields() {
|
||||
// Normal Test (all front fields removed)
|
||||
let mut nt_norm = Notetype::default();
|
||||
nt_norm.add_field("baz"); // Fields "foo" and "bar" were removed
|
||||
nt_norm.fields[0].ord = Some(2);
|
||||
|
||||
nt_norm.add_template("Card 1", "front {{foo}}", "back {{bar}}");
|
||||
nt_norm.templates[0].ord = Some(0);
|
||||
let mut parsed = nt_norm.parsed_templates();
|
||||
|
||||
let mut field_map: HashMap<String, Option<String>> = HashMap::new();
|
||||
field_map.insert("foo".to_owned(), None);
|
||||
field_map.insert("bar".to_owned(), None);
|
||||
|
||||
nt_norm.update_templates_for_renamed_and_removed_fields(field_map, &mut parsed);
|
||||
assert_eq!(nt_norm.templates[0].config.q_format, "front {{baz}}");
|
||||
assert_eq!(nt_norm.templates[0].config.a_format, "back ");
|
||||
|
||||
// Cloze Test 1/2 (front and back cloze fields removed)
|
||||
let mut nt_cloze = Notetype {
|
||||
config: Notetype::new_cloze_config(),
|
||||
..Default::default()
|
||||
};
|
||||
nt_cloze.add_field("baz"); // Fields "foo" and "bar" were removed
|
||||
nt_cloze.fields[0].ord = Some(2);
|
||||
|
||||
nt_cloze.add_template("Card 1", "front {{cloze:foo}}", "back {{cloze:bar}}");
|
||||
nt_cloze.templates[0].ord = Some(0);
|
||||
let mut parsed = nt_cloze.parsed_templates();
|
||||
|
||||
let mut field_map: HashMap<String, Option<String>> = HashMap::new();
|
||||
field_map.insert("foo".to_owned(), None);
|
||||
field_map.insert("bar".to_owned(), None);
|
||||
|
||||
nt_cloze.update_templates_for_renamed_and_removed_fields(field_map, &mut parsed);
|
||||
assert_eq!(nt_cloze.templates[0].config.q_format, "front {{cloze:baz}}");
|
||||
assert_eq!(nt_cloze.templates[0].config.a_format, "back {{cloze:baz}}");
|
||||
|
||||
// Cloze Test 2/2 (only back cloze field is removed)
|
||||
let mut nt_cloze = Notetype {
|
||||
config: Notetype::new_cloze_config(),
|
||||
..Default::default()
|
||||
};
|
||||
nt_cloze.add_field("foo");
|
||||
nt_cloze.fields[0].ord = Some(0);
|
||||
nt_cloze.add_field("baz");
|
||||
nt_cloze.fields[1].ord = Some(2);
|
||||
// ^ only field "bar" was removed
|
||||
|
||||
nt_cloze.add_template("Card 1", "front {{cloze:foo}}", "back {{cloze:bar}}");
|
||||
nt_cloze.templates[0].ord = Some(0);
|
||||
let mut parsed = nt_cloze.parsed_templates();
|
||||
|
||||
let mut field_map: HashMap<String, Option<String>> = HashMap::new();
|
||||
field_map.insert("bar".to_owned(), None);
|
||||
|
||||
nt_cloze.update_templates_for_renamed_and_removed_fields(field_map, &mut parsed);
|
||||
assert_eq!(nt_cloze.templates[0].config.q_format, "front {{cloze:foo}}");
|
||||
assert_eq!(nt_cloze.templates[0].config.a_format, "back {{cloze:foo}}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -730,6 +730,30 @@ impl ParsedTemplate {
|
|||
let old_nodes = std::mem::take(&mut self.0);
|
||||
self.0 = rename_and_remove_fields(old_nodes, fields);
|
||||
}
|
||||
|
||||
pub(crate) fn contains_cloze_replacement(&self) -> bool {
|
||||
self.0.iter().any(|node| {
|
||||
matches!(
|
||||
node,
|
||||
ParsedNode::Replacement {key:_, filters} if filters.iter().any(|f| f=="cloze")
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn contains_field_replacement(&self) -> bool {
|
||||
self.0
|
||||
.iter()
|
||||
.any(|node| matches!(node, ParsedNode::Replacement { key: _, filters: _ }))
|
||||
}
|
||||
|
||||
pub(crate) fn add_missing_field_replacement(&mut self, field_name: &str, is_cloze: bool) {
|
||||
let key = String::from(field_name);
|
||||
let filters = match is_cloze {
|
||||
true => vec![String::from("cloze")],
|
||||
false => Vec::new(),
|
||||
};
|
||||
self.0.push(ParsedNode::Replacement { key, filters });
|
||||
}
|
||||
}
|
||||
|
||||
fn rename_and_remove_fields(
|
||||
|
|
Loading…
Reference in New Issue