etherpad-lite/src/node/utils
John McLear ef205bf2ac
fix(theme-color): dark address bar + no light-flash on dark-OS load (#7606) (#7909)
* fix(theme-color): emit media-scoped dark variant for iOS Safari (#7606)

The theme-color meta only had a single light value rendered server-side;
dark mode was applied purely by JS (skin_variants.ts) after page load.
iOS Safari colors the address bar at parse time and does not reliably
repaint when JS mutates the meta later, so dark-mode iPhone users kept a
white address bar above a dark toolbar (the green Chromium Playwright test
masked this because Chrome does honor the dynamic update).

Emit a prefers-color-scheme media-scoped pair server-side so the correct
color is chosen at first paint without JS:

  <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
  <meta name="theme-color" content="#485365" media="(prefers-color-scheme: dark)">

- Add SkinColors.darkToolbarColor() (reuses toolbarColorForTokens).
- Expose enableDarkMode via getPublicSettings so the templates can gate the
  dark variant on it (no dark variant when dark mode can't be reached).
- Apply to both pad.html and timeslider.html.
- updateThemeColorMeta now updates every theme-color meta so a manual
  #options-darkmode toggle still wins over the media scoping on
  desktop/Android.
- Backend + frontend tests updated to assert the media-scoped pair and the
  enableDarkMode-off case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(theme-color): prevent the light-mode flash on dark-OS load (#7606)

The theme-color meta fix corrects the address-bar tint, but dark-OS users
still saw the whole page painted light before the JS bundle ran and applied
the dark skin classes in postAceInit — a visible flash on every browser,
not just the mobile address bar.

Add a tiny blocking inline script in <head>, before the stylesheet, that
applies the dark skin classes to <html> synchronously during parse when the
client is in dark mode (matchMedia + no localStorage white-mode override).
The condition mirrors pad.ts's auto-switch, which still runs on init to wire
up the #options-darkmode toggle and theme the editor iframes (those don't
exist yet at parse time). Gated on the same enableDarkMode + colibris check
as the dark theme-color variant. Applied to pad.html and timeslider.html.

Verified in Chromium: at domcontentloaded a dark-OS client's <html> already
carries super-dark-editor/dark-background/super-dark-toolbar (no flash), and
a light-OS client is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(changelog): note the dark-mode address-bar + flash fix (#7606)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(theme-color): guard pre-paint script on #skinvariantsbuilder; ignore updater state

Address PR review:
- Copilot: the inline pre-paint dark-mode script must skip the auto-dark
  switch on the #skinvariantsbuilder hash, matching pad.ts — otherwise it
  forces super-dark classes on a dark-OS client and fights the variants
  builder UI. Added the guard to pad.html and timeslider.html and a backend
  assertion so it can't regress.
- Qodo: ignore var/update-state.json (runtime updater cache) so the server
  run that regenerates it can't dirty the tree or be committed accidentally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:54:08 +02:00
..
AbsolutePaths.ts chore: migrated settings to esm6 (#7062) 2025-08-04 22:42:50 +02:00
AdminSettingsRedact.ts fix(admin): show resolved runtime values on /admin/settings (#7803) (#7807) 2026-05-18 13:27:53 +01:00
anonymizeIp.ts feat(gdpr): IP/privacy audit (PR2 of #6701) (#7547) 2026-05-01 13:47:40 +01:00
checkValidRev.ts Added typescript to etherpad 2024-02-05 21:13:02 +01:00
Cleanup.ts chore: moved first files to esm (#7061) 2025-08-04 19:59:28 +02:00
Cli.ts chore: use args from cmd (#7112) 2025-09-03 21:01:20 +02:00
customError.ts Added typescript to etherpad 2024-02-05 21:13:02 +01:00
ensureAuthorTokenCookie.ts feat(gdpr): HttpOnly author-token cookie (PR3 of #6701) (#7548) 2026-05-03 05:56:56 +01:00
ExportEtherpad.ts fix(export): /export/etherpad honors the :rev URL segment (#7566) 2026-04-26 10:29:02 +02:00
ExportHelper.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
ExportHtml.ts Escape exported data attributes and warn on default/placeholder credentials (#7905) 2026-06-07 16:05:57 +01:00
ExportPdfNative.ts feat(export): native DOCX export via html-to-docx (opt-in) (#7568) 2026-05-08 18:33:50 +01:00
ExportSanitizeHtml.ts feat(export): native DOCX export via html-to-docx (opt-in) (#7568) 2026-05-08 18:33:50 +01:00
ExportTxt.ts feat!: replace Abiword with LibreOffice and add DOCX export (#7539) 2026-04-19 09:08:22 +01:00
ImportDocxNative.ts feat(export): native DOCX export via html-to-docx (opt-in) (#7568) 2026-05-08 18:33:50 +01:00
ImportEtherpad.ts harden: assorted server-side tightening for 3.0.2 (#7784) 2026-05-17 13:19:41 +01:00
ImportHtml.ts harden: assorted server-side tightening for 3.0.2 (#7784) 2026-05-17 13:19:41 +01:00
LibreOffice.ts chore: migrated settings to esm6 (#7062) 2025-08-04 22:42:50 +02:00
Minify.ts chore: migrated settings to esm6 (#7062) 2025-08-04 22:42:50 +02:00
MinifyWorker.ts Feat/frontend vitest (#6469) 2024-08-16 22:55:42 +02:00
NodeVersion.ts chore: moved first files to esm (#7061) 2025-08-04 19:59:28 +02:00
padDiff.ts fix: createDiffHTML API fails with "Not a changeset: undefined" (#7445) 2026-04-04 08:25:26 +01:00
path_exists.ts Moved path_exists and promises to es6 2024-08-18 19:52:21 +02:00
PluginCapabilities.ts feat(settings): default settings.enablePluginPadOptions to true (#7841) 2026-05-25 14:43:29 +01:00
promises.ts Moved path_exists and promises to es6 2024-08-18 19:52:21 +02:00
randomstring.ts chore: moved first files to esm (#7061) 2025-08-04 19:59:28 +02:00
run_cmd.ts feat(packaging): add Debian (.deb) build via nfpm with systemd unit (v2) (#7583) 2026-04-27 10:33:30 +01:00
sanitizePathname.ts Feat/frontend vitest (#6469) 2024-08-16 22:55:42 +02:00
sanitizeProxyPath.ts feat: support X-Forwarded-Prefix and X-Ingress-Path (#7802) (#7806) 2026-05-18 13:27:59 +01:00
Settings.ts fix(theme-color): dark address bar + no light-flash on dark-OS load (#7606) (#7909) 2026-06-08 21:54:08 +02:00
SettingsTree.ts Enforce 2-space indentation across codebase (#7426) 2026-04-01 19:48:45 +01:00
SkinColors.ts fix(theme-color): dark address bar + no light-flash on dark-OS load (#7606) (#7909) 2026-06-08 21:54:08 +02:00
socialMeta.ts feat: support X-Forwarded-Prefix and X-Ingress-Path (#7802) (#7806) 2026-05-18 13:27:59 +01:00
Stream.ts Added typescript to etherpad 2024-02-05 21:13:02 +01:00
tar.json Changeset: New API to simplify attribute processing 2021-11-21 04:11:41 -05:00
toolbar.ts fix(a11y): name role=toolbar regions, hide linemetricsdiv from AT (#7255) (#7777) 2026-05-16 13:08:33 +01:00
UpdateCheck.ts Drop swagger-ui, document telemetry, add opt-outs (#7524) (#7757) 2026-05-16 18:34:22 +01:00