fix: prevent crash when pasting bare <li> without parent list element (#7431)

When HTML containing <li> elements without a wrapping <ul> or <ol> is
pasted (e.g., from ChatGPT), the contentcollector crashes with
"TypeError: lineAttributes.list is undefined" because it assumes
_enterList() was already called by a parent list element.

The fix defaults bare <li> elements to bullet1 list type and properly
sets oldListTypeOrNull so the list state is cleaned up after the <li>
is processed. Also guards the .indexOf() call on lineAttributes.list.

Fixes: https://github.com/ether/etherpad-lite/issues/6665

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
John McLear 2026-04-03 07:11:08 +01:00 committed by GitHub
parent a324b1e3a8
commit 2f8e37805f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 1 deletions

View file

@ -504,9 +504,14 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author)
// See https://github.com/ether/etherpad-lite/issues/2412 for reasoning
if (!abrowser.chrome) oldListTypeOrNull = (_enterList(state, undefined) || 'none');
} else if (tname === 'li') {
// If the <li> has no parent <ul>/<ol> (e.g., pasted bare HTML), default to bullet list.
// See https://github.com/ether/etherpad-lite/issues/6665
if (!state.lineAttributes.list) {
oldListTypeOrNull = (_enterList(state, 'bullet1') || 'none');
}
state.lineAttributes.start = state.start || 0;
_recalcAttribString(state);
if (state.lineAttributes.list.indexOf('number') !== -1) {
if (state.lineAttributes.list && state.lineAttributes.list.indexOf('number') !== -1) {
/*
Nested OLs are not --> <ol><li>1</li><ol>nested</ol></ol>
They are --> <ol><li>1</li><li><ol><li>nested</li></ol></li></ol>

View file

@ -332,6 +332,33 @@ pre
wantAlines: ['+f*1+2+2'],
wantText: ['Need more space s !'],
},
{
description: 'Bare <li> without parent <ul>/<ol> should not crash (bug #6665)',
html: '<html><body><li>this should not crash</li></body></html>',
wantAlines: [
'*0*2*6+1+l',
],
wantText: ['*this should not crash'],
},
{
description: 'Multiple bare <li> elements without parent list',
html: '<html><body><li>first</li><li>second</li></body></html>',
wantAlines: [
'*0*2*6+1+5',
'*0*2*6+1+6',
],
wantText: ['*first', '*second'],
},
{
description: 'Mixed bare <li> and normal content',
html: '<html><body><p>before</p><li>bare item</li><p>after</p></body></html>',
wantAlines: [
'+6',
'*0*2*6+1+9',
'+5',
],
wantText: ['before', '*bare item', 'after'],
},
];
describe(__filename, function () {