fix: final checkup review follow-ups

- i18n: the spreadsheet notice's feature words (charts, drawings, macros,
  pivot tables, external links) were bare, case-insensitive zh-CN keys, so
  the page translator also renamed a charts/ or macros/ folder in the Files
  panel and a case of that name in the case picker. They are now scoped
  'Spreadsheet feature: <word>' keys; warningText() falls back to the plain
  word when the scoped key has no translation (English, no i18n). Removing
  the bare keys closes this branch's regression. The older 'models' key has
  the same class of problem; it is left alone here, since adding
  .case-combobox-option-label to USER_TEXT_SELECTOR would also untranslate
  the picker's two action rows and still miss the title attribute.
- Spreadsheet notice bar: marked data-i18n-skip. It is written already
  translated, item by item, and ends with a number format's code, which the
  observer's t() over the whole line rewrote ({name}, "Codeman").
- Connection tile (Header Stats Style Tiles): applyLocalization() now repaints
  the indicator, so a switch back to English no longer leaves the Chinese
  value word in its data-i18n-skip span until the next keystroke or ACK.
- Tiles default: loadAppSettingsFromStorage() no longer caches the
  posture-dependent showTileGridButton default, so the init merge never
  persists it; a 2-in-1 first opened as a tablet gets the button once docked.
  Every reader still resolves the absent key through a fresh
  getDefaultSettings(), so phones stay OFF and desktops ON.
- Tile grid over a split: closeSplitPane() skips Pane A's closing resize only
  when Pane A becomes a tile. With mergeSplit false (Open group as tiles, a
  stored grid) a Pane A left out of the set gets its full width back before
  the main terminal parks, instead of keeping the split's half width.
- By-case tab strip on tablets and phones: with the boxes dissolved, the
  -<case> part of a generated name shows again, so w1-alpha and w1-beta no
  longer both read "w1".

Each new assertion fails against the previous source.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-09 10:17:44 +02:00
parent 9d38cbf51a
commit a4511a0e48
10 changed files with 207 additions and 25 deletions
+50
View File
@@ -118,6 +118,56 @@ describe('the device default: ON on desktop, OFF on handhelds and touch-primary
expect(defaultsOn(PHONE).showTileGridButton).toBe(false);
});
it('never stores the posture default: a 2-in-1 first opened as a tablet gets the button once it is docked', () => {
// A fresh device caches loadAppSettingsFromStorage()'s fallback, and the
// server-settings merge saves that object (saveAppSettingsToStorage(merged)),
// so a default taken from the instantaneous primary pointer must not be in it.
let coarse = true;
const stored = new Map<string, string>();
const CodemanApp = function CodemanApp(this: unknown) {};
const context = vm.createContext({
CodemanApp,
VoiceInput: {},
localStorage: {
getItem: (k: string) => stored.get(k) ?? null,
setItem: (k: string, v: string) => stored.set(k, String(v)),
},
document: { getElementById: () => null },
console,
MobileDetection: {
isHandheldDevice: () => false,
isTouchDevice: () => true,
getDeviceType: () => 'desktop',
},
window: {
matchMedia: (q: string) => ({
matches: q === '(pointer: coarse)' ? coarse : q === '(pointer: fine)' && !coarse,
}),
},
});
vm.runInContext(SOURCE, context, { filename: 'settings-ui.js' });
type SettingsApp = {
getDefaultSettings(): Record<string, unknown>;
loadAppSettingsFromStorage(): Record<string, unknown>;
saveAppSettingsToStorage(s: Record<string, unknown>): void;
};
const app = Object.create(CodemanApp.prototype) as SettingsApp;
// What every reader resolves (header button, App Settings chip, chord).
const resolvedNow = () =>
(app.loadAppSettingsFromStorage().showTileGridButton ?? app.getDefaultSettings().showTileGridButton ?? true) ===
true;
// First load in tablet posture: OFF, and nothing about it is cached or saved.
expect(resolvedNow()).toBe(false);
expect(app.loadAppSettingsFromStorage()).not.toHaveProperty('showTileGridButton');
app.saveAppSettingsToStorage({ ...app.loadAppSettingsFromStorage() });
expect([...stored.values()].join('')).not.toContain('showTileGridButton');
// Docked (keyboard and trackpad: fine primary pointer): the desktop default.
coarse = false;
expect(resolvedNow()).toBe(true);
});
it('a context with no window at all still answers (the desktop default)', () => {
const CodemanApp = function CodemanApp(this: unknown) {};
const context = vm.createContext({