Skip to content

Commit 453bee7

Browse files
iBatAlexander Bulychev
andauthored
HtmlEditor: multiline break before list should not merge with the 1st list item (T1206652) (#110)
* Multiline break before list should not merge with the 1st list item (T1206652) * Turn on checks for devextreme 24.1 branch * Fix CI workflow * Fix tests * Cleanup * Fix tests * Review fix --------- Co-authored-by: Alexander Bulychev <[email protected]>
1 parent 408ed5e commit 453bee7

File tree

5 files changed

+78
-8
lines changed

5 files changed

+78
-8
lines changed

.github/workflows/html-editor-checks.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
- master
1010

1111
env:
12-
DEVEXTREME_BRANCHES: '["23_2", "23_1", "22_2", "22_1"]'
12+
DEVEXTREME_BRANCHES: '["24_1", "23_2", "23_1", "22_2", "22_1"]'
1313

1414
jobs:
1515
set-up-branches:
@@ -52,7 +52,7 @@ jobs:
5252
uses: ./quill-repo/.github/actions/html-editor/steps/build
5353
with:
5454
branch: ${{ matrix.branch }}
55-
devextreme-package-directory: ${{ matrix.branch == '23_2' && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
55+
devextreme-package-directory: ${{ (matrix.branch == '23_2' || matrix.branch == '24_1') && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
5656

5757
qunit:
5858
needs: [build-devextreme, set-up-branches]
@@ -74,7 +74,7 @@ jobs:
7474
uses: ./quill-repo/.github/actions/html-editor/steps/qunit-tests
7575
with:
7676
branch: ${{ matrix.branch }}
77-
devextreme-package-directory: ${{ matrix.branch == '23_2' && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
77+
devextreme-package-directory: ${{ (matrix.branch == '23_2' || matrix.branch == '24_1') && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
7878
test-suite: ${{ matrix.test-suite }}
7979

8080
testcafe:
@@ -99,6 +99,6 @@ jobs:
9999
uses: ./quill-repo/.github/actions/html-editor/steps/testcafe-tests
100100
with:
101101
branch: ${{ matrix.branch }}
102-
devextreme-package-directory: ${{ matrix.branch == '23_2' && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
102+
devextreme-package-directory: ${{ (matrix.branch == '23_2' || matrix.branch == '24_1') && 'devextreme-repo/packages/devextreme' || 'devextreme-repo' }}
103103
component-directory: ${{ matrix.test-suite.componentFolder }}
104104
quarantine-mode: ${{ matrix.test-suite.quarantineMode }}

modules/clipboard.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class Clipboard extends Module {
7373
this.quill.root.addEventListener('paste', this.onCapturePaste.bind(this));
7474
this.matchers = [];
7575
this.tableBlots = options.tableBlots ?? [];
76+
this.multilineParagraph = false;
7677
CLIPBOARD_CONFIG.concat(this.options.matchers).forEach(
7778
([selector, matcher]) => {
7879
this.addMatcher(selector, matcher);
@@ -129,6 +130,7 @@ class Clipboard extends Module {
129130
elementMatchers,
130131
textMatchers,
131132
nodeMatches,
133+
this.multilineParagraph,
132134
);
133135
// Remove trailing newline
134136
if (
@@ -382,23 +384,30 @@ function isPre(node) {
382384
return preNodes.get(node);
383385
}
384386

385-
function traverse(scroll, node, elementMatchers, textMatchers, nodeMatches) {
387+
function traverse(scroll, node, elementMatchers, textMatchers, nodeMatches, multilineParagraph) {
386388
// Post-order
387389
if (node.nodeType === node.TEXT_NODE) {
388390
return textMatchers.reduce((delta, matcher) => {
389391
return matcher(node, delta, scroll);
390392
}, new Delta());
391393
}
392394
if (node.nodeType === node.ELEMENT_NODE) {
393-
return Array.from(node.childNodes || []).reduce((delta, childNode) => {
395+
return Array.from(node.childNodes || []).reduce((delta, childNode, idx, allNodes) => {
394396
let childrenDelta = traverse(
395397
scroll,
396398
childNode,
397399
elementMatchers,
398400
textMatchers,
399401
nodeMatches,
402+
multilineParagraph,
400403
);
404+
const nextNode = idx < allNodes.length - 1 && allNodes[idx + 1];
405+
const isNextNodeList = nextNode
406+
&& nextNode.nodeType === node.ELEMENT_NODE
407+
&& ['ul', 'ol'].indexOf(nextNode.tagName.toLowerCase()) > -1;
408+
401409
if (childNode.nodeType === node.ELEMENT_NODE) {
410+
multilineParagraph = childNode.tagName.toLowerCase() === 'br';
402411
childrenDelta = elementMatchers.reduce((reducedDelta, matcher) => {
403412
return matcher(childNode, reducedDelta, scroll);
404413
}, childrenDelta);
@@ -409,7 +418,14 @@ function traverse(scroll, node, elementMatchers, textMatchers, nodeMatches) {
409418
childrenDelta,
410419
);
411420
}
412-
return delta.concat(childrenDelta);
421+
422+
const newDelta = delta.concat(childrenDelta);
423+
424+
if (multilineParagraph && isNextNodeList) {
425+
newDelta.insert('\n');
426+
}
427+
428+
return newDelta;
413429
}, new Delta());
414430
}
415431
return new Delta();

modules/multiline.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import MultilineBreak from '../blots/multiline_break';
44
import Module from '../core/module';
55

66
function breakMatcher(node) {
7-
if (!node.nextSibling && !node.previousSibling) {
7+
if (!(node.nextSibling || node.previousSibling)) {
88
return new Delta().insert('\n');
99
}
1010
return new Delta().insert({ multilineBreak: '' });

test/functional/example/list.html

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>DevExtreme-Quill Base Editing</title>
8+
<link rel="stylesheet" type="text/css" href="src/dx-quill.core.css"/>
9+
<script type="text/javascript" src="src/dx-quill.js"></script>
10+
</head>
11+
12+
<body>
13+
<div>
14+
<div id="editor">
15+
Test Headline
16+
<br><br>
17+
<ul>
18+
<li>First</li>
19+
<li>Second</li>
20+
<li>Third</li>
21+
</ul>
22+
</div>
23+
</div>
24+
</body>
25+
26+
<script>
27+
const editorElem = document.getElementById('editor');
28+
const editor = new DevExpress.Quill(editorElem, {
29+
modules: {
30+
multiline: true
31+
}
32+
});
33+
</script>
34+
</html>

test/functional/list.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { getEditorSelector, sanitizeTableHtml } from './helpers';
2+
import url from './helpers/getPageUrl';
3+
4+
fixture`HtmlEditor - list`
5+
.page(url(__dirname, './example/list.html'));
6+
7+
test('multiline break before list should not merge with the 1st list item (T1206652)', async (t) => {
8+
const editor = getEditorSelector('.ql-editor');
9+
const tableContent = sanitizeTableHtml(await editor.innerHTML);
10+
11+
await t.expect(tableContent.replace(/\s/g, ''))
12+
.eql(`
13+
<p>Test Headline<br><br></p>
14+
<ol>
15+
<li><span class="ql-ui" contenteditable="false"></span>First</li>
16+
<li><span class="ql-ui" contenteditable="false"></span>Second</li>
17+
<li><span class="ql-ui" contenteditable="false"></span>Third</li>
18+
</ol>
19+
`.replace(/\s/g, ''));
20+
});

0 commit comments

Comments
 (0)