Lists merge if new line character between lists is deleted
Creating an unordered list, adding a line break, then adding an unordered list renders correctly. When you delete the new line character between these lists, the lists merge, but data-list values are not updated, creating a strange experience - see screenshots.
Steps for Reproduction
- Create an unordered list
- Add a line break
- Create an ordered list
- Delete line break
- See that ordered list and unordered list have the same ol container, and data-list selectors are not consolidated.
Expected behavior: List items in the same ol container have the same data-list value
Actual behavior: List items in the same ol container can have different data-list values.
Platforms: Chrome
Include browser, operating system and respective versions
Version: 2.0.0-rc.4
Run Quill.version to find out
I fixed this programmatically in on change events with the following. I suspect there are more efficient ways to deal with this in quill internals, but as a work around for now:
mergeLists(): void {
const lines = this.editor?.getLines() ?? [];
const firstListItem = [];
let isListStartNode = false;
// Collect the first list item in each discrete list
for (const line of lines) {
if (line.domNode.tagName === 'LI' && !isListStartNode) {
isListStartNode = true;
firstListItem.push(line);
} else if (line.domNode.tagName === 'LI') {
isListStartNode = false;
}
}
// Ensure that all items in each discrete list have the same list style
for (const listItem of firstListItem) {
const listFormat = listItem.domNode.getAttribute('data-list');
let nextListElement = listItem.next;
while (nextListElement) {
nextListElement.format('list', listFormat, 'silent');
nextListElement = nextListElement.next;
}
}
}
I performed a similar operation when togglign between an ordered and bullet list using the config:
toolbar: {
container: `#rich-text-editor-toolbar-${this.guid}`,
handlers: {
list: this.onClickListButton
}
}
onClickListButton(value: string): void {
if (!this.Quill || !this.editor) {
return;
}
const range = this.editor.getSelection();
if (range) {
const formats = this.editor.getFormat(range);
if ((formats.list === 'ordered' && value === 'ordered') || (formats.list === 'bullet' && value === 'bullet')) {
this.editor.formatLine(range.index, range.length, 'list', false, 'user');
} else {
// Format selection to ensure that entire selection is converted to list
this.editor.formatLine(range.index, range.length, 'list', value, 'user');
// Iterate over all lines under the same parent, and ensure they have the same list styling
const line = this.editor.getLine(range.index)[0];
let child = line?.parent?.children?.head;
while (child) {
child.format('list', value, 'silent');
child = child.next;
}
}
}
}