[ZZ1] insert.dateTime in the Handout/Notes Master view fills the master's date placeholder

PowerPoint: Header and Footer > Notes and Handouts > Date and time puts a date field in the
date placeholder of the notes and handout masters, and every handout and notes page shows it.
Before, with no text caret the command wrote the current slide's date placeholder (design
.headerFooter) even in those views, so the handout PDF showed nothing. Now it writes the selected
date placeholder, else the master's own, as a field (update) or plain text, answers where:
master, and refuses (changing nothing) when the master has no date placeholder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Zach Berry
2026-10-27 18:55:41 -05:00
co-authored by Claude Fable 5.1
parent 55e5ee56b4
commit 6a1b8f1e39
2 changed files with 113 additions and 1 deletions
@@ -149,6 +149,11 @@ fn apply_date(s: &mut Session, o: &DateOpts) -> Result<Value> {
}
return Ok(json!({"where": "caret", "format": o.format, "update": o.update, "text": o.sample}));
}
// Handout or Notes Master view: the master's date placeholder (the selected one, else the
// master's own), which every handout or notes page then shows.
if s.doc()?.selection.target.is_page_master() {
return write_master_date(s, o);
}
// Not editing: the slide's date placeholder (this slide only). A layout with no date
// placeholder gets a text box instead, so the chosen format is still inserted.
s.execute("design.headerFooter", &json!({"date": true, "all": false}))?;
@@ -158,6 +163,49 @@ fn apply_date(s: &mut Session, o: &DateOpts) -> Result<Value> {
Ok(json!({"where": "footer", "format": o.format, "update": o.update, "text": o.sample}))
}
/// Put the date in the date placeholder of the handout or notes master being edited.
fn write_master_date(s: &mut Session, o: &DateOpts) -> Result<Value> {
let (format, sample, lang, update) = (o.format.clone(), o.sample.clone(), o.lang.clone(), o.update);
let has_date = {
let st = s.doc()?;
crate::page_master(&st.doc, st.selection.target).is_some_and(|m| m.shapes.iter().any(|x| x.ph_type() == Some(deckcraft_model::PhType::Date)))
};
if !has_date {
return Err(bad(
"insert.dateTime",
"this master has no date placeholder; show it with handout.placeholders or notes.placeholders {date: true}",
));
}
// The text the master holds afterwards, which the answer reports (it can differ from the
// caller's sample when the placeholder's own language formats a fixed date).
let mut written = o.sample.clone();
s.edit(|doc, sel| {
let Some(m) = crate::page_master_mut(doc, sel.target) else { return Ok(false) };
let m = std::sync::Arc::make_mut(m);
let date = |x: &deckcraft_model::Shape| x.ph_type() == Some(deckcraft_model::PhType::Date);
let chosen = sel.shapes.iter().find_map(|id| m.shapes.iter().position(|x| x.id == *id && date(x)));
let Some(i) = chosen.or_else(|| m.shapes.iter().position(date)) else { return Ok(false) };
let Some(sh) = m.shapes.get_mut(i) else { return Ok(false) };
let mut props = sh.text.as_ref().and_then(|t| t.paragraphs.first()).and_then(|p| p.runs.first()).map(|r| r.props.clone()).unwrap_or_default();
// A fixed date reads in the placeholder's own language when the caller named none.
let text = match (&lang, &props.lang) {
(None, Some(l)) if !update => date_sample(&format, Some(l)).unwrap_or_else(|_| sample.clone()),
_ => sample.clone(),
};
if let Some(lang) = lang {
props.lang = Some(lang);
}
let kind = if update { RunKind::Field { field: format } } else { RunKind::Text };
let body = sh.text.clone().unwrap_or_default();
let mut para = body.paragraphs.first().cloned().unwrap_or_default();
written.clone_from(&text);
para.runs = vec![deckcraft_model::Run { text, props, kind }];
sh.text = Some(TextBody { paragraphs: vec![para], ..body });
Ok(true)
})?;
Ok(json!({"where": "master", "format": o.format, "update": o.update, "text": written}))
}
/// Point the current slide's date placeholder at this format (a field, or the sample as plain text).
fn write_date_placeholder(s: &mut Session, o: &DateOpts) -> Result<bool> {
let format = o.format.clone();