The Show group stacked Ruler, Formula Bar, Gridlines and Headings in
one column, but the ribbon body fits only three rows, so Headings was
cut off at the bottom and could not be reached. The four checkboxes now
sit in two columns of two (Ruler/Gridlines, Formula Bar/Headings), as in
Excel's Show group. Checked in English and German, which has the
longest labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Excel stores the path of a linked workbook relative to the file that uses it, and rewrites it when the file is saved into another folder. The path was kept as text, so after Save As it named a file next to the new copy: a missing link, or another workbook with the same name. Relative externalLinkPath targets are now resolved against the folder the workbook was read from and written relative to the folder it is saved into (absolute when there is no relative path, on another drive).
Cell format 0 always mapped to the model's built-in Calibri 11 default, so the file's Normal font was replaced on save and every default-formatted cell changed size. The Normal style now takes the font of cell format 0, and a Normal font in the theme's body face is written with scheme="minor" again.
Excel uses the cached cell values of a saved file only when workbook.xml has both <fileVersion> and the calcFeatures extension; without them it recalculates everything on open, and lookups into closed workbooks come back as #CALC!. Both are now read into the workbook's kept content and written back in schema order: fileVersion first, the calcFeatures ext in <extLst> last. A workbook that had neither gets neither.
A page that frames GridCraft on the same origin can now open workbooks
in it and store what it saves, through postMessage, instead of Save and
Export becoming browser downloads. Built for a Nextcloud integration,
but nothing in it is host-specific.
Only the web shell changes:
- gridcraft:open from the parent goes through the inbox, like a picked
or dropped file
- Services::download sends the bytes to the parent (gridcraft:save); an
.xlsx workbook handed over counts as saved under that name
- gridcraft:dirty reports unsaved changes; gridcraft:ready and
gridcraft:failed report start-up
- in host mode no sample opens, and ?author= names the user for notes
and comments
Enabled only by ?host=parent inside a frame; only the parent window on
the page's own origin is heard or answered. Without it nothing changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G6GtUCaPiCMEQCN4QcdQnp
text_width sums in u64; an all-zero or non-finite dash array is written as
solid ([] 0 d); stroke widths are clamped to >= 0 (NaN -> 0); drawing calls
with non-finite or non-positive geometry return before storing anything.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Info strings were WinAnsi; PDF text strings are PDFDocEncoding or UTF-16BE.
Printable ASCII stays a literal string; anything else is a <FEFF...> hex
string. Info strings are capped at 1024 characters.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
home.rowHeight, home.autofitRowHeight and data.ungroup change row hidden
state without marking the edit structural, so SUBTOTAL(101-111) kept a stale
value. Found by the command-sequence fuzz (seed 3).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
With values on rows and no column field, the header cell above the data
column reads "Total", as Excel saves it (tabular checked against a real
file).
Σ Values in Columns always comes after the last column field: the column
layout doesn't place it anywhere else, so `pivot.moveField` no longer
stores a position there, the reader ignores where `-2` sits in colFields
and the writer puts it last.
`pivot.changeSource` removes dropped row and column fields one by one so
Σ Values keeps its place ahead of the field it preceded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Format Cells dialog drew English literals in every language. Its
tabs, labels, options and protection note now go through Language::tr,
as do dialog titles and the shared OK/Cancel buttons. The Fill tab is
keyed Format Cells|Fill because the Alignment tab's Fill is a different
word in some languages. d.tab keeps the English name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Excel rejects a text criterion longer than 255 characters in COUNTIF(S),
SUMIF(S), AVERAGEIF(S), MAXIFS and MINIFS with #VALUE!; GridCraft matched
it anyway. Found by the calc oracle on an Excel-saved report where a
268-character concatenated criterion caches #VALUE!.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The exponent sign goes right before the exponent digits, after any literal that follows
the E; ? pads exponent digits with spaces; % and commas never scale a scientific section;
zero shows 0 in every integer placeholder. Checked against the 248 TEXT() rows of Apache
POI's NumberFormatApproxTests.xlsx, copied as data into a test.
home.deleteRows/deleteColumns used only the last selected area. They now
take every area (or a comma list like "3:3,7:8"), merge them and delete
from the last to the first inside one edit, so it is one undo step.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A formula under a criteria label that names no field is evaluated for each record: its relative references move from the first record to that record, and the database labels name the record's fields, as in Excel. The calc evaluator passes the criteria reference to the database functions through Ctx::computed_criterion.
Ctrl+Shift+Arrow (and Shift+Arrow, Shift+PageUp/PageDown, Alt+Shift+PageUp/PageDown,
Ctrl+Shift+Home/End, Shift+Home) extend the selection by moving its far corner while the
active cell stays on the anchor. After the move the grid set `ensure_visible`, but the
scroll-into-view step in `grid::show` always targeted `selection.active`, which is the
anchor and is already on screen. So the view never followed the extension past the last
visible row or column.
The keyboard extension paths now also set `GridState::reveal_moving_end`, and the
ensure-visible step then scrolls to `Selection::moving_end()`, the corner opposite the
anchor. `selection.move` now uses that same helper (it had the logic inline) to find where
an extension starts. Other ensure-visible callers (Go To, Name Box, plain moves) still
reveal the active cell.
Regression test: crates/ui-egui/tests/selection_scroll.rs drives Ctrl+Shift+Up/Down/
Left/Right, Shift+Down/Right and Ctrl+Shift+Home/End through real egui key events and
checks that the moving end ends up on screen while the anchor and active cell stay put.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parser stripped _xludf. like _xlfn., but the two mean opposite things:
_xludf. marks a name Excel must not treat as a built-in. Keeping it in the
call name makes the call an unknown function (#NAME?, as in Excel) and the
writer emits it unchanged, so _xludf.EOMONTH() no longer saves as an
EOMONTH() call Excel repairs away.
CalcMode repeats in every worksheet substream like the iteration records and sets wb.calc.mode from the first worksheet; CalcPrecision sits in the globals and sets precision_as_displayed, matching calcMode and fullPrecision on the .xlsx side.
CalcIter, CalcCount and CalcDelta repeat in every worksheet substream and were skipped, so a workbook saved with iterative calculation on opened with it off and its circular references showed #CIRC!. They now set wb.calc from the first worksheet, as <calcPr iterate iterateCount iterateDelta> does for .xlsx.