css: restore URL wrapping in pad editor (#7894) (#7896)

* 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

* test: add regression test for long URL wrapping in pad editor (#7894)

* test: add regression test for long URL wrapping in pad editor (#7894)
This commit is contained in:
John McLear 2026-06-05 13:44:15 +01:00 committed by GitHub
parent 9e8f9cb513
commit 7b33892a76
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 0 deletions

View file

@ -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;

View file

@ -0,0 +1,53 @@
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';
// 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');
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');
// 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);
});
});