diff --git a/.gitignore b/.gitignore index 71584e76bb5..fbd45ade780 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ plugin_packages playwright-report state.json /src/static/oidc +.claude/ diff --git a/settings.json.docker b/settings.json.docker index a265a9235cf..3fa7495038d 100644 --- a/settings.json.docker +++ b/settings.json.docker @@ -273,6 +273,7 @@ */ "padOptions": { "noColors": "${PAD_OPTIONS_NO_COLORS:false}", + "showAuthorColors": "${PAD_OPTIONS_SHOW_AUTHOR_COLORS:true}", "showControls": "${PAD_OPTIONS_SHOW_CONTROLS:true}", "showChat": "${PAD_OPTIONS_SHOW_CHAT:true}", "showLineNumbers": "${PAD_OPTIONS_SHOW_LINE_NUMBERS:true}", diff --git a/settings.json.template b/settings.json.template index 9f0bc55a00e..0a655cd5ad1 100644 --- a/settings.json.template +++ b/settings.json.template @@ -252,6 +252,7 @@ */ "padOptions": { "noColors": false, + "showAuthorColors": true, "showControls": true, "showChat": true, "showLineNumbers": true, diff --git a/src/node/utils/Settings.ts b/src/node/utils/Settings.ts index d25c3d4e1a3..f6f758d84a8 100644 --- a/src/node/utils/Settings.ts +++ b/src/node/utils/Settings.ts @@ -192,6 +192,7 @@ export type SettingsType = { defaultPadText: string, padOptions: { noColors: boolean, + showAuthorColors: boolean, showControls: boolean, showChat: boolean, showLineNumbers: boolean, @@ -398,6 +399,7 @@ const settings: SettingsType = { */ padOptions: { noColors: false, + showAuthorColors: true, showControls: true, showChat: true, showLineNumbers: true, diff --git a/src/static/js/pad.ts b/src/static/js/pad.ts index d9cc4e902ed..812fbc4170d 100644 --- a/src/static/js/pad.ts +++ b/src/static/js/pad.ts @@ -69,6 +69,13 @@ const getParameters = [ $('#clearAuthorship').hide(); }, }, + { + name: 'showAuthorColors', + checkVal: 'false', + callback: (val) => { + settings.showAuthorColorsDisabled = true; + }, + }, { name: 'showControls', checkVal: 'true', @@ -461,7 +468,10 @@ const pad = { chat.chatAndUsers(true); // stick it to the screen $('#options-chatandusers').prop('checked', true); // set the checkbox to on } - if (padcookie.getPref('showAuthorshipColors') === false) { + const authorColorsPref = padcookie.getPref('showAuthorshipColors'); + if (authorColorsPref === true) { + pad.changeViewOption('showAuthorColors', true); + } else if (authorColorsPref === false) { pad.changeViewOption('showAuthorColors', false); } if (padcookie.getPref('showLineNumbers') === false) { @@ -555,6 +565,13 @@ const pad = { this.changeViewOption('noColors', true); } + // If showAuthorColors is set to false in padOptions, default colors off. + // The user can still toggle them on via the checkbox; the cookie will + // override this default on subsequent visits. + if (settings.showAuthorColorsDisabled === true) { + this.changeViewOption('showAuthorColors', false); + } + // RTL override is applied in postAceInit (after padeditor.init resolves) // to avoid a race where setViewOptions(initialViewOptions) overwrites it. @@ -783,6 +800,7 @@ const init = () => pad.init(); const settings = { LineNumbersDisabled: false, noColors: false, + showAuthorColorsDisabled: false, useMonospaceFontGlobal: false, globalUserName: false, globalUserColor: false, diff --git a/src/static/js/pad_editor.ts b/src/static/js/pad_editor.ts index 7feb81e30ea..113b99c9c33 100644 --- a/src/static/js/pad_editor.ts +++ b/src/static/js/pad_editor.ts @@ -172,16 +172,15 @@ const padeditor = (() => { padutils.setCheckbox($('#options-linenoscheck'), v); v = getOption('showAuthorColors', true); + // noColors overrides showAuthorColors completely + if (settings.noColors) { + v = false; + } self.ace.setProperty('showsauthorcolors', v); $('#chattext').toggleClass('authorColors', v); $('iframe[name="ace_outer"]').contents().find('#sidedivinner').toggleClass('authorColors', v); padutils.setCheckbox($('#options-colorscheck'), v); - // Override from parameters if true - if (settings.noColors !== false) { - self.ace.setProperty('showsauthorcolors', !settings.noColors); - } - self.ace.setProperty('textface', newOptions.padFontFamily || ''); }, dispose: () => { diff --git a/src/static/js/types/SocketIOMessage.ts b/src/static/js/types/SocketIOMessage.ts index f2b8cfc14fa..99622b01e8d 100644 --- a/src/static/js/types/SocketIOMessage.ts +++ b/src/static/js/types/SocketIOMessage.ts @@ -239,6 +239,7 @@ export type PadOptionsMessage = { export type PadOption = { "noColors"?: boolean, + "showAuthorColors"?: boolean, "showControls"?: boolean, "showChat"?: boolean, "showLineNumbers"?: boolean, diff --git a/src/tests/frontend-new/specs/show_author_colors.spec.ts b/src/tests/frontend-new/specs/show_author_colors.spec.ts new file mode 100644 index 00000000000..fbd4cfce1b1 --- /dev/null +++ b/src/tests/frontend-new/specs/show_author_colors.spec.ts @@ -0,0 +1,41 @@ +import {expect, test} from "@playwright/test"; +import { + appendQueryParams, + clearPadContent, + getPadBody, + goToNewPad, + writeToPad, +} from "../helper/padHelper"; + +test.describe('showAuthorColors pad option', () => { + test('authorship colors checkbox is checked by default', async ({page}) => { + await goToNewPad(page); + const checkbox = page.locator('#options-colorscheck'); + await expect(checkbox).toBeChecked(); + }); + + test('noColors query param unchecks the authorship colors checkbox', async ({page}) => { + const padId = await goToNewPad(page); + await appendQueryParams(page, {noColors: 'true'}); + const checkbox = page.locator('#options-colorscheck'); + await expect(checkbox).not.toBeChecked(); + }); + + test('toggling authorship colors checkbox works', async ({page}) => { + await goToNewPad(page); + const padBody = await getPadBody(page); + + await clearPadContent(page); + await writeToPad(page, 'Hello colors'); + await expect(padBody.locator('div span').first()).toHaveAttribute('class', /author-/); + + // Uncheck colors + const checkbox = page.locator('#options-colorscheck'); + await checkbox.click(); + await expect(checkbox).not.toBeChecked(); + + // Re-check colors + await checkbox.click(); + await expect(checkbox).toBeChecked(); + }); +});