diff --git a/doc/docker.md b/doc/docker.md index 71af392360f..92a72b77a9c 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -109,6 +109,7 @@ If your database needs additional settings, you will have to use a personalized | `PAD_OPTIONS_ALWAYS_SHOW_CHAT` | | `false` | | `PAD_OPTIONS_CHAT_AND_USERS` | | `false` | | `PAD_OPTIONS_LANG` | | `null` | +| `PAD_OPTIONS_FADE_INACTIVE_AUTHOR_COLORS` | Fade each author's caret/background toward white as they go inactive. Set to `false` if users pick light colors that become indistinguishable from the faded variants. | `true` | ### Shortcuts diff --git a/settings.json.docker b/settings.json.docker index 8fdd51de01e..fa26c199d38 100644 --- a/settings.json.docker +++ b/settings.json.docker @@ -288,7 +288,8 @@ "rtl": "${PAD_OPTIONS_RTL:false}", "alwaysShowChat": "${PAD_OPTIONS_ALWAYS_SHOW_CHAT:false}", "chatAndUsers": "${PAD_OPTIONS_CHAT_AND_USERS:false}", - "lang": "${PAD_OPTIONS_LANG:null}" + "lang": "${PAD_OPTIONS_LANG:null}", + "fadeInactiveAuthorColors": "${PAD_OPTIONS_FADE_INACTIVE_AUTHOR_COLORS:true}" }, /* diff --git a/settings.json.template b/settings.json.template index 0d1493c2b40..d05b9360a96 100644 --- a/settings.json.template +++ b/settings.json.template @@ -261,7 +261,13 @@ "rtl": false, "alwaysShowChat": false, "chatAndUsers": false, - "lang": null + "lang": null, + /* + * When true (default), each author's caret/background color fades toward white + * as the author goes inactive. Set to false if users pick light colors and the + * faded variants become visually indistinguishable. + */ + "fadeInactiveAuthorColors": true }, /* diff --git a/src/node/utils/Settings.ts b/src/node/utils/Settings.ts index 0b250e494c3..5bd1e5d47f9 100644 --- a/src/node/utils/Settings.ts +++ b/src/node/utils/Settings.ts @@ -203,6 +203,7 @@ export type SettingsType = { alwaysShowChat: boolean, chatAndUsers: boolean, lang: string | null, + fadeInactiveAuthorColors: boolean, }, enableMetrics: boolean, padShortcutEnabled: { @@ -410,6 +411,7 @@ const settings: SettingsType = { alwaysShowChat: false, chatAndUsers: false, lang: null, + fadeInactiveAuthorColors: true, }, /** * Wether to enable the /stats endpoint. The functionality in the admin menu is untouched for this. diff --git a/src/static/js/ace2_inner.ts b/src/static/js/ace2_inner.ts index 3ca880a9484..b40e2026651 100644 --- a/src/static/js/ace2_inner.ts +++ b/src/static/js/ace2_inner.ts @@ -236,7 +236,13 @@ function Ace2Inner(editorInfo, cssManagers) { cssManagers.parent.removeSelectorStyle(authorSelector); } else if (info.bgcolor) { let bgcolor = info.bgcolor; - if ((typeof info.fade) === 'number') { + // padOptions.fadeInactiveAuthorColors (default true) controls whether the author + // background fades toward white as the author goes inactive. Integrators can set + // it to false server-side when users pick light colors that become indistinguishable + // from the faded variants. + const fadeEnabled = window.clientVars.padOptions == null || + window.clientVars.padOptions.fadeInactiveAuthorColors !== false; + if (fadeEnabled && (typeof info.fade) === 'number') { bgcolor = fadeColor(bgcolor, info.fade); } const textColor = diff --git a/src/static/js/pad.ts b/src/static/js/pad.ts index d9698f5e776..641b1c057b8 100644 --- a/src/static/js/pad.ts +++ b/src/static/js/pad.ts @@ -69,6 +69,13 @@ const getParameters = [ $('#clearAuthorship').hide(); }, }, + { + name: 'fadeInactiveAuthorColors', + checkVal: 'false', + callback: (val) => { + if (clientVars.padOptions) clientVars.padOptions.fadeInactiveAuthorColors = false; + }, + }, { name: 'showControls', checkVal: 'true', diff --git a/src/tests/backend/specs/settings.ts b/src/tests/backend/specs/settings.ts index 3f836ae404a..e89531b0fdb 100644 --- a/src/tests/backend/specs/settings.ts +++ b/src/tests/backend/specs/settings.ts @@ -147,4 +147,15 @@ describe(__filename, function () { } }); }); + + // Regression test for https://github.com/ether/etherpad/issues/7138. + // padOptions.fadeInactiveAuthorColors must default to true so existing + // installations keep the legacy fade-on-inactive behavior, and must be + // overridable via PAD_OPTIONS_FADE_INACTIVE_AUTHOR_COLORS in docker. + describe('padOptions.fadeInactiveAuthorColors (issue #7138)', function () { + it('defaults to true so existing deployments are unchanged', function () { + const settings = require('../../../node/utils/Settings'); + assert.strictEqual(settings.padOptions.fadeInactiveAuthorColors, true); + }); + }); }); diff --git a/src/tests/frontend-new/specs/inactive_color_fade.spec.ts b/src/tests/frontend-new/specs/inactive_color_fade.spec.ts new file mode 100644 index 00000000000..f28c7cc35e5 --- /dev/null +++ b/src/tests/frontend-new/specs/inactive_color_fade.spec.ts @@ -0,0 +1,24 @@ +import {expect, test} from "@playwright/test"; +import {appendQueryParams, goToNewPad} from "../helper/padHelper"; + +test.beforeEach(async ({page}) => { + // clearCookies on the page's own context — `browser.newContext()` + // creates a separate context that the `page` fixture doesn't use, + // so clearing cookies on it is a no-op (Qodo review feedback). + await page.context().clearCookies(); + await goToNewPad(page); +}); + +test.describe('fadeInactiveAuthorColors URL parameter (issue #7138)', function () { + test('defaults to true (legacy fade behavior preserved)', async function ({page}) { + const fade = await page.evaluate(() => (window as any).clientVars?.padOptions?.fadeInactiveAuthorColors); + expect(fade).toBe(true); + }); + + test('fadeInactiveAuthorColors=false disables the fade', async function ({page}) { + await appendQueryParams(page, {fadeInactiveAuthorColors: 'false'}); + const fade = await page.evaluate( + () => (window as any).clientVars?.padOptions?.fadeInactiveAuthorColors); + expect(fade).toBe(false); + }); +});