8
0
Quellcode durchsuchen

Merge pull request #8417 from ckeditor/i/7805

Fix (paste-from-office): Improved a mechanism that detects nested lists while pasting from Word. In some scenarios, pasting nested lists could produce invalid results in the editor. Closes #7805.
Maciej vor 5 Jahren
Ursprung
Commit
be5b989419

+ 13 - 0
packages/ckeditor5-paste-from-office/src/filters/list.js

@@ -361,6 +361,11 @@ function removeBulletElement( element, writer ) {
 // Whether previous and current item belongs to the same list. It is determined based on `item.id`
 // (extracted from `mso-list` style, see #getListItemData) and previous sibling of the current item.
 //
+// However, it's quite easy to change the `id` attribute for nested lists in Word. It will break the list feature while pasting.
+// Let's check also the `indent` attribute. If between those two elements, the difference is equal to 1, we can assume that
+// the `currentItem` is a beginning of the nested list because lists in CKEditor 5 always starts with the `indent=0` attribute.
+// See: https://github.com/ckeditor/ckeditor5/issues/7805.
+//
 // @param {Object} previousItem
 // @param {Object} currentItem
 // @returns {Boolean}
@@ -370,6 +375,14 @@ function isNewListNeeded( previousItem, currentItem ) {
 	}
 
 	if ( previousItem.id !== currentItem.id ) {
+		// See: https://github.com/ckeditor/ckeditor5/issues/7805.
+		//
+		// * List item 1.
+		//     - Nested list item 1.
+		if ( currentItem.indent - previousItem.indent === 1 ) {
+			return false;
+		}
+
 		return true;
 	}
 

+ 17 - 6
packages/ckeditor5-paste-from-office/tests/_data/list/index.js

@@ -16,6 +16,7 @@ import resumeTemplate from './resume-template/input.word2016.html';
 import nested from './nested/input.word2016.html';
 import nestedMixed from './nested-mixed/input.word2016.html';
 import nestedMultiple from './nested-multiple/input.word2016.html';
+import nestedMixedId from './nested-mixed-id/input.word2016.html';
 
 import simpleNormalized from './simple/normalized.word2016.html';
 import styledNormalized from './styled/normalized.word2016.html';
@@ -29,6 +30,7 @@ import resumeTemplateNormalized from './resume-template/normalized.word2016.html
 import nestedNormalized from './nested/normalized.word2016.html';
 import nestedMixedNormalized from './nested-mixed/normalized.word2016.html';
 import nestedMultipleNormalized from './nested-multiple/normalized.word2016.html';
+import nestedMixedIdNormalized from './nested-mixed-id/normalized.word2016.html';
 
 import simpleModel from './simple/model.word2016.html';
 import styledModel from './styled/model.word2016.html';
@@ -42,6 +44,7 @@ import resumeTemplateModel from './resume-template/model.word2016.html';
 import nestedModel from './nested/model.word2016.html';
 import nestedMixedModel from './nested-mixed/model.word2016.html';
 import nestedMultipleModel from './nested-multiple/model.word2016.html';
+import nestedMixedIdModel from './nested-mixed-id/model.word2016.html';
 
 export const fixtures = {
 	input: {
@@ -56,7 +59,8 @@ export const fixtures = {
 		resumeTemplate,
 		nested,
 		nestedMixed,
-		nestedMultiple
+		nestedMultiple,
+		nestedMixedId
 	},
 	normalized: {
 		simple: simpleNormalized,
@@ -70,7 +74,8 @@ export const fixtures = {
 		resumeTemplate: resumeTemplateNormalized,
 		nested: nestedNormalized,
 		nestedMixed: nestedMixedNormalized,
-		nestedMultiple: nestedMultipleNormalized
+		nestedMultiple: nestedMultipleNormalized,
+		nestedMixedId: nestedMixedIdNormalized
 	},
 	model: {
 		simple: simpleModel,
@@ -84,7 +89,8 @@ export const fixtures = {
 		resumeTemplate: resumeTemplateModel,
 		nested: nestedModel,
 		nestedMixed: nestedMixedModel,
-		nestedMultiple: nestedMultipleModel
+		nestedMultiple: nestedMultipleModel,
+		nestedMixedId: nestedMixedIdModel
 	}
 };
 
@@ -101,6 +107,7 @@ import resumeTemplateSafari from './resume-template/input.safari.word2016.html';
 import nestedSafari from './nested/input.safari.word2016.html';
 import nestedMixedSafari from './nested-mixed/input.safari.word2016.html';
 import nestedMultipleSafari from './nested-multiple/input.safari.word2016.html';
+import nestedMixedIdSafari from './nested-mixed-id/input.safari.word2016.html';
 
 import simpleNormalizedSafari from './simple/normalized.safari.word2016.html';
 import styledNormalizedSafari from './styled/normalized.safari.word2016.html';
@@ -112,6 +119,7 @@ import heading3StyledNormalizedSafari from './heading3-styled/normalized.safari.
 import heading7NormalizedSafari from './heading7/normalized.safari.word2016.html';
 import resumeTemplateNormalizedSafari from './resume-template/normalized.safari.word2016.html';
 import nestedMultipleNormalizedSafari from './nested-multiple/normalized.safari.word2016.html';
+import nestedMixedIdNormalizedSafari from './nested-mixed-id/normalized.safari.word2016.html';
 
 import styledSafariModel from './styled/model.safari.word2016.html';
 import resumeTemplateSafariModel from './resume-template/model.safari.word2016.html';
@@ -130,7 +138,8 @@ export const browserFixtures = {
 			resumeTemplate: resumeTemplateSafari,
 			nested: nestedSafari,
 			nestedMixed: nestedMixedSafari,
-			nestedMultiple: nestedMultipleSafari
+			nestedMultiple: nestedMultipleSafari,
+			nestedMixedId: nestedMixedIdSafari
 		},
 		normalized: {
 			simple: simpleNormalizedSafari,
@@ -144,7 +153,8 @@ export const browserFixtures = {
 			resumeTemplate: resumeTemplateNormalizedSafari,
 			nested: nestedNormalized,
 			nestedMixed: nestedMixedNormalized,
-			nestedMultiple: nestedMultipleNormalizedSafari
+			nestedMultiple: nestedMultipleNormalizedSafari,
+			nestedMixedId: nestedMixedIdNormalizedSafari
 		},
 		model: {
 			simple: simpleModel,
@@ -158,7 +168,8 @@ export const browserFixtures = {
 			resumeTemplate: resumeTemplateSafariModel,
 			nested: nestedModel,
 			nestedMixed: nestedMixedModel,
-			nestedMultiple: nestedMultipleModel
+			nestedMultiple: nestedMultipleModel,
+			nestedMixedId: nestedMixedIdModel
 		}
 	}
 };

Datei-Diff unterdrückt, da er zu groß ist
+ 341 - 0
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/input.safari.word2016.html


Datei-Diff unterdrückt, da er zu groß ist
+ 1089 - 0
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/input.word2016.html


+ 11 - 0
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/model.word2016.html

@@ -0,0 +1,11 @@
+<listItem listIndent="0" listStyle="disc" listType="bulleted">Lorem</listItem>
+<listItem listIndent="0" listStyle="disc" listType="bulleted">Ipsum</listItem>
+<listItem listIndent="1" listStyle="default" listType="numbered">Dolor</listItem>
+<listItem listIndent="1" listStyle="default" listType="numbered">Sit</listItem>
+<listItem listIndent="0" listStyle="disc" listType="bulleted">Amet</listItem>
+<paragraph></paragraph>
+<listItem listIndent="0" listStyle="default" listType="numbered">Lorem</listItem>
+<listItem listIndent="0" listStyle="default" listType="numbered">Ipsum</listItem>
+<listItem listIndent="1" listStyle="disc" listType="bulleted">Dolor</listItem>
+<listItem listIndent="1" listStyle="disc" listType="bulleted">Sit</listItem>
+<listItem listIndent="0" listStyle="default" listType="numbered">Amet</listItem>

BIN
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/nested-mixed-id.docx


+ 54 - 0
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/normalized.safari.word2016.html

@@ -0,0 +1,54 @@
+<ul style="list-style-type:disc">
+	<li class="MsoListParagraphCxSpFirst" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US">Lorem<o:p></o:p></span>
+	</li>
+	<li class="MsoListParagraphCxSpMiddle" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US">Ipsum<o:p></o:p></span>
+		<ol>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l0 level2 lfo2;text-indent:-18.0pt">
+				<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+				<span lang="EN-US">Dolor<o:p></o:p></span>
+			</li>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l0 level2 lfo2;text-indent:-18.0pt">
+				<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+				<span lang="EN-US">Sit<o:p></o:p></span>
+			</li>
+		</ol>
+	</li>
+</ul>
+
+<ul style="list-style-type:disc">
+	<li class="MsoListParagraphCxSpLast" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US">Amet<o:p></o:p></span>
+	</li>
+</ul>
+
+<p class="MsoNormal" style="-webkit-text-size-adjust:auto;-webkit-text-stroke-width:0px;caret-color:rgb(0, 0, 0);color:rgb(0, 0, 0);font-family:Calibri, sans-serif;font-size:11pt;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;line-height:15.693333625793457px;margin:0cm 0cm 8pt;orphans:auto;text-align:start;text-decoration:none;text-indent:0px;text-transform:none;white-space:normal;widows:auto;word-spacing:0px"><span lang="EN-US"></span></p>
+
+<ol>
+	<li class="MsoListParagraphCxSpFirst" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US">Lorem<o:p></o:p></span>
+	</li>
+	<li class="MsoListParagraphCxSpMiddle" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US">Ipsum<o:p></o:p></span>
+		<ul style="list-style-type:disc">
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l2 level2 lfo3;text-indent:-18.0pt">
+				<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+				<span lang="EN-US">Dolor<o:p></o:p></span>
+			</li>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l2 level2 lfo3;text-indent:-18.0pt">
+				<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+				<span lang="EN-US">Sit<o:p></o:p></span>
+			</li>
+		</ul>
+	</li>
+	<li class="MsoListParagraphCxSpLast" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US">Amet<o:p></o:p></span>
+	</li>
+</ol>

+ 56 - 0
packages/ckeditor5-paste-from-office/tests/_data/list/nested-mixed-id/normalized.word2016.html

@@ -0,0 +1,56 @@
+<ul style="list-style-type:disc">
+	<li class="MsoListParagraphCxSpFirst" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Lorem<o:p></o:p></span>
+	</li>
+	<li class="MsoListParagraphCxSpMiddle" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Ipsum<o:p></o:p></span>
+		<ol>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l0 level2 lfo2;text-indent:-18.0pt">
+				<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+				<span lang="EN-US" style="mso-ansi-language:EN-US">Dolor<o:p></o:p></span>
+			</li>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l0 level2 lfo2;text-indent:-18.0pt">
+				<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+				<span lang="EN-US" style="mso-ansi-language:EN-US">Sit<o:p></o:p></span>
+			</li>
+		</ol>
+	</li>
+</ul>
+
+<ul style="list-style-type:disc">
+	<li class="MsoListParagraphCxSpLast" style="mso-list:l1 level1 lfo1;text-indent:-18.0pt">
+		<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Amet<o:p></o:p></span>
+	</li>
+</ul>
+
+<p class="MsoNormal">
+	<span lang="EN-US" style="mso-ansi-language:EN-US"></span>
+</p>
+
+<ol>
+	<li class="MsoListParagraphCxSpFirst" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Lorem<o:p></o:p></span>
+	</li>
+	<li class="MsoListParagraphCxSpMiddle" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Ipsum<o:p></o:p></span>
+		<ul style="list-style-type:disc">
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l2 level2 lfo3;text-indent:-18.0pt">
+				<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+				<span lang="EN-US" style="mso-ansi-language:EN-US">Dolor<o:p></o:p></span>
+			</li>
+			<li class="MsoListParagraphCxSpMiddle" style="margin-left:72.0pt;mso-add-space:auto;mso-list:l2 level2 lfo3;text-indent:-18.0pt">
+				<span lang="EN-US" style="font-family:Symbol;mso-ansi-language:EN-US;mso-bidi-font-family:Symbol;mso-fareast-font-family:Symbol"></span>
+				<span lang="EN-US" style="mso-ansi-language:EN-US">Sit<o:p></o:p></span>
+			</li>
+		</ul>
+	</li>
+	<li class="MsoListParagraphCxSpLast" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt">
+		<span lang="EN-US" style="mso-ansi-language:EN-US;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin"></span>
+		<span lang="EN-US" style="mso-ansi-language:EN-US">Amet<o:p></o:p></span>
+	</li>
+</ol>

+ 29 - 0
packages/ckeditor5-paste-from-office/tests/filters/list.js

@@ -181,6 +181,35 @@ describe( 'PasteFromOffice - filters', () => {
 							'</li>' +
 						'</ol>' );
 				} );
+
+				it( 'handles indentation for nested lists with different the `mso-list-id` value', () => {
+					const html = '<p style="mso-list:l0 level1 lfo0">Foo 1</p><p style="mso-list:l1 level2 lfo0">Bar 1.1</p>';
+					const view = htmlDataProcessor.toView( html );
+
+					const styles = '@list l0\n' +
+						'{ mso-list-id: 111; }\n' +
+						'@list l0:level1\n' +
+						'{ mso-level-number-format: alpha-upper; }\n' +
+						'@list l1' +
+						'{ mso-list-id:222; }' +
+						'@list l1:level1\n' +
+						'{ mso-level-number-format: bullet; }' +
+						'@list l1:level2\n' +
+						'{ mso-level-number-format: bullet; }';
+
+					transformListItemLikeElementsIntoLists( view, styles );
+
+					expect( view.childCount ).to.equal( 1 );
+					expect( stringify( view ) ).to.equal(
+						'<ol style="list-style-type:upper-alpha">' +
+							'<li style="mso-list:l0 level1 lfo0">Foo 1' +
+								'<ul>' +
+									'<li style="mso-list:l1 level2 lfo0">Bar 1.1</li>' +
+								'</ul>' +
+							'</li>' +
+						'</ol>'
+					);
+				} );
 			} );
 
 			describe( 'list styles', () => {