From 6c9f0e8073f5de74e709fdd4356df2601a3c9eb6 Mon Sep 17 00:00:00 2001 From: Zihua Li Date: Mon, 19 Feb 2024 22:17:17 +0800 Subject: [PATCH] Fix getSemanticHTML for list items (#4016) --- CHANGELOG.md | 4 +- packages/quill/src/core/editor.ts | 10 ++--- packages/quill/test/unit/core/editor.spec.ts | 45 ++++++++++++-------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 840366d38e..6067230dd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ # [Unreleased] +- Fix `Quill#getSemanticHTML()` for list items + # 2.0.0-rc.2 - Fix toolbar button state not updated in some cases - Narrower `BubbleTheme.tooltip` type -- Fix `Selection.getBounds()` when starting range at end of text node +- Fix `Selection#getBounds()` when starting range at end of text node - Improve compatibility with esbuild # 2.0.0-rc.1 diff --git a/packages/quill/src/core/editor.ts b/packages/quill/src/core/editor.ts index edf35ba58b..b73d82ec33 100644 --- a/packages/quill/src/core/editor.ts +++ b/packages/quill/src/core/editor.ts @@ -199,9 +199,9 @@ class Editor { const [line, lineOffset] = this.scroll.line(index); if (line) { const lineLength = line.length(); - if (line.length() >= lineOffset + length) { - const excludeOuterTag = !(lineOffset === 0 && length === lineLength); - return convertHTML(line, lineOffset, length, excludeOuterTag); + const isWithinLine = line.length() >= lineOffset + length; + if (isWithinLine && !(lineOffset === 0 && length === lineLength)) { + return convertHTML(line, lineOffset, length, true); } return convertHTML(this.scroll, index, length, true); } @@ -364,7 +364,7 @@ function convertHTML( blot: Blot, index: number, length: number, - excludeOuterTag = false, + isRoot = false, ): string { if ('html' in blot && typeof blot.html === 'function') { return blot.html(index, length); @@ -395,7 +395,7 @@ function convertHTML( blot.children.forEachAt(index, length, (child, offset, childLength) => { parts.push(convertHTML(child, offset, childLength)); }); - if (excludeOuterTag || blot.statics.blotName === 'list') { + if (isRoot || blot.statics.blotName === 'list') { return parts.join(''); } const { outerHTML, innerHTML } = blot.domNode as Element; diff --git a/packages/quill/test/unit/core/editor.spec.ts b/packages/quill/test/unit/core/editor.spec.ts index ecfdcbadac..2519cce417 100644 --- a/packages/quill/test/unit/core/editor.spec.ts +++ b/packages/quill/test/unit/core/editor.spec.ts @@ -1,14 +1,14 @@ import Delta from 'quill-delta'; import Editor from '../../../src/core/editor'; import Block from '../../../src/blots/block'; -import Selection, { Range } from '../../../src/core/selection'; +import { Range } from '../../../src/core/selection'; import Scroll from '../../../src/blots/scroll'; import { Registry } from 'parchment'; import Text from '../../../src/blots/text'; import Emitter from '../../../src/core/emitter'; import Break from '../../../src/blots/break'; import { describe, expect, test } from 'vitest'; -import { createRegistry, createScroll } from '../__helpers__/factory'; +import { createRegistry } from '../__helpers__/factory'; import List, { ListContainer } from '../../../src/formats/list'; import Bold from '../../../src/formats/bold'; import Image from '../../../src/formats/image'; @@ -25,11 +25,15 @@ import { SizeClass } from '../../../src/formats/size'; import Blockquote from '../../../src/formats/blockquote'; import IndentClass from '../../../src/formats/indent'; import { ColorClass } from '../../../src/formats/color'; - -const createEditor = (html: string | { html: string }) => { - const scroll = createScroll( - html, - createRegistry([ +import Quill from '../../../src/core'; +import { normalizeHTML } from '../__helpers__/utils'; + +const createEditor = (html: string) => { + const container = document.createElement('div'); + container.innerHTML = normalizeHTML(html); + document.body.appendChild(container); + const quill = new Quill(container, { + registry: createRegistry([ ListContainer, List, IndentClass, @@ -49,8 +53,8 @@ const createEditor = (html: string | { html: string }) => { Blockquote, SizeClass, ]), - ); - return new Editor(scroll); + }); + return quill.editor; }; describe('Editor', () => { @@ -786,9 +790,9 @@ describe('Editor', () => { }); test('code block', () => { - const editor = createEditor({ - html: '

0

1
23


', - }); + const editor = createEditor( + '

0

1
23


', + ); editor.applyDelta(new Delta().delete(4).retain(1).delete(2)); expect(editor.scroll.domNode.innerHTML).toEqual('

2

'); }); @@ -1134,10 +1138,10 @@ describe('Editor', () => { test('cursor with preformat', () => { const editor = createEditor('

0123

'); - const selection = new Selection(editor.scroll, editor.scroll.emitter); - selection.setRange(new Range(2)); - selection.format('underline', true); - selection.format('color', 'red'); + const quill = Quill.find(editor.scroll.domNode.parentElement!) as Quill; + quill.selection.setRange(new Range(2)); + quill.selection.format('underline', true); + quill.selection.format('color', 'red'); expect(editor.getFormat(2)).toEqual({ bold: true, italic: true, @@ -1228,6 +1232,11 @@ describe('Editor', () => { expect(editor.getHTML(0, 5)).toEqual('
Test
'); }); + test('entire list item', () => { + const editor = createEditor(''); + expect(editor.getHTML(0, 5)).toEqual(''); + }); + test('across lines', () => { const editor = createEditor( '

Header

Text

Quote
', @@ -1352,8 +1361,8 @@ describe('Editor', () => { }); test('text within tag', () => { - const editor = createEditor('

a

'); - expect(editor.getHTML(0, 1)).toEqual('a'); + const editor = createEditor('

a

'); + expect(editor.getHTML(0, 1)).toEqual('a'); }); test('escape html', () => {