Check for clozes when saving notetype
Error if: - Cloze notetype lacks a cloze field on either template side. - Non-cloze notetype has a cloze field on any template.
This commit is contained in:
parent
6fae0ea21f
commit
3dfa1de68b
@ -22,6 +22,8 @@ card-templates-add-mobile-class = Add Mobile Class
|
|||||||
card-templates-preview-settings = Options
|
card-templates-preview-settings = Options
|
||||||
card-templates-invalid-template-number = Card template { $number } in notetype '{ $notetype }' has a problem.
|
card-templates-invalid-template-number = Card template { $number } in notetype '{ $notetype }' has a problem.
|
||||||
card-templates-identical-front = Its front side is identical with the one of card template { $number }.
|
card-templates-identical-front = Its front side is identical with the one of card template { $number }.
|
||||||
|
card-templates-missing-cloze = The 'cloze' filter must be used on both sides of a cloze template.
|
||||||
|
card-templates-extraneous-cloze = The 'cloze' filter can only be used on cloze templates.
|
||||||
card-templates-see-preview = See the render preview for more information.
|
card-templates-see-preview = See the render preview for more information.
|
||||||
card-templates-changes-saved = Changes saved.
|
card-templates-changes-saved = Changes saved.
|
||||||
card-templates-discard-changes = Discard changes?
|
card-templates-discard-changes = Discard changes?
|
||||||
|
@ -67,6 +67,10 @@ impl AnkiError {
|
|||||||
let details = match err.details {
|
let details = match err.details {
|
||||||
TemplateSaveErrorDetails::TemplateError => tr.card_templates_see_preview(),
|
TemplateSaveErrorDetails::TemplateError => tr.card_templates_see_preview(),
|
||||||
TemplateSaveErrorDetails::Duplicate(i) => tr.card_templates_identical_front(i),
|
TemplateSaveErrorDetails::Duplicate(i) => tr.card_templates_identical_front(i),
|
||||||
|
TemplateSaveErrorDetails::MissingCloze => tr.card_templates_missing_cloze(),
|
||||||
|
TemplateSaveErrorDetails::ExtraneousCloze => {
|
||||||
|
tr.card_templates_extraneous_cloze()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
format!("{}<br>{}", header, details)
|
format!("{}<br>{}", header, details)
|
||||||
}
|
}
|
||||||
@ -146,6 +150,8 @@ pub struct TemplateSaveError {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum TemplateSaveErrorDetails {
|
pub enum TemplateSaveErrorDetails {
|
||||||
Duplicate(usize),
|
|
||||||
TemplateError,
|
TemplateError,
|
||||||
|
Duplicate(usize),
|
||||||
|
MissingCloze,
|
||||||
|
ExtraneousCloze,
|
||||||
}
|
}
|
||||||
|
@ -287,6 +287,28 @@ impl Notetype {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_cloze_if_and_only_if_cloze_notetype(
|
||||||
|
&self,
|
||||||
|
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
|
||||||
|
) -> Result<()> {
|
||||||
|
if self.is_cloze() {
|
||||||
|
if missing_cloze_filter(parsed_templates) {
|
||||||
|
return Err(AnkiError::TemplateSaveError(TemplateSaveError {
|
||||||
|
notetype: self.name.clone(),
|
||||||
|
ordinal: 0,
|
||||||
|
details: TemplateSaveErrorDetails::MissingCloze,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else if let Some(i) = find_cloze_filter(parsed_templates) {
|
||||||
|
return Err(AnkiError::TemplateSaveError(TemplateSaveError {
|
||||||
|
notetype: self.name.clone(),
|
||||||
|
ordinal: i,
|
||||||
|
details: TemplateSaveErrorDetails::ExtraneousCloze,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn normalize_names(&mut self) {
|
pub(crate) fn normalize_names(&mut self) {
|
||||||
ensure_string_in_nfc(&mut self.name);
|
ensure_string_in_nfc(&mut self.name);
|
||||||
for f in &mut self.fields {
|
for f in &mut self.fields {
|
||||||
@ -349,6 +371,7 @@ impl Notetype {
|
|||||||
details: TemplateSaveErrorDetails::TemplateError,
|
details: TemplateSaveErrorDetails::TemplateError,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
self.ensure_cloze_if_and_only_if_cloze_notetype(&parsed_templates)?;
|
||||||
let reqs = self.updated_requirements(&parsed_templates);
|
let reqs = self.updated_requirements(&parsed_templates);
|
||||||
|
|
||||||
// handle renamed+deleted fields
|
// handle renamed+deleted fields
|
||||||
@ -448,6 +471,35 @@ impl Notetype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if the slice is empty or either template of the first tuple doesn't have a cloze field.
|
||||||
|
fn missing_cloze_filter(
|
||||||
|
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
|
||||||
|
) -> bool {
|
||||||
|
parsed_templates
|
||||||
|
.get(0)
|
||||||
|
.map_or(true, |t| !has_cloze(&t.0) || !has_cloze(&t.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the index of the first tuple with a cloze field on either template.
|
||||||
|
fn find_cloze_filter(
|
||||||
|
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
|
||||||
|
) -> Option<usize> {
|
||||||
|
parsed_templates.iter().enumerate().find_map(|(i, t)| {
|
||||||
|
if has_cloze(&t.0) || has_cloze(&t.1) {
|
||||||
|
Some(i)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if the template is non-empty and has a cloze field.
|
||||||
|
fn has_cloze(template: &Option<ParsedTemplate>) -> bool {
|
||||||
|
template
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |t| !t.cloze_fields().is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Notetype> for NotetypeProto {
|
impl From<Notetype> for NotetypeProto {
|
||||||
fn from(nt: Notetype) -> Self {
|
fn from(nt: Notetype) -> Self {
|
||||||
NotetypeProto {
|
NotetypeProto {
|
||||||
|
Loading…
Reference in New Issue
Block a user