Layers: point copied live captions at copied anchored objects

Duplicate Layer pointed copied live captions at the copied objects before anchored objects in the copied stories had their ids, so a caption whose source is anchored kept the original object as its source. Anchored objects in copied stories also kept their captions and parent-item overrides unchanged. The copies now take their links after every anchored object has its id, and anchored objects get the same remapping as the other copies.
This commit is contained in:
dotCooCoo committed 2026-11-12 07:49:45 -08:00
1 parent 3ff65a381a
commit 72475633c2
1 file changed
+48 -5
+48 -5
View File
@@ -91,11 +91,6 @@ pub(super) fn duplicate_layer(s: &mut Session, p: &Value) -> Result<Value> {
copies.push((r, copy));
}
}
// Every copy has its id before overrides are pointed at the copied parent items.
for (r, mut copy) in copies {
move_copy(&mut copy, new_id, &ids);
d.insert_item(r, copy, None)?;
}
// A story copy holds the same anchored objects as the original: they get ids of their own, and the stories of
// anchored text frames get copies in turn. The story copies are taken in story order.
let mut pending: Vec<StoryId> = stories.values().copied().collect();
@@ -106,6 +101,17 @@ pub(super) fn duplicate_layer(s: &mut Session, p: &Value) -> Result<Value> {
renumber_anchored(d, &mut st, new_id, &mut stories, &mut ids, &mut pending);
d.stories.insert(new, Arc::new(st));
}
// Every copy, anchored objects included, has its id before overrides are pointed at the copied parent items and
// live captions at the copied objects.
for (r, mut copy) in copies {
move_copy(&mut copy, new_id, &ids);
d.insert_item(r, copy, None)?;
}
for new in stories.values() {
if let Some(st) = d.story_mut(*new) {
move_anchored(st, new_id, &ids);
}
}
// Each story copy gets its frames in the original order, text anchors of its own, which its cross-references
// and those of the other copies point at, and tables with ids of their own, the tables in its cells and notes
// included, allocated in story order.
@@ -375,6 +381,22 @@ fn move_copy(it: &mut Item, to: LayerId, ids: &HashMap<ItemId, ItemId>) {
}
}
/// Run [`move_copy`] on the anchored objects of `st` and of the stories of its table cells and notes. [`too_deep`] bounds
/// the nesting.
fn move_anchored(st: &mut Story, to: LayerId, ids: &HashMap<ItemId, ItemId>) {
for o in &mut st.objects {
move_copy(&mut Arc::make_mut(o).item, to, ids);
}
for t in st.tables.values_mut() {
for c in &mut Arc::make_mut(t).cells {
move_anchored(&mut c.text, to, ids);
}
}
for n in st.notes.iter_mut().chain(st.endnotes.iter_mut()) {
move_anchored(&mut Arc::make_mut(n).text, to, ids);
}
}
#[cfg(test)]
mod layer_tests {
use serde_json::json;
@@ -695,6 +717,27 @@ mod layer_tests {
assert_ne!(frame.id.0, a);
}
#[test]
fn duplicate_layer_points_copied_live_captions_at_copied_anchored_objects() {
let mut s = crate::Session::new();
s.execute("file.new", &json!({})).unwrap();
let base = s.doc().unwrap().doc.layers[0].id.0;
let a = s.execute("frame.create", &json!({"rect": [450, 450, 474, 490]})).unwrap()["id"].as_u64().unwrap();
s.execute("object.caption", &json!({"ids": [a], "text": "{name}", "live": true})).unwrap();
let text = json!({"rect": [72, 72, 400, 400], "content": "text", "text": "Before after."});
let f = s.execute("frame.create", &text).unwrap()["id"].as_u64().unwrap();
let sid = s.doc().unwrap().doc.item(designcraft_doc::ItemId(f)).unwrap().text_frame().unwrap().story;
// The caption's source moves into the story and keeps its id.
s.execute("anchored.insert", &json!({"ids": [a], "story": sid.0, "pos": 7})).unwrap();
let copy = s.execute("layer.duplicate", &json!({"id": base})).unwrap()["id"].as_u64().unwrap();
let d = &s.doc().unwrap().doc;
let anchored = d.anchored_items().into_iter().map(|(_, i)| i).find(|i| i.layer.0 == copy).unwrap();
assert_ne!(anchored.id.0, a);
let copies = on_layer(d, copy);
let caption = copies.iter().find_map(|i| i.live_caption.as_ref()).unwrap();
assert_eq!(caption.source, anchored.id, "the caption's copy follows the anchored object's copy");
}
#[test]
fn duplicate_layer_copies_the_hyperlinks_of_its_objects_and_text() {
use designcraft_doc::{HyperlinkDest, HyperlinkSource};