From 92b164b0c0ddb1cc198b3c3deedb3f180416ebf5 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 4 Jun 2026 16:13:11 +0100 Subject: [PATCH 1/3] css: restore URL wrapping in pad editor (#7894) Long URLs in the pad editor overflow instead of wrapping because the global a { white-space: nowrap } rule in pad.css overrides the wrapping properties set on #innerdocbody. Add explicit white-space, word-wrap, and overflow-wrap to #innerdocbody a so URLs wrap inside the editor while preserving no-wrap behavior for links elsewhere in the UI. Fixes #7894 --- src/static/css/iframe_editor.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/static/css/iframe_editor.css b/src/static/css/iframe_editor.css index a29c11573ae..703485c2138 100644 --- a/src/static/css/iframe_editor.css +++ b/src/static/css/iframe_editor.css @@ -53,6 +53,9 @@ html.outer-editor, html.inner-editor { #innerdocbody a { color: #2e96f3; + white-space: normal; + word-wrap: break-word; + overflow-wrap: break-word; } #innerdocbody.authorColors [class^='author-'] a { color: inherit; From 1b96379810cd5d9f44822cae53173f7b6cdbd224 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 4 Jun 2026 16:35:38 +0100 Subject: [PATCH 2/3] test: add regression test for long URL wrapping in pad editor (#7894) --- .../frontend-new/specs/url_wrapping.spec.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/tests/frontend-new/specs/url_wrapping.spec.ts diff --git a/src/tests/frontend-new/specs/url_wrapping.spec.ts b/src/tests/frontend-new/specs/url_wrapping.spec.ts new file mode 100644 index 00000000000..0bb3f88e4b3 --- /dev/null +++ b/src/tests/frontend-new/specs/url_wrapping.spec.ts @@ -0,0 +1,48 @@ +import {expect, test} from "@playwright/test"; +import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper"; + +test.beforeEach(async ({page}) => { + await goToNewPad(page); +}); + +// Regression test for https://github.com/ether/etherpad/issues/7894 +test.describe('long URL wrapping in pad editor', function () { + test('long URLs should wrap instead of overflowing the editor', async function ({page}) { + const padBody = await getPadBody(page); + await clearPadContent(page); + + // The fix for #7894 ensures #innerdocbody a has white-space: normal, + // word-wrap: break-word, and overflow-wrap: break-word to override + // the global a { white-space: nowrap } from pad.css. + const longUrl = + 'https://example.com/this/is/a/very/long/test/url/for/etherpad/regression/' + + 'issue/7894/wrapping/behavior/long/urls/should/wrap/instead/of/overflowing/' + + 'to/the/right/and/causing/awkward/rendering'; + + await writeToPad(page, longUrl + ' '); + + // Verify the URL became a clickable link + const link = padBody.locator('a'); + await expect(link).toHaveCount(1); + await expect(link).toHaveAttribute('href', longUrl); + + // Verify wrapping CSS properties are applied (the direct fix for #7894) + const cssProps = await link.evaluate((el) => { + const style = window.getComputedStyle(el); + return { + whiteSpace: style.whiteSpace, + wordWrap: style.wordWrap, + overflowWrap: style.overflowWrap, + }; + }); + + expect(cssProps.whiteSpace).toBe('normal'); + expect(cssProps.wordWrap).toBe('break-word'); + expect(cssProps.overflowWrap).toBe('break-word'); + + // Verify the link does not overflow the editor (actual wrapping behavior) + const linkWidth = await link.evaluate((el) => el.getBoundingClientRect().width); + const bodyWidth = await padBody.evaluate((el) => el.getBoundingClientRect().width); + expect(linkWidth).toBeLessThanOrEqual(bodyWidth); + }); +}); From ff3d76b7c5f7889e579560264b9977c1277ed019 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 4 Jun 2026 16:36:35 +0100 Subject: [PATCH 3/3] test: add regression test for long URL wrapping in pad editor (#7894) --- src/tests/frontend-new/specs/url_wrapping.spec.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/frontend-new/specs/url_wrapping.spec.ts b/src/tests/frontend-new/specs/url_wrapping.spec.ts index 0bb3f88e4b3..7e02286c3ef 100644 --- a/src/tests/frontend-new/specs/url_wrapping.spec.ts +++ b/src/tests/frontend-new/specs/url_wrapping.spec.ts @@ -19,7 +19,8 @@ test.describe('long URL wrapping in pad editor', function () { 'issue/7894/wrapping/behavior/long/urls/should/wrap/instead/of/overflowing/' + 'to/the/right/and/causing/awkward/rendering'; - await writeToPad(page, longUrl + ' '); + // Write a short word on line 1, then the long URL on line 2 + await writeToPad(page, 'hello\n' + longUrl + ' '); // Verify the URL became a clickable link const link = padBody.locator('a'); @@ -40,9 +41,13 @@ test.describe('long URL wrapping in pad editor', function () { expect(cssProps.wordWrap).toBe('break-word'); expect(cssProps.overflowWrap).toBe('break-word'); - // Verify the link does not overflow the editor (actual wrapping behavior) - const linkWidth = await link.evaluate((el) => el.getBoundingClientRect().width); - const bodyWidth = await padBody.evaluate((el) => el.getBoundingClientRect().width); - expect(linkWidth).toBeLessThanOrEqual(bodyWidth); + // The short line should be one line tall, the wrapped URL line should + // be much taller — this is the observable behavior that wrapping works. + const lines = padBody.locator('> div'); + await expect(lines).toHaveCount(2); + + const shortLineHeight = await lines.nth(0).evaluate((el) => el.getBoundingClientRect().height); + const longLineHeight = await lines.nth(1).evaluate((el) => el.getBoundingClientRect().height); + expect(longLineHeight).toBeGreaterThan(shortLineHeight * 1.5); }); });