Browse Source

Extend the feature guide.

Maciej Gołaszewski 6 years ago
parent
commit
c0d74c992b
1 changed files with 156 additions and 0 deletions
  1. 156 0
      packages/ckeditor5-mention/docs/features/mention.md

+ 156 - 0
packages/ckeditor5-mention/docs/features/mention.md

@@ -10,6 +10,8 @@ The {@link module:mention/mention~Mention} feature brings support for smart comp
 
 ## Demo
 
+You can type `'@'` character to invoke mention auto-complete UI. The below demo is configured as static list of names.
+
 {@snippet features/mention}
 
 ## Installation
@@ -42,6 +44,160 @@ ClassicEditor
 
 ## Configuration
 
+The minimal configuration of a mention requires defining a feed and optionally a marker (if not using the default `@` character).
+
+### Providing the feed
+
+The {@link module:mention/mention~MentionFeed#feed} can be provided as:
+
+- static array - good for scenarios with relatively small set of auto-complete items.
+- a callback - which provides more control over the returned list of items.
+
+If using a callback you can return a `Promise` that resolves with list of {@link module:mention/mention~MentionFeedItem mention feed items}. Those can be simple stings used as mention text or plain objects with at least one `name` property. The other parameters can be used either when {@link #customizing-the-auto-complete-list customizing the auto-complete list} {@link #customizing-the-output customizing the output}.
+
+The callback receives a matched text which should be used to filter item suggestions. The callback should return a Promise and resolve it with an array of items that match to the feed text.
+
+<info-box>
+The mention feature does not limit items displayed in the mention suggestion list when using the callback. You should limit the output by yourself. 
+</info-box>
+
+```js
+const items = [
+		{ 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' }
+	];
+
+function getFeedItems( feedText ) {
+	// As an example of asynchronous action return a promise that resolves after a 100ms timeout.  
+	return new Promise( resolve => {
+		setTimeout( () => {
+			resolve( items.filter( isItemMathing ) );
+		}, 100 );
+	} );
+
+	// Filtering function - it uses `name` and `username` properties of an item to find a match.
+	function isItemMatching( item ) {
+		// Make search case-insensitive.
+		const searchString = feedText.toLowerCase();
+
+		// Include an item in the search results if name or username includes the current user input.
+		return textIncludesSearchSting( item.name, searchString ) || textIncludesSearchSting( item.username, searchString );
+ 	}
+
+	function textIncludesSearchSting( text, searchString ) {
+		return text.toLowerCase().includes( searchString );
+	}
+}
+
+```
+
+### Customizing the auto-complete list
+
+The list displayed in auto-complete list can be customized by defining the {@link module:mention/mention~MentionFeed#itemRenderer} callback.
+
+This callback takes a plain object feed item (at least with `name` parameter - even when feed items are defined as strings). It should return a new DOM element.
+
+```js
+function customItemRenderer( item ) {
+	const span = document.createElement( 'span' );
+
+	span.classList.add( 'custom-item' );
+	span.id = `mention-list-item-id-${ item.id }`;
+
+	span.innerHTML = `${ item.name } <span class="custom-item-username">@${ item.username }</span>`;
+
+	return span;
+}
+``` 
+
+### Customizing the output
+
+In order to have full control over the markup generated by the editor you can overwrite the conversion process. To do that you must specify both {@link module:engine/conversion/upcastdisatcher upcast} and {@link module:engine/conversion/downcastdisatcher downcast} converters.
+
+```js
+import priorities from '@ckeditor/ckeditor5-utils/src/priorities';
+
+// The link plugin using highest priority in conversion pipeline.
+const HIGHER_THEN_HIGHEST = priorities.highest + 50;
+
+// The upcast converter will convert <a class="mention"> elements to the model 'mention' attribute. 
+editor.conversion.for( 'upcast' ).elementToAttribute( {
+	view: {
+		name: 'a',
+		key: 'data-mention',
+		classes: 'mention',
+		attributes: {
+			href: true
+		}
+	},
+	model: {
+		key: 'mention',
+		value: viewItem => {
+			// Optionally: do not convert partial mentions.
+			if( !isFullMention(viewItem)){
+				return;
+			}
+			  
+			// The mention feature expects that mention attribute value in the model is a plain object:
+			const mentionValue = {
+				// The name attribute is required by mention editing.
+				name: viewItem.getAttribute( 'data-mention' ),
+				// Add any other properties as required.
+				link: viewItem.getAttribute( 'href' ),
+				id: viewItem.getAttribute( 'data-user-id' )
+			};
+
+			return mentionValue;
+		}
+	},
+	converterPriority: HIGHER_THEN_HIGHEST
+} );
+
+function isFullMention( viewElement ) {
+	const textNode = viewElement.getChild( 0 );
+
+	// Do not parse empty mentions.
+	if ( !textNode || !textNode.is( 'text' ) ) {
+		return;
+	}
+
+	const mentionString = textNode.data;
+
+	// Assume that mention is set as marker + mention name.
+	const marker = mentionString.slice( 0, 1 );
+	const name = mentionString.slice( 1 );
+
+	// Do not upcast partial mentions - might come from copy-paste of partially selected mention.
+	if ( name != dataMention ) {
+		return;
+	}
+
+}
+
+// Don't forget to define a downcast converter as well:
+
+editor.conversion.for( 'downcast' ).attributeToElement( {
+	model: 'mention',
+	view: ( modelAttributeValue, viewWriter ) => {
+		if ( !modelAttributeValue ) {
+			// Do not convert empty attributes.
+			return;
+		}
+
+		return viewWriter.createAttributeElement( 'a', {
+			class: 'mention',
+			'data-mention': modelAttributeValue.name,
+			'data-user-id': modelAttributeValue.id,
+			'href': modelAttributeValue.link
+		} );
+	},
+	converterPriority: HIGHER_THEN_HIGHEST
+} );
+```
+
 ## Common API
 
 The {@link module:mention/mention~Mention} plugin registers: