mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-05 01:58:58 +00:00
#2120: Remove Hyperlink clears links on cells with nothing stored
Addresses review comment 4455436875: `clear` clipped each range to the sheet's used range (stored cells) before removing links and notes, so a link from a file on an empty cell outside it was left in place, and nothing was removed on a sheet with no cells. Notes and links are now cleared over the whole range; cells and merges still only within the used range. Test: engine tests::clear_hyperlinks_removes_links_on_cells_with_nothing_stored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f9edafa800
commit
58e876a4d8
2 files changed
+33
-15
No files matched your search
@@ -245,20 +245,16 @@ fn clear(s: &mut Session, p: &Json, what: &str) -> Result<Json> {
|
||||
})
|
||||
};
|
||||
edit(s, |cx| {
|
||||
for r in &ranges {
|
||||
let r = match cx.wb.sheet(sheet).and_then(|sh| sh.used_range()) {
|
||||
Some(u) => match r.intersection(&u) {
|
||||
Some(x) => x,
|
||||
None => continue,
|
||||
},
|
||||
None => continue,
|
||||
for &whole in &ranges {
|
||||
// Cells are only stored inside the used range. Notes and links are kept apart from
|
||||
// them, so they are cleared over the whole range: one from a file can sit on a cell
|
||||
// with nothing stored in it.
|
||||
let used = cx.wb.sheet(sheet).and_then(|sh| sh.used_range()).and_then(|u| whole.intersection(&u));
|
||||
let skip = cx.wb.sheet(sheet).map(|sh| filtered_rows(sh, whole)).unwrap_or_default();
|
||||
let cells: Vec<(CellRef, Cell)> = match (cx.wb.sheet(sheet), used) {
|
||||
(Some(sh), Some(r)) => sh.cells.iter_range(r).filter(|(c, _)| !skip.contains(&c.row)).map(|(c, x)| (c, x.clone())).collect(),
|
||||
_ => Vec::new(),
|
||||
};
|
||||
let skip = cx.wb.sheet(sheet).map(|sh| filtered_rows(sh, r)).unwrap_or_default();
|
||||
let cells: Vec<(CellRef, Cell)> = cx
|
||||
.wb
|
||||
.sheet(sheet)
|
||||
.map(|sh| sh.cells.iter_range(r).filter(|(c, _)| !skip.contains(&c.row)).map(|(c, x)| (c, x.clone())).collect())
|
||||
.unwrap_or_default();
|
||||
// Report every stored cell we touch, even beyond a million coordinates in a sparse
|
||||
// selection. Removed formula anchors must also reach calc so their spills disappear.
|
||||
cx.changed.extend(cells.iter().map(|(c, _)| (sheet, *c)));
|
||||
@@ -294,14 +290,16 @@ fn clear(s: &mut Session, p: &Json, what: &str) -> Result<Json> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let cleared = |c: CellRef| r.contains(c) && !skip.contains(&c.row);
|
||||
let cleared = |c: CellRef| whole.contains(c) && !skip.contains(&c.row);
|
||||
if matches!(what, "all" | "comments") {
|
||||
sh.comments.retain(|c, _| !cleared(*c));
|
||||
}
|
||||
if matches!(what, "all" | "hyperlinks") {
|
||||
sh.hyperlinks.retain(|c, _| !cleared(*c));
|
||||
}
|
||||
if matches!(what, "all" | "formats") {
|
||||
if let Some(r) = used
|
||||
&& matches!(what, "all" | "formats")
|
||||
{
|
||||
let mut unmerged = false;
|
||||
sh.merges.retain(|m| {
|
||||
let keep = !r.contains_range(m) || skip.range(m.start.row..=m.end.row).next().is_some();
|
||||
|
||||
@@ -5457,3 +5457,23 @@ fn a_view_kept_through_redo_doesnt_make_the_saved_workbook_dirty() {
|
||||
assert_eq!(d.wb.active().unwrap().view, gridcraft_model::SheetViewMode::PageBreakPreview);
|
||||
assert!(!d.is_dirty(), "back at the saved edits, the view alone isn't a change");
|
||||
}
|
||||
|
||||
/// A link from a file can sit on a cell with nothing stored in it, past the used range (or on a
|
||||
/// sheet with no cells at all). Clear Hyperlinks, and Remove Hyperlink in the cell menu, must
|
||||
/// still remove it.
|
||||
#[test]
|
||||
fn clear_hyperlinks_removes_links_on_cells_with_nothing_stored() {
|
||||
let mut s = s();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "x"})).unwrap();
|
||||
let link = || gridcraft_model::Hyperlink { target: "https://example.com".into(), tooltip: None, external: true };
|
||||
let (a1, c5) = (CellRef::parse("A1").unwrap(), CellRef::parse("C5").unwrap());
|
||||
std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().wb).sheet_mut(0).unwrap().hyperlinks.insert(c5, link());
|
||||
s.execute("edit.clearHyperlinks", json!({"range": "C5"})).unwrap();
|
||||
assert!(!s.doc().unwrap().wb.active().unwrap().hyperlinks.contains_key(&c5), "the link past the used range is removed");
|
||||
|
||||
// No cells at all.
|
||||
s.execute("edit.clearAll", json!({"range": "A1"})).unwrap();
|
||||
std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().wb).sheet_mut(0).unwrap().hyperlinks.insert(a1, link());
|
||||
s.execute("edit.clearHyperlinks", json!({"range": "A1"})).unwrap();
|
||||
assert!(!s.doc().unwrap().wb.active().unwrap().hyperlinks.contains_key(&a1), "the link on an empty sheet is removed");
|
||||
}
|
||||
Reference in new issue
Block a user