Procházet zdrojové kódy

Use name instead of label. Update MentionEditing tests.

Maciej Gołaszewski před 6 roky
rodič
revize
22a7b6d678

+ 2 - 2
packages/ckeditor5-mention/src/mentioncommand.js

@@ -43,12 +43,12 @@ export default class MentionCommand extends Command {
 		const mention = options.mention;
 		const range = options.range || selection.getFirstRange();
 
-		const label = mention.label || mention;
+		const name = mention.name || mention;
 
 		model.change( writer => {
 			writer.remove( range );
 
-			writer.insertText( `${ marker }${ label }`, { mention }, range.start );
+			writer.insertText( `${ marker }${ name }`, { mention }, range.start );
 			writer.insertText( ' ', model.document.selection.focus );
 		} );
 	}

+ 14 - 5
packages/ckeditor5-mention/src/mentionediting.js

@@ -40,18 +40,20 @@ export default class MentionEditing extends Plugin {
 			},
 			model: {
 				key: 'mention',
-				value: viewItem => {
-					return viewItem.getAttribute( 'data-mention' );
-				}
+				value: viewItem => ( {
+					name: viewItem.getAttribute( 'data-mention' )
+				} )
 			}
 		} );
 
 		editor.conversion.for( 'downcast' ).attributeToElement( {
 			model: 'mention',
 			view: ( modelAttributeValue, viewWriter ) => {
+				const mention = modelAttributeValue && modelAttributeValue.name || modelAttributeValue;
+
 				return viewWriter.createAttributeElement( 'span', {
 					class: 'mention',
-					'data-mention': modelAttributeValue
+					'data-mention': mention
 				} );
 			}
 		} );
