mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-24 10:08:00 -06:00
M12: only date clauses are other ways to type a date, and a date is rewritten only into a first pattern that keeps it
This commit is contained in:
@@ -506,7 +506,8 @@ pub fn fields_template(data: &str) -> String {
|
||||
}
|
||||
|
||||
/// Date fields whose edit pictures list alternatives, as forms let a date be typed several ways
|
||||
/// (`date{YYYYMMDD}|date{YYMMDD}|…`); one with a single pattern; a text field.
|
||||
/// (`date{YYYYMMDD}|date{YYMMDD}|…`); one with a single pattern; a text field; `code`, whose
|
||||
/// only alternative is a text clause; and `short`, whose first pattern has a two-digit year.
|
||||
pub fn date_alternatives_template() -> String {
|
||||
r##"<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
|
||||
@@ -516,6 +517,8 @@ pub fn date_alternatives_template() -> String {
|
||||
<field name="leave" w="2in" h="0.3in"><ui><dateTimeEdit/><picture>date{YYYYMMDD}|date{DDMMMYY}|date{YYMMDD}|date{YYYYMMD}|date{YY MM DD}</picture></ui><value><date/></value></field>
|
||||
<field name="born" w="2in" h="0.3in"><ui><dateTimeEdit/><picture>date{YYYY-MM-DD}</picture></ui><value><date/></value></field>
|
||||
<field name="name" w="2in" h="0.3in"><ui><textEdit/></ui></field>
|
||||
<field name="code" w="2in" h="0.3in"><ui><dateTimeEdit/><picture>date{YYYYMMDD}|text{YYMMDD}</picture></ui><value><date/></value></field>
|
||||
<field name="short" w="2in" h="0.3in"><ui><dateTimeEdit/><picture>date{YYMMDD}|date{YYYYMMDD}</picture></ui><value><date/></value></field>
|
||||
</subform>
|
||||
</template>
|
||||
</xdp:xdp>
|
||||
|
||||
@@ -29,8 +29,9 @@ pub(crate) fn alternatives(picture: &str) -> Vec<&str> {
|
||||
/// `text` typed into the date field at `som` by one of its edit picture's alternatives after the
|
||||
/// first, written in the first, which the field shows and checks typed dates against (`261018`
|
||||
/// becomes `20261018` for `date{YYYYMMDD}|date{YYMMDD}`). A pattern reads the text only when the
|
||||
/// date it gives, written in that pattern, is the text again. `None` when the field isn't a date
|
||||
/// field with alternatives, the first pattern reads the text, or no other does.
|
||||
/// date it gives, written in that pattern, is the text again, and only date clauses count. `None`
|
||||
/// when the field isn't a date field with alternatives, the first pattern reads the text, no
|
||||
/// other does, or the first pattern can't hold the date (a two-digit year for 1901).
|
||||
pub fn typed_date(tpl: &Template, som: &str, text: &str) -> Option<String> {
|
||||
let f = template_field(tpl, som)?;
|
||||
if f.ui != Ui::DateTimeEdit {
|
||||
@@ -42,6 +43,20 @@ pub fn typed_date(tpl: &Template, som: &str, text: &str) -> Option<String> {
|
||||
if reads(&first).is_some() {
|
||||
return None;
|
||||
}
|
||||
let iso = alternatives(picture).into_iter().skip(1).filter_map(date_letters).find_map(|p| reads(&p))?;
|
||||
Some(iso_to_pattern(&iso, &first))
|
||||
let iso = alternatives(picture).into_iter().skip(1).filter(|a| is_date_clause(a)).filter_map(date_letters).find_map(|p| reads(&p))?;
|
||||
// Written in the first pattern only when it reads back as the same date: a year a two-digit
|
||||
// year can't hold would otherwise become another century's.
|
||||
let shown = iso_to_pattern(&iso, &first);
|
||||
(pattern_to_iso(&shown, &first).as_deref() == Some(iso.as_str())).then_some(shown)
|
||||
}
|
||||
|
||||
/// Whether picture clause `clause` is a date pattern: a `date{…}` clause (with or without a
|
||||
/// locale, `date(en_US){…}`), or a bare pattern, which a date field reads as a date. A clause of
|
||||
/// another category (`text{…}`, `num{…}`, `time{…}`) is not, whatever its letters.
|
||||
fn is_date_clause(clause: &str) -> bool {
|
||||
let clause = clause.trim();
|
||||
match clause.find(['{', '(']) {
|
||||
Some(i) => clause.get(..i).is_some_and(|category| category.trim().eq_ignore_ascii_case("date")),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2675,3 +2675,16 @@ fn a_date_typed_by_another_of_its_edit_pictures_patterns_is_written_in_the_first
|
||||
assert_eq!(typed("form[0].born[0]", "181026"), None, "one pattern: nothing else to try");
|
||||
assert_eq!(typed("form[0].name[0]", "261018"), None, "not a date field");
|
||||
}
|
||||
|
||||
/// Only date clauses are other ways to type a date, and a date is rewritten only when the first
|
||||
/// pattern keeps it: a later `text{…}` clause is no date pattern, and a year a two-digit first
|
||||
/// pattern can't hold leaves the text as typed instead of becoming another date.
|
||||
#[test]
|
||||
fn a_typed_date_is_rewritten_only_by_date_clauses_into_a_first_pattern_that_keeps_it() {
|
||||
let (tpl, _) = crate::parse(&crate::fixtures::date_alternatives_template()).unwrap();
|
||||
let typed = |som: &str, text: &str| crate::typed_date(&tpl, som, text);
|
||||
assert_eq!(typed("form[0].code[0]", "261018"), None, "text{{YYMMDD}} is not a date alternative");
|
||||
let short = "form[0].short[0]";
|
||||
assert_eq!(typed(short, "20261018").as_deref(), Some("261018"), "a year the first pattern keeps");
|
||||
assert_eq!(typed(short, "19011018"), None, "1901 as 01 would read back as 2001");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user