Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore whitespace between pasted empty paragraphs #3990

Merged
merged 1 commit into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- **Clipboard** Convert newlines between inline elements to a space.
- **Clipboard** Avoid generating unsupported formats on paste.
- **Clipboard** Improve support for pasting from Google Docs and Microsoft Word.
- **Clipboard** Ignore whitespace between pasted empty paragraphs.
- **Syntax** Support highlight.js v10 and v11.

# 2.0.0-beta.2
Expand Down
33 changes: 18 additions & 15 deletions packages/quill/src/modules/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,12 @@ function deltaEndsWith(delta: Delta, text: string) {
return endText.slice(-1 * text.length) === text;
}

function isLine(node: Element) {
if (node.childNodes.length === 0) return false; // Exclude embed blocks
function isLine(node: Node, scroll: ScrollBlot) {
if (!(node instanceof Element)) return false;
const match = scroll.query(node);
// @ts-expect-error
if (match && match.prototype instanceof EmbedBlot) return false;

return [
'address',
'article',
Expand Down Expand Up @@ -334,12 +338,12 @@ function isLine(node: Element) {
].includes(node.tagName.toLowerCase());
}

function isBetweenInlineElements(node: HTMLElement) {
function isBetweenInlineElements(node: HTMLElement, scroll: ScrollBlot) {
return (
node.previousElementSibling &&
node.nextElementSibling &&
!isLine(node.previousElementSibling) &&
!isLine(node.nextElementSibling)
!isLine(node.previousElementSibling, scroll) &&
!isLine(node.nextElementSibling, scroll)
);
}

Expand Down Expand Up @@ -525,15 +529,13 @@ function matchList(node: Node, delta: Delta, scroll: ScrollBlot) {

function matchNewline(node: Node, delta: Delta, scroll: ScrollBlot) {
if (!deltaEndsWith(delta, '\n')) {
// @ts-expect-error
if (isLine(node)) {
if (isLine(node, scroll)) {
return delta.insert('\n');
}
if (delta.length() > 0 && node.nextSibling) {
let nextSibling: Node | null = node.nextSibling;
while (nextSibling != null) {
// @ts-expect-error
if (isLine(nextSibling)) {
if (isLine(nextSibling, scroll)) {
return delta.insert('\n');
}
const match = scroll.query(nextSibling);
Expand Down Expand Up @@ -596,7 +598,7 @@ function matchTable(
return delta;
}

function matchText(node: HTMLElement, delta: Delta) {
function matchText(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
// @ts-expect-error
let text = node.data;
// Word represents empty line with <o:p>&nbsp;</o:p>
Expand All @@ -607,7 +609,7 @@ function matchText(node: HTMLElement, delta: Delta) {
if (
text.trim().length === 0 &&
text.includes('\n') &&
!isBetweenInlineElements(node)
!isBetweenInlineElements(node, scroll)
) {
return delta;
}
Expand All @@ -620,16 +622,17 @@ function matchText(node: HTMLElement, delta: Delta) {
if (
(node.previousSibling == null &&
node.parentElement != null &&
isLine(node.parentElement)) ||
(node.previousSibling instanceof Element && isLine(node.previousSibling))
isLine(node.parentElement, scroll)) ||
(node.previousSibling instanceof Element &&
isLine(node.previousSibling, scroll))
) {
text = text.replace(/^\s+/, replacer.bind(replacer, false));
}
if (
(node.nextSibling == null &&
node.parentElement != null &&
isLine(node.parentElement)) ||
(node.nextSibling instanceof Element && isLine(node.nextSibling))
isLine(node.parentElement, scroll)) ||
(node.nextSibling instanceof Element && isLine(node.nextSibling, scroll))
) {
text = text.replace(/\s+$/, replacer.bind(replacer, false));
}
Expand Down
12 changes: 12 additions & 0 deletions packages/quill/test/unit/modules/clipboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ describe('Clipboard', () => {
expect(delta).toEqual(new Delta().insert('foo\nbar'));
});

test('space between empty paragraphs', () => {
const html = '<p></p> <p></p>';
const delta = createClipboard().convert({ html });
expect(delta).toEqual(new Delta().insert('\n'));
});

test('newline between empty paragraphs', () => {
const html = '<p></p>\n<p></p>';
const delta = createClipboard().convert({ html });
expect(delta).toEqual(new Delta().insert('\n'));
});

test('break', () => {
const html =
'<div>0<br>1</div><div>2<br></div><div>3</div><div><br>4</div><div><br></div><div>5</div>';
Expand Down