@@ -77,7 +79,14 @@ export default class MentionEditing extends Plugin {
 
 					if ( nodeBefore && nodeBefore.hasAttribute( 'mention' ) ) {
 						const text = nodeBefore.data;
-						if ( text != nodeBefore.getAttribute( 'mention' ) ) {
+
+						const mention = nodeBefore.getAttribute( 'mention' );
+
+						const name = mention.name || mention;
+
+						const textName = text.slice( 1 );
+
+						if ( textName != name ) {
 							writer.removeAttribute( 'mention', nodeBefore );
 							wasChanged = true;
 						}

+ 7 - 7
packages/ckeditor5-mention/src/mentioneditingelement.js

@@ -38,12 +38,12 @@ class MentionCommand extends Command {
 		const item = options.mention;
 		const range = options.range || selection.getFirstRange();
 
-		const label = item.label || item;
+		const name = item.name || item;
 
 		model.change( writer => {
 			writer.remove( range );
 
-			const mention = writer.createElement( 'mentionElement', { label, item } );
+			const mention = writer.createElement( 'mentionElement', { name, item } );
 
 			model.insertContent( mention );
 			writer.insertText( ' ', model.document.selection.focus );
@@ -74,7 +74,7 @@ export default class MentionElementEditing extends Plugin {
 			allowWhere: '$text',
 			isObject: true,
 			isInline: true,
-			allowAttributes: [ 'label', 'item' ]
+			allowAttributes: [ 'name', 'item' ]
 		} );
 
 		editor.conversion.for( 'downcast' ).elementToElement( {
@@ -82,7 +82,7 @@ export default class MentionElementEditing extends Plugin {
 			view: ( modelItem, viewWriter ) => {
 				const mentionElement = viewWriter.createContainerElement( 'span', { class: 'mention' } );
 
-				const viewText = viewWriter.createText( modelItem.getAttribute( 'label' ) );
+				const viewText = viewWriter.createText( modelItem.getAttribute( 'name' ) );
 
 				viewWriter.insert( viewWriter.createPositionAt( mentionElement, 0 ), viewText );
 
@@ -93,17 +93,17 @@ export default class MentionElementEditing extends Plugin {
 		editor.conversion.for( 'upcast' ).elementToElement( {
 			view: 'mentionElement',
 			model: ( viewElement, modelWriter ) => {
-				let label = 'general';
+				let name = 'general';
 
 				if ( viewElement.childCount ) {
 					const text = viewElement.getChild( 0 );
 
 					if ( text.is( 'text' ) ) {
-						label = text;
+						name = text;
 					}
 				}
 
-				return modelWriter.createElement( 'mentionElement', { label } );
+				return modelWriter.createElement( 'mentionElement', { name } );
 			}
 		} );
 

+ 4 - 4
packages/ckeditor5-mention/src/mentioneditingmarker.js

@@ -44,19 +44,19 @@ class MentionCommand extends Command {
 		const item = options.mention;
 		const range = options.range || selection.getFirstRange();
 
-		const label = item.label || item;
+		const name = item.name || item;
 
 		model.change( writer => {
 			writer.remove( range );
 
-			const text = writer.createText( '@' + label );
+			const text = writer.createText( '@' + name );
 
 			writer.insert( text, selection.focus );
 
 			// TODO dumb
-			const name = createMentionMarkerId( label );
+			const markerName = createMentionMarkerId( name );
 
-			writer.addMarker( name, {
+			writer.addMarker( markerName, {
 				range: writer.createRange( selection.focus.getShiftedBy( -text.data.length ), selection.focus ),
 				usingOperation: true,
 				affectData: true

+ 4 - 4
packages/ckeditor5-mention/src/mentionui.js

@@ -102,7 +102,7 @@ export default class MentionUI extends Plugin {
 		this._mentionsView.listView.items.bindTo( this._items ).using( data => {
 			// itemRenderer
 			const { item, marker } = data;
-			const { label } = item;
+			const { name } = item;
 
 			const listItemView = new MentionListItemView( editor.locale );
 
@@ -117,7 +117,7 @@ export default class MentionUI extends Plugin {
 			} else {
 				const buttonView = new ButtonView( editor.locale );
 
-				buttonView.label = label;
+				buttonView.label = name;
 				buttonView.withText = true;
 
 				listItemView.children.add( buttonView );
@@ -197,8 +197,8 @@ export default class MentionUI extends Plugin {
 				.then( feed => {
 					this._items.clear();
 
-					for ( const label of feed ) {
-						const item = typeof label != 'object' ? { label } : label;
+					for ( const name of feed ) {
+						const item = typeof name != 'object' ? { name } : name;
 
 						this._items.add( { item, marker } );
 					}

+ 7 - 7
packages/ckeditor5-mention/tests/manual/mention-custom-renderer.js

@@ -36,7 +36,7 @@ ClassicEditor
 					span.classList.add( 'custom-item' );
 					span.id = `mention-list-item-id-${ item.id }`;
 
-					span.innerHTML = `${ item.label } <span class="custom-item-username">@${ item.username }</span>`;
+					span.innerHTML = `${ item.name } <span class="custom-item-username">@${ item.username }</span>`;
 
 					return span;
 				}
@@ -52,14 +52,14 @@ ClassicEditor
 
 function getFeed( feedText ) {
 	return Promise.resolve( [
-		{ id: '1', label: 'Barney Stinson', username: 'swarley' },
-		{ id: '2', label: 'Lily Aldrin', username: 'lilypad' },
-		{ id: '3', label: 'Marshall Eriksen', username: 'marshmallow' },
-		{ id: '4', label: 'Robin Scherbatsky', username: 'rsparkles' },
-		{ id: '5', label: 'Ted Mosby', username: 'tdog' }
+		{ id: '1', name: 'Barney Stinson', username: 'swarley' },
+		{ id: '2', name: 'Lily Aldrin', username: 'lilypad' },
+		{ id: '3', name: 'Marshall Eriksen', username: 'marshmallow' },
+		{ id: '4', name: 'Robin Scherbatsky', username: 'rsparkles' },
+		{ id: '5', name: 'Ted Mosby', username: 'tdog' }
 	].filter( item => {
 		const searchString = feedText.toLowerCase();
 
-		return item.label.toLowerCase().includes( searchString ) || item.username.toLowerCase().includes( searchString );
+		return item.name.toLowerCase().includes( searchString ) || item.username.toLowerCase().includes( searchString );
 	} ) );
 }

+ 6 - 6
packages/ckeditor5-mention/tests/manual/mention-custom-renderer.md

@@ -4,14 +4,14 @@
 
 The mention configuration with custom balloon panel item renderer.
 
-The list is returned in promise (no timeout) and is filtered for any match of `label` and `username` (custom feed):
+The list is returned in promise (no timeout) and is filtered for any match of `name` and `username` (custom feed):
 
 The feed:
-- `{ id: '1', label: 'Barney Stinson', username: 'swarley' }`
-- `{ id: '2', label: 'Lily Aldrin', username: 'lilypad' }`
-- `{ id: '3', label: 'Marshall Eriksen', username: 'marshmallow' }`
-- `{ id: '4', label: 'Robin Scherbatsky', username: 'rsparkles' }`
-- `{ id: '5', label: 'Ted Mosby', username: 'tdog' }`
+- `{ id: '1', name: 'Barney Stinson', username: 'swarley' }`
+- `{ id: '2', name: 'Lily Aldrin', username: 'lilypad' }`
+- `{ id: '3', name: 'Marshall Eriksen', username: 'marshmallow' }`
+- `{ id: '4', name: 'Robin Scherbatsky', username: 'rsparkles' }`
+- `{ id: '5', name: 'Ted Mosby', username: 'tdog' }`
 
 The item is rendered as `<span>` instead of default button.
 

+ 15 - 15
packages/ckeditor5-mention/tests/manual/mention-custom-view.js

@@ -54,7 +54,7 @@ class CustomMentionAttributeView extends Plugin {
 				key: 'mention',
 				value: viewItem => {
 					const mentionValue = {
-						label: viewItem.getAttribute( 'data-mention' ),
+						name: viewItem.getAttribute( 'data-mention' ),
 						link: viewItem.getAttribute( 'href' )
 					};
 
@@ -73,7 +73,7 @@ class CustomMentionAttributeView extends Plugin {
 
 				return viewWriter.createAttributeElement( 'a', {
 					class: 'mention',
-					'data-mention': modelAttributeValue.label,
+					'data-mention': modelAttributeValue.name,
 					'href': modelAttributeValue.link
 				} );
 			},
@@ -97,7 +97,7 @@ class CustomMentionElementView extends Plugin {
 			},
 			model: ( viewItem, modelWriter ) => {
 				const item = {
-					label: viewItem.getAttribute( 'data-mention' ),
+					name: viewItem.getAttribute( 'data-mention' ),
 					link: viewItem.getAttribute( 'href' )
 				};
 
@@ -106,7 +106,7 @@ class CustomMentionElementView extends Plugin {
 
 				modelWriter.insert( mention, frag, 0 );
 
-				modelWriter.insertText( item.label, mention, 0 );
+				modelWriter.insertText( item.name, mention, 0 );
 
 				return mention;
 			},
@@ -120,7 +120,7 @@ class CustomMentionElementView extends Plugin {
 
 				const link = viewWriter.createContainerElement( 'a', {
 					class: 'mention',
-					'data-mention': item.label,
+					'data-mention': item.name,
 					'href': item.link
 				} );
 
@@ -149,7 +149,7 @@ class CustomMentionMarkerView extends Plugin {
 
 		editor.conversion.for( 'downcast' ).add( dispatcher => {
 			dispatcher.on( 'addMarker:mention', ( evt, data, conversionApi ) => {
-				const label = data.markerName.split( ':' )[ 1 ];
+				const name = data.markerName.split( ':' )[ 1 ];
 				const id = data.markerName.split( ':' )[ 2 ];
 
 				if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
@@ -158,17 +158,17 @@ class CustomMentionMarkerView extends Plugin {
 
 				const viewWriter = conversionApi.writer;
 
-				const item = getFeed( label.replace( '-', ' ' ) )[ 0 ];
+				const item = getFeed( name.replace( '-', ' ' ) )[ 0 ];
 
 				const attributes = {
 					class: [ 'mention' ],
-					'data-mention': label,
+					'data-mention': name,
 					id
 				};
 
 				if ( item ) {
 					attributes.href = item.link;
-					attributes.title = item.label;
+					attributes.title = item.name;
 				}
 
 				// OMG I just wanted to change `<span>` to `<a>`...
@@ -234,14 +234,14 @@ ClassicEditor
 
 function getFeed( feedText ) {
 	return [
-		{ id: '1', label: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
-		{ id: '2', label: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
-		{ id: '3', label: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' },
-		{ id: '4', label: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' },
-		{ id: '5', label: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
+		{ id: '1', name: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
+		{ id: '2', name: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
+		{ id: '3', name: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' },
+		{ id: '4', name: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' },
+		{ id: '5', name: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
 	].filter( item => {
 		const searchString = feedText.toLowerCase();
 
-		return item.label.toLowerCase().includes( searchString );
+		return item.name.toLowerCase().includes( searchString );
 	} );
 }

+ 5 - 5
packages/ckeditor5-mention/tests/manual/mention-custom-view.md

@@ -19,11 +19,11 @@ Use the code of this manual sample to change bahavior of the feature.
 ### Data
 
 The feed:
-- `{ label: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' }`
-- `{ label: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989?ref_=tt_cl_t5' }`
-- `{ label: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' }`
-- `{ label: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' }`
-- `{ label: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }`
+- `{ name: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' }`
+- `{ name: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989?ref_=tt_cl_t5' }`
+- `{ name: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' }`
+- `{ name: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' }`
+- `{ name: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }`
 
 The mention is converted to link (`<a>`) with additional data of default span.
 

+ 50 - 28
packages/ckeditor5-mention/tests/mentionediting.js

@@ -51,97 +51,119 @@ describe( 'MentionEditing', () => {
 			} );
 
 			it( 'should convert <span class="mention" data-mention="John"> to mention attribute', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 
 				expect( getModelData( model, { withoutSelection: true } ) )
-					.to.equal( '<paragraph>foo <$text mention="John">John</$text> bar</paragraph>' );
+					.to.equal( '<paragraph>foo <$text mention="{"name":"John"}">@John</$text> bar</paragraph>' );
 
-				expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				const textNode = doc.getRoot().getChild( 0 ).getChild( 1 );
+
+				expect( textNode ).to.not.be.null;
+				expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
+				expect( textNode.getAttribute( 'mention' ) ).to.deep.equal( { name: 'John' } );
+
+				expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 			} );
 
 			it( 'should remove mention on adding a text inside mention', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 
 				model.change( writer => {
 					const paragraph = doc.getRoot().getChild( 0 );
 
-					writer.setSelection( paragraph, 5 );
+					writer.setSelection( paragraph, 6 );
 
 					writer.insertText( 'a', doc.selection.getAttributes(), writer.createPositionAt( paragraph, 6 ) );
 				} );
 
-				expect( editor.getData() ).to.equal( '<p>foo Joahn bar</p>' );
+				expect( editor.getData() ).to.equal( '<p>foo @Jaohn bar</p>' );
 			} );
 
 			it( 'should remove mention on removing a text inside mention', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 
-				model.change( writer => {
-					const paragraph = doc.getRoot().getChild( 0 );
+				const paragraph = doc.getRoot().getChild( 0 );
 
-					writer.setSelection( paragraph, 5 );
+				model.change( writer => {
+					writer.setSelection( paragraph, 6 );
+				} );
 
-					writer.remove( writer.createRange( writer.createPositionAt( paragraph, 5 ), writer.createPositionAt( paragraph, 6 ) ) );
+				model.enqueueChange( () => {
+					model.modifySelection( doc.selection, { direction: 'backward', unit: 'codepoint' } );
+					model.deleteContent( doc.selection );
 				} );
 
-				expect( editor.getData() ).to.equal( '<p>foo Jhn bar</p>' );
+				expect( editor.getData() ).to.equal( '<p>foo @ohn bar</p>' );
 			} );
 
 			it( 'should remove mention on removing a text at the and of a mention', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 
 				const paragraph = doc.getRoot().getChild( 0 );
 
 				// Set selection at the end of a John.
 				model.change( writer => {
-					writer.setSelection( paragraph, 8 );
+					writer.setSelection( paragraph, 9 );
 				} );
 
-				model.change( writer => {
-					writer.remove( writer.createRange( writer.createPositionAt( paragraph, 7 ), writer.createPositionAt( paragraph, 8 ) ) );
+				model.enqueueChange( () => {
+					model.modifySelection( doc.selection, { direction: 'backward', unit: 'codepoint' } );
+					model.deleteContent( doc.selection );
 				} );
 
-				expect( editor.getData() ).to.equal( '<p>foo Joh bar</p>' );
+				expect( editor.getData() ).to.equal( '<p>foo @Joh bar</p>' );
 			} );
 
-			it( 'should work on insert text to an empty node', () => {
-				editor.setData( '<p></p>' );
+			it( 'should not remove mention on removing a text just after a mention', () => {
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 
+				const paragraph = doc.getRoot().getChild( 0 );
+
+				// Set selection before bar.
 				model.change( writer => {
-					const paragraph = doc.getRoot().getChild( 0 );
+					writer.setSelection( paragraph, 10 );
+				} );
 
-					writer.insertText( 'foo', paragraph, 0 );
+				model.enqueueChange( () => {
+					model.modifySelection( doc.selection, { direction: 'backward', unit: 'codepoint' } );
+					model.deleteContent( doc.selection );
 				} );
 
-				expect( editor.getData() ).to.equal( '<p>foo</p>' );
+				expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="John">@John</span>bar</p>' );
 			} );
+		} );
 
+		describe( 'typing integration', () => {
 			it( 'should remove mention attribute from a selection if selection is on right side of a mention', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span>bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span>bar</p>' );
 
 				model.change( writer => {
 					const paragraph = doc.getRoot().getChild( 0 );
 
-					writer.setSelection( paragraph, 8 );
+					writer.setSelection( paragraph, 9 );
 				} );
 
 				expect( Array.from( doc.selection.getAttributes() ) ).to.deep.equal( [] );
 			} );
 
 			it( 'should allow to type after a mention', () => {
-				editor.setData( '<p>foo <span class="mention" data-mention="John">John</span>bar</p>' );
+				editor.setData( '<p>foo <span class="mention" data-mention="John">@John</span>bar</p>' );
 
 				model.change( writer => {
 					const paragraph = doc.getRoot().getChild( 0 );
 
-					writer.setSelection( paragraph, 8 );
+					writer.setSelection( paragraph, 9 );
 
-					writer.insertText( ' ', paragraph, 8 );
+					writer.insertText( ' ', paragraph, 9 );
 				} );
 
-				expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="John">John</span> bar</p>' );
+				expect( editor.getData() ).to.equal( '<p>foo <span class="mention" data-mention="John">@John</span> bar</p>' );
 			} );
 		} );
+
+		describe( 'postFixer', () => {
+			it( 'should..', () => {} );
+		} );
 	} );
 
 	function createTestEditor( mentionConfig ) {

+ 3 - 3
packages/ckeditor5-mention/tests/mentionui.js

@@ -475,7 +475,7 @@ describe( 'MentionUI', () => {
 
 						const commandOptions = spy.getCall( 0 ).args[ 0 ];
 
-						expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { label: 'Ted' } );
+						expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { name: 'Ted' } );
 						expect( commandOptions ).to.have.property( 'marker', '@' );
 						expect( commandOptions ).to.have.property( 'range' );
 
@@ -520,7 +520,7 @@ describe( 'MentionUI', () => {
 
 						const commandOptions = spy.getCall( 0 ).args[ 0 ];
 
-						expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { label: 'Ted' } );
+						expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { name: 'Ted' } );
 						expect( commandOptions ).to.have.property( 'marker', '@' );
 						expect( commandOptions ).to.have.property( 'range' );
 
@@ -750,7 +750,7 @@ describe( 'MentionUI', () => {
 
 					const commandOptions = spy.getCall( 0 ).args[ 0 ];
 
-					expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { label: 'Barney' } );
+					expect( commandOptions ).to.have.property( 'mention' ).that.deep.equal( { name: 'Barney' } );
 					expect( commandOptions ).to.have.property( 'marker', '@' );
 					expect( commandOptions ).to.have.property( 'range' );