8
0
فهرست منبع

Refactor the model-to-view zero offset position mapper & fix the marker position handling.

Maciej Gołaszewski 6 سال پیش
والد
کامیت
c17b8bcc99

+ 41 - 1
packages/ckeditor5-list/src/todolistconverters.js

@@ -251,6 +251,46 @@ export function modelViewChangeChecked( onCheckedChange ) {
 	};
 }
 
+/**
+ * A model-to-view position at zero offset mapper.
+ *
+ * This helper ensures that position inside todo-list in the view is mapped after the checkbox.
+ *
+ * It only handles the position at the beginning of a list item as other positions are properly mapped be the default mapper.
+ *
+ * @param {module:engine/view/view~View} view
+ * @param {module:engine/conversion/mapper~Mapper} mapper
+ * @return {Function}
+ */
+export function mapModelToViewZeroOffsetPosition( view, mapper ) {
+	return ( evt, data ) => {
+		const modelPosition = data.modelPosition;
+		const parent = modelPosition.parent;
+
+		// Handle only position at the beginning of a todo list item.
+		if ( !parent.is( 'listItem' ) || parent.getAttribute( 'listType' ) != 'todo' || modelPosition.offset !== 0 ) {
+			return;
+		}
+
+		const viewLi = mapper.toViewElement( parent );
+		const label = findLabel( viewLi, view );
+
+		// If there is no label then most probably the default converter was overridden.
+		if ( !label ) {
+			return;
+		}
+
+		// Map the position to the next sibling (if it is not a marker) - most likely it will be a text node...
+		if ( label.nextSibling && !label.nextSibling.is( 'uiElement' ) ) {
+			data.viewPosition = view.createPositionAt( label.nextSibling, 0 );
+		}
+		// ... otherwise return position after the label.
+		else {
+			data.viewPosition = view.createPositionAfter( label );
+		}
+	};
+}
+
 // Creates a checkbox UI element.
 //
 // @private
@@ -288,7 +328,7 @@ function createCheckmarkElement( modelItem, viewWriter, isChecked, onChange ) {
 }
 
 // Helper method to find label element inside li.
-export function findLabel( viewItem, view ) {
+function findLabel( viewItem, view ) {
 	const range = view.createRangeIn( viewItem );
 
 	for ( const value of range ) {

+ 3 - 23
packages/ckeditor5-list/src/todolistediting.js

@@ -14,13 +14,13 @@ import TodoListCheckCommand from './todolistcheckcommand';
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 
 import {
-	modelViewInsertion,
 	dataModelViewInsertion,
 	dataModelViewTextInsertion,
 	dataViewModelCheckmarkInsertion,
+	mapModelToViewZeroOffsetPosition,
 	modelViewChangeChecked,
 	modelViewChangeType,
-	findLabel
+	modelViewInsertion
 } from './todolistconverters';
 
 /**
@@ -82,27 +82,7 @@ export default class TodoListEditing extends Plugin {
 			modelViewChangeChecked( listItem => this._handleCheckmarkChange( listItem ) )
 		);
 
-		// Fix view position on 0 offset.
-		editing.mapper.on( 'modelToViewPosition', ( evt, data ) => {
-			const view = editing.view;
-			const modelPosition = data.modelPosition;
-
-			if ( modelPosition.parent.is( 'listItem' ) && modelPosition.parent.getAttribute( 'listType' ) == 'todo' ) {
-				const viewLi = editing.mapper.toViewElement( data.modelPosition.parent );
-
-				if ( modelPosition.offset === 0 ) {
-					const label = findLabel( viewLi, view );
-
-					if ( label ) {
-						if ( label.nextSibling ) {
-							data.viewPosition = view.createPositionAt( label.nextSibling, 0 );
-						} else {
-							data.viewPosition = view.createPositionAfter( label );
-						}
-					}
-				}
-			}
-		}, { priority: 'low' } );
+		editing.mapper.on( 'modelToViewPosition', mapModelToViewZeroOffsetPosition( editing.view, editing.mapper ) );
 
 		data.upcastDispatcher.on( 'element:input', dataViewModelCheckmarkInsertion, { priority: 'high' } );
 

+ 7 - 7
packages/ckeditor5-list/tests/todolistediting.js

@@ -23,7 +23,7 @@ import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'
 
 /* global Event, document */
 
-describe.only( 'TodoListEditing', () => {
+describe( 'TodoListEditing', () => {
 	let editor, model, modelDoc, modelRoot, view, viewDoc;
 
 	beforeEach( () => {
@@ -455,12 +455,12 @@ describe.only( 'TodoListEditing', () => {
 			} );
 			model.change( writer => {
 				writer.addMarker( 'element1', {
-					range: writer.createRangeIn( writer.createPositionAt( modelRoot.getChild( 0 ), 0 ) ),
+					range: writer.createRange( writer.createPositionAt( modelRoot.getChild( 0 ), 0 ) ),
 					usingOperation: false
 				} );
 
 				writer.addMarker( 'element2', {
-					range: writer.createRangeIn( writer.createPositionAt( modelRoot.getChild( 0 ), 0 ) ),
+					range: writer.createRange( writer.createPositionAt( modelRoot.getChild( 0 ), 0 ) ),
 					usingOperation: false
 				} );
 
@@ -473,11 +473,11 @@ describe.only( 'TodoListEditing', () => {
 			assertEqualMarkup( getViewData( view ),
 				'<ul class="todo-list">' +
 					'<li>' +
-						'<span class="highlight">' +
-							'<label class="todo-list__checkmark" contenteditable="false"></label>' +
-							'<element1></element1>' +
+						'<label class="todo-list__checkmark" contenteditable="false"></label>' +
+						'[]<span class="highlight">' +
 							'<element2></element2>' +
-							'{}foo' +
+							'<element1></element1>' +
+							'foo' +
 						'</span>' +
 					'</li>' +
 					'<li>' +