quill icon indicating copy to clipboard operation
quill copied to clipboard

Lists merge if new line character between lists is deleted

Open pshatara90 opened this issue 1 year ago • 1 comments

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

  1. Create an unordered list
  2. Add a line break
  3. Create an ordered list
  4. Delete line break
  5. See that ordered list and unordered list have the same ol container, and data-list selectors are not consolidated. Screenshot 2024-04-08 at 10 35 56 AM Screenshot 2024-04-08 at 10 36 02 AM

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

pshatara90 avatar Apr 08 '24 17:04 pshatara90

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

pshatara90 avatar Apr 17 '24 18:04 pshatara90