From cd793294c42915ef5e4c9d5d23869d9965244752 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 26 Apr 2026 16:56:38 +0800 Subject: [PATCH] fix(chat): icon click, disabled toggles, username layout (#7590, #7592, #7593) (#7597) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(userlist): stop username input from overlapping the Log out button Fixes #7593. In the pad's Users popup, #myusernameform had no width set and the inside it took its natural content width, pushing past the Log out button and making the button overflow the popup at common widths. Constrain #myusernameform to 75px and make the input fill its container with box-sizing: border-box so the text field stays inside the form and the Log out button sits visibly next to it rather than getting covered or clipped off-screen. Low-risk, CSS-only change. No test plan beyond visual verification because the affected control is in the users popup UI. * fix(chat): bottom-align titlebar controls; restore chat icon click (#7590) Two regressions from the #7584 a11y refactor of the chat widget, both pure-CSS fixes scoped to the chat panel. 1. Title bar — `` → ` +
diff --git a/src/tests/frontend-new/specs/change_user_name.spec.ts b/src/tests/frontend-new/specs/change_user_name.spec.ts index b4f906846..ac0d03797 100644 --- a/src/tests/frontend-new/specs/change_user_name.spec.ts +++ b/src/tests/frontend-new/specs/change_user_name.spec.ts @@ -33,3 +33,28 @@ test('Own user name is shown when you enter a chat', async ({page})=> { expect(chatText).toContain('😃') expect(chatText).toContain(chatMessage) }); + +// #7593 review: the previous fix capped #myusernameform at 75px so a plugin- +// supplied "Log out" button wouldn't overflow, but vanilla etherpad-lite has +// no such button and the cap just made the username field too small. The +// colibris skin also pre-existing override of margin-left:35px (chosen for +// the chatAndUsers sticky layout) has been aligned with the base 10px. +test('#myusernameform has 10px left margin and is not width-capped', async ({page}) => { + await toggleUserList(page); + + const styles = await page.evaluate(() => { + const form = document.querySelector('#myusernameform') as HTMLElement; + const input = document.querySelector('#myusernameedit') as HTMLElement; + return { + formMarginLeft: getComputedStyle(form).marginLeft, + formWidth: getComputedStyle(form).width, + inputWidth: getComputedStyle(input).width, + }; + }); + + expect(styles.formMarginLeft).toBe('10px'); + // The form should size to its content / parent flex behaviour, NOT be capped + // at 75px — width should comfortably exceed that. + expect(parseFloat(styles.formWidth)).toBeGreaterThan(80); + expect(parseFloat(styles.inputWidth)).toBeGreaterThan(80); +}); diff --git a/src/tests/frontend-new/specs/chat.spec.ts b/src/tests/frontend-new/specs/chat.spec.ts index 2543f1dfc..b568cba1e 100644 --- a/src/tests/frontend-new/specs/chat.spec.ts +++ b/src/tests/frontend-new/specs/chat.spec.ts @@ -115,3 +115,79 @@ test('Checks showChat=false URL Parameter hides chat then' + // chat should be visible. expect(await secondChatIcon.isVisible()).toBe(true) }); + +// Regression: applyShowChat(false) sets inline `display: none` on #chatbox via +// jQuery .hide(); re-enabling chat doesn't undo it, and chat.show() only flips +// visibility via the .visible class — so without an explicit display reset the +// box stays hidden by the lingering inline style. (PR #7597) +test('chat icon click reveals chatbox after a disable → enable cycle', async ({page}) => { + await showSettings(page); + await page.locator('label[for="options-disablechat"]').click(); + await expect(page.locator('#options-disablechat')).toBeChecked(); + await expect(page.locator('#chaticon')).toBeHidden(); + + await page.locator('label[for="options-disablechat"]').click(); + await expect(page.locator('#options-disablechat')).not.toBeChecked(); + await expect(page.locator('#chaticon')).toBeVisible(); + await hideSettings(page); + + await showChat(page); + await expect(page.locator('#chatbox')).toBeVisible(); + await expect(page.locator('#chatbox')).toHaveClass(/visible/); +}); + +// Title-bar layout / glyph regressions from #7590 review. +test('chat title bar lays out as a centred flex row with underscore minimize', async ({page}) => { + await showChat(page); + + // Minimize button uses an underscore (sits at the bottom of its em-box and + // reads as a proper minimize indicator); it must not silently revert to + // − or a hyphen. + await expect(page.locator('#titlecross')).toHaveText('_'); + + const styles = await page.evaluate(() => { + const cs = (sel: string) => getComputedStyle(document.querySelector(sel)!); + const rect = (sel: string) => document.querySelector(sel)!.getBoundingClientRect(); + const tb = rect('#titlebar'); + const lab = rect('#titlelabel'); + const sticky = rect('#titlesticky'); + return { + titlebarDisplay: cs('#titlebar').display, + titlebarAlignItems: cs('#titlebar').alignItems, + labelFlex: cs('#titlelabel').flexGrow, + crossFloat: cs('#titlecross').float, + crossTransform: cs('#titlecross').transform, + stickyFloat: cs('#titlesticky').float, + // Visual symmetry — CHAT's left edge sits roughly the same distance + // from the title-bar left edge as the rightmost button sits from the + // right edge. Tested via rendered geometry rather than CSS literal so + // we don't get tripped up by skin overrides (colibris ships its own + // #titlebar padding rule). + leftGap: lab.left - tb.left, + rightGap: tb.right - sticky.right, + }; + }); + expect(styles.titlebarDisplay).toBe('flex'); + expect(styles.titlebarAlignItems).toBe('center'); + // Title takes the remaining width so corner buttons sit at the right edge. + expect(styles.labelFlex).toBe('1'); + // Buttons are flex items, not floats — old `float: right` layout must stay gone. + expect(styles.crossFloat).toBe('none'); + expect(styles.stickyFloat).toBe('none'); + // 5px lift on #titlecross so the `_` glyph reads near the title's baseline + // rather than at the very bottom of the row. + expect(styles.crossTransform).not.toBe('none'); + // Padding looks symmetric (within 2px to allow for sub-pixel rounding). + expect(Math.abs(styles.leftGap - styles.rightGap)).toBeLessThanOrEqual(2); +}); + +// Regression: #chaticon was a
before the #7584 a11y refactor; once it +// became a