|
|
@@ -6,22 +6,27 @@ category: features
|
|
|
|
|
|
# Mention
|
|
|
|
|
|
-The {@link module:mention/mention~Mention} feature brings support for smart completion based on user input. When user types a pre-configured marker, such as `@` or `#`, they get an autocomplete suggestions in a balloon panel displayed next to the caret. The selected suggestion is then inserted into the content.
|
|
|
+The {@link module:mention/mention~Mention} feature brings support for smart autocompletion based on user input. When user types a pre-configured marker, such as `@` or `#`, they get an autocomplete suggestions in a panel displayed next to the caret. The selected suggestion is then inserted into the content.
|
|
|
|
|
|
## Demo
|
|
|
|
|
|
-You can type `'@'` character to invoke mention auto-complete UI. The below demo is configured as static list of names.
|
|
|
+You can type `'@'` character to invoke mention autocomplete UI. The below demo is configured as static list of names.
|
|
|
|
|
|
{@snippet features/mention}
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
-The minimal configuration of a mention requires defining a {@link module:mention/mention~MentionFeed `feed`} and a {@link module:mention/mention~MentionFeed `marker`} (if not using the default `@` character). You can define also `minimumCharacters` after which the auto-complete panel will be shown.
|
|
|
+The minimal configuration of the mention feature requires defining a {@link module:mention/mention~MentionFeed `feed`} and a {@link module:mention/mention~MentionFeed `marker`}. You can also define `minimumCharacters` after which the autocomplete panel will be shown.
|
|
|
+
|
|
|
+The code snippet below was used to configure the demo above. It defines the list of names that will be autocompleted after the user types the `'@'` character.
|
|
|
|
|
|
```js
|
|
|
ClassicEditor
|
|
|
.create( document.querySelector( '#editor' ), {
|
|
|
+ // This feature is not available in any of the builds.
|
|
|
+ // See the "Installation" section.
|
|
|
plugins: [ Mention, ... ],
|
|
|
+
|
|
|
mention: {
|
|
|
feeds: [
|
|
|
{
|
|
|
@@ -36,29 +41,29 @@ ClassicEditor
|
|
|
.catch( ... );
|
|
|
```
|
|
|
|
|
|
-Additionally you can configure:
|
|
|
-- How the item is rendered in the auto-complete panel.
|
|
|
-- How the item is converted during the conversion.
|
|
|
+Additionally, you can configure:
|
|
|
+
|
|
|
+* How the item is rendered in the autocomplete panel (via setting {@link module:mention/mention~MentionFeed `itemRenderer`}). See ["Customizing the autocomplete list"](#customizing-the-autocomplete-list).
|
|
|
+* How the item is converted during the conversion. See ["Customizing the output"](#customizing-the-output).
|
|
|
+* Multiple feeds — in the demo above we used only one feed, which is triggered by the `'@'` character. You can define multiple feeds but they must use different markers. For example, you can use `'@'` for people and `#` for tags.
|
|
|
|
|
|
### 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.
|
|
|
+* a static array — good for scenarios with relatively small set of autocomplete 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 features/mention#customizing-the-auto-complete-list customizing the auto-complete list} {@link features/mention#customizing-the-output customizing the output}.
|
|
|
+When using a callback you can return a `Promise` that resolves with the list of {@link module:mention/mention~MentionFeedItem matching feed items}. Those can be simple stringsor plain objects with at least the `name` property. The other properties of this object can later be used e.g. when [customizing the autocomplete list](#customizing-the-autocomplete-list) or [customizing the output](#customizing-the-output).
|
|
|
|
|
|
<info-box>
|
|
|
-When using external resources to obtain the feed it is recommended to add some caching mechanism so subsequent calls for the same suggestoin would load faster.
|
|
|
-</info-box>
|
|
|
+ When using external resources to obtain the feed it is recommended to add some caching mechanism so subsequent calls for the same suggestion would load faster.
|
|
|
|
|
|
-The callback receives a matched text which should be used to filter item suggestions. It should return a `Promise` and resolve it with an array of items that match to the feed text.
|
|
|
-
|
|
|
-<info-box>
|
|
|
-Consider adding the `minimumCharacters` option to the feed config so the editor will call the feed callback after a minimum characters typed instead of action on marker alone.
|
|
|
+ You can also consider adding the `minimumCharacters` option to the feed config so the editor will call the feed callback after a minimum characters typed instead of action on marker alone.
|
|
|
</info-box>
|
|
|
|
|
|
+The callback receives the query text which should be used to filter item suggestions. It should return a `Promise` and resolve it with an array of items that match to the feed text.
|
|
|
+
|
|
|
```js
|
|
|
const items = [
|
|
|
{ id: '1', name: 'Barney Stinson', username: 'swarley', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
|
|
|
@@ -68,14 +73,16 @@ const items = [
|
|
|
{ id: '5', name: 'Ted Mosby', username: 'tdog', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
|
|
|
];
|
|
|
|
|
|
-function getFeedItems( feedText ) {
|
|
|
- // As an example of asynchronous action return a promise that resolves after a 100ms timeout.
|
|
|
+function getFeedItems( queryText ) {
|
|
|
+ // As an example of an asynchronous action, let's return a promise
|
|
|
+ // that resolves after a 100ms timeout.
|
|
|
+ // This can be a server request, or any sort of delayed action.
|
|
|
return new Promise( resolve => {
|
|
|
setTimeout( () => {
|
|
|
const itemsToDisplay = items
|
|
|
- // Filter out the full list of all items to only those matching feedText.
|
|
|
+ // Filter out the full list of all items to only those matching queryText.
|
|
|
.filter( isItemMatching )
|
|
|
- // Return at most 10 items - notably for generic queries when the list may contain hundreds of elements.
|
|
|
+ // Return 10 items max - needed for generic queries when the list may contain hundreds of elements.
|
|
|
.slice( 0, 10 );
|
|
|
|
|
|
resolve( itemsToDisplay );
|
|
|
@@ -85,29 +92,24 @@ function getFeedItems( feedText ) {
|
|
|
// 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();
|
|
|
+ const searchString = queryText.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 );
|
|
|
+ return (
|
|
|
+ item.name.toLowerCase().includes( searchString ) ||
|
|
|
+ item.username.toLowerCase().includes( searchString )
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-The full working demo with all customization possible is {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
+A full, working demo with all possible customizations and its source code is available {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
|
|
|
-<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>
|
|
|
+### Customizing the autocomplete list
|
|
|
|
|
|
-### Customizing the auto-complete list
|
|
|
+The items displayed in the autocomplete list can be customized by defining the {@link module:mention/mention~MentionFeed `itemRenderer`} callback.
|
|
|
|
|
|
-The items 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). The item renderer function must return a new DOM element.
|
|
|
+This callback takes a feed item (it contains at least the `name` property). The item renderer function must return a new DOM element.
|
|
|
|
|
|
```js
|
|
|
ClassicEditor
|
|
|
@@ -115,7 +117,7 @@ ClassicEditor
|
|
|
plugins: [ Mention, ... ],
|
|
|
mention: {
|
|
|
feeds: [
|
|
|
- {
|
|
|
+ {
|
|
|
feed: [ ... ],
|
|
|
// Define the custom item renderer:
|
|
|
itemRenderer: customItemRenderer
|
|
|
@@ -127,25 +129,30 @@ ClassicEditor
|
|
|
.catch( ... );
|
|
|
|
|
|
function customItemRenderer( item ) {
|
|
|
- const span = document.createElement( 'span' );
|
|
|
+ const itemElement = document.createElement( 'span' );
|
|
|
+
|
|
|
+ itemElement.classList.add( 'custom-item' );
|
|
|
+ itemElement.id = `mention-list-item-id-${ item.id }`;
|
|
|
+ itemElement.textContent = `${ item.name } `;
|
|
|
|
|
|
- span.classList.add( 'custom-item' );
|
|
|
- span.id = `mention-list-item-id-${ item.id }`;
|
|
|
+ const usernameElement = document.createElement( 'span' );
|
|
|
|
|
|
- // Add child nodes to the main span or just set innerHTML.
|
|
|
- span.innerHTML = `${ item.name } <span class="custom-item-username">@${ item.username }</span>`;
|
|
|
+ usernameElement.classList.add( 'custom-item-username' );
|
|
|
+ usernameElement.textContent = `@${ item.username }`;
|
|
|
|
|
|
- return span;
|
|
|
+ itemElement.appendChild( usernameElement );
|
|
|
+
|
|
|
+ return itemElement;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-The full working demo with all customization possible is {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
+A full, working demo with all possible customizations and its source code is available {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
|
|
|
### 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/upcastdispatcher~UpcastDispatcher upcast} and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast} converters.
|
|
|
+In order to change the markup generated by the editor for mentions you can overwrite the default converter of the mention feature. To do that, you must specify both {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast} and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast} converters.
|
|
|
|
|
|
-Below is an example of a plugin that overrides the default output:
|
|
|
+The example below defined a plugin which overrides the default output:
|
|
|
|
|
|
```html
|
|
|
<span data-mention="Ted" class="mention">@Ted</span>
|
|
|
@@ -157,26 +164,22 @@ To a link:
|
|
|
<a class="mention" data-mention="Ted Mosby" data-user-id="5" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">@Ted Mosby</a>
|
|
|
```
|
|
|
|
|
|
-The below converters must have priority higher then link attribute converter. The mention item in the model must be stored as a plain object with `name` attribute.
|
|
|
+The converters must be defined with a `'high'` priority to be executed before the link feature's converter and before the default converter of the mention feature. A mention is stored in the model as a text attribute which stores an object (see {@link module:mention/mention~MentionFeedItem}).
|
|
|
|
|
|
```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;
|
|
|
-
|
|
|
ClassicEditor
|
|
|
.create( document.querySelector( '#editor' ), {
|
|
|
- plugins: [ Mention, CustomMention, ... ], // Add custom mention plugin function.
|
|
|
+ plugins: [ Mention, MentionCustomization, ... ], // Add custom mention plugin function.
|
|
|
mention: {
|
|
|
- // configuration...
|
|
|
+ // Configuration...
|
|
|
}
|
|
|
} )
|
|
|
.then( ... )
|
|
|
.catch( ... );
|
|
|
|
|
|
-function CustomMention( editor ) {
|
|
|
- // The upcast converter will convert <a class="mention"> elements to the model 'mention' attribute.
|
|
|
+function MentionCustomization( editor ) {
|
|
|
+ // The upcast converter will convert view <a class="mention" href="" data-user-id="">
|
|
|
+ // elements to the model 'mention' text attribute.
|
|
|
editor.conversion.for( 'upcast' ).elementToAttribute( {
|
|
|
view: {
|
|
|
name: 'a',
|
|
|
@@ -190,16 +193,13 @@ function CustomMention( editor ) {
|
|
|
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:
|
|
|
+ // The mention feature expects that the mention attribute value
|
|
|
+ // in the model is a plain object:
|
|
|
const mentionValue = {
|
|
|
- // The name attribute is required by mention editing.
|
|
|
+ // The name attribute is required.
|
|
|
name: viewItem.getAttribute( 'data-mention' ),
|
|
|
- // Add any other properties as required.
|
|
|
+
|
|
|
+ // Add any other properties that you need.
|
|
|
link: viewItem.getAttribute( 'href' ),
|
|
|
id: viewItem.getAttribute( 'data-user-id' )
|
|
|
};
|
|
|
@@ -207,33 +207,105 @@ function CustomMention( editor ) {
|
|
|
return mentionValue;
|
|
|
}
|
|
|
},
|
|
|
- converterPriority: HIGHER_THEN_HIGHEST
|
|
|
+ converterPriority: 'high'
|
|
|
} );
|
|
|
|
|
|
- function isFullMention( viewElement ) {
|
|
|
- const textNode = viewElement.getChild( 0 );
|
|
|
- const dataMention = viewElement.getAttribute( 'data-mention' );
|
|
|
+ // Downcast the model 'mention' text attribute to a view <a> element.
|
|
|
+ editor.conversion.for( 'downcast' ).attributeToElement( {
|
|
|
+ model: 'mention',
|
|
|
+ view: ( modelAttributeValue, viewWriter ) => {
|
|
|
+ // Do not convert empty attributes (lack of value means no mention).
|
|
|
+ if ( !modelAttributeValue ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // Do not parse empty mentions.
|
|
|
- if ( !textNode || !textNode.is( 'text' ) ) {
|
|
|
- return false;
|
|
|
+ return viewWriter.createAttributeElement( 'a', {
|
|
|
+ class: 'mention',
|
|
|
+ 'data-mention': modelAttributeValue.name,
|
|
|
+ 'data-user-id': modelAttributeValue.id,
|
|
|
+ 'href': modelAttributeValue.link
|
|
|
+ } );
|
|
|
+ },
|
|
|
+ converterPriority: 'high'
|
|
|
+ } );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+The full working demo with all customization possible is {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
+
|
|
|
+### Fully customized mention feed
|
|
|
+
|
|
|
+Below is an example of a customized mention feature that:
|
|
|
+
|
|
|
+* Uses a feed of items with additional properties (`id`, `username`, `link`).
|
|
|
+* Renders custom item views in the autocomplete panel.
|
|
|
+* Converts mention to an `<a>` element instead of `<span>`.
|
|
|
+
|
|
|
+{@snippet features/mention-customization}
|
|
|
+
|
|
|
+#### Source code
|
|
|
+
|
|
|
+```js
|
|
|
+ClassicEditor
|
|
|
+ .create( document.querySelector( '#snippet-mention-customization' ), {
|
|
|
+ plugins: [ Mention, MentionCustomization, ... ],
|
|
|
+ mention: {
|
|
|
+ feeds: [
|
|
|
+ {
|
|
|
+ marker: '@',
|
|
|
+ feed: getFeedItems,
|
|
|
+ itemRenderer: customItemRenderer,
|
|
|
+ minimumCharacters: 1
|
|
|
+ }
|
|
|
+ ]
|
|
|
}
|
|
|
+ } )
|
|
|
+ .then( editor => {
|
|
|
+ window.editor = editor;
|
|
|
+ } )
|
|
|
+ .catch( err => {
|
|
|
+ console.error( err.stack );
|
|
|
+ } );
|
|
|
|
|
|
- const mentionString = textNode.data;
|
|
|
+function MentionCustomization( editor ) {
|
|
|
+ // The upcast converter will convert <a class="mention" href="" data-user-id="">
|
|
|
+ // elements to the model 'mention' attribute.
|
|
|
+ editor.conversion.for( 'upcast' ).elementToAttribute( {
|
|
|
+ view: {
|
|
|
+ name: 'a',
|
|
|
+ key: 'data-mention',
|
|
|
+ classes: 'mention',
|
|
|
+ attributes: {
|
|
|
+ href: true,
|
|
|
+ 'data-user-id': true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ model: {
|
|
|
+ key: 'mention',
|
|
|
+ value: viewItem => {
|
|
|
+ // The mention feature expects that the mention attribute value
|
|
|
+ // in the model is a plain object:
|
|
|
+ const mentionValue = {
|
|
|
+ // The name attribute is required.
|
|
|
+ name: viewItem.getAttribute( 'data-mention' ),
|
|
|
|
|
|
- // Assume that mention is set as marker + mention name.
|
|
|
- const name = mentionString.slice( 1 );
|
|
|
+ // Add any other properties that you need.
|
|
|
+ link: viewItem.getAttribute( 'href' ),
|
|
|
+ id: viewItem.getAttribute( 'data-user-id' )
|
|
|
+ };
|
|
|
|
|
|
- // Do not upcast partial mentions - might come from copy-paste of partially selected mention.
|
|
|
- return name == dataMention;
|
|
|
- }
|
|
|
+ return mentionValue;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ converterPriority: 'high'
|
|
|
+ } );
|
|
|
|
|
|
- // Don't forget to define a downcast converter as well:
|
|
|
+ // Do not forget to define a downcast converter as well:
|
|
|
editor.conversion.for( 'downcast' ).attributeToElement( {
|
|
|
model: 'mention',
|
|
|
view: ( modelAttributeValue, viewWriter ) => {
|
|
|
+ // Do not convert empty attributes (lack of value means no mention).
|
|
|
if ( !modelAttributeValue ) {
|
|
|
- // Do not convert empty attributes.
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -244,22 +316,58 @@ function CustomMention( editor ) {
|
|
|
'href': modelAttributeValue.link
|
|
|
} );
|
|
|
},
|
|
|
- converterPriority: HIGHER_THEN_HIGHEST
|
|
|
+ converterPriority: 'high'
|
|
|
} );
|
|
|
}
|
|
|
-```
|
|
|
|
|
|
-The full working demo with all customization possible is {@link features/mention#fully-customized-mention-feed at the end of this section}.
|
|
|
+const items = [
|
|
|
+ { id: '1', name: 'Barney Stinson', username: 'swarley', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
|
|
|
+ { id: '2', name: 'Lily Aldrin', username: 'lilypad', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
|
|
|
+ { id: '3', name: 'Marshall Eriksen', username: 'marshmallow', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' },
|
|
|
+ { id: '4', name: 'Robin Scherbatsky', username: 'rsparkles', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' },
|
|
|
+ { id: '5', name: 'Ted Mosby', username: 'tdog', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
|
|
|
+];
|
|
|
|
|
|
-# Fully customized mention feed
|
|
|
+function getFeedItems( queryText ) {
|
|
|
+ // As an example of an asynchronous action, let's return a promise
|
|
|
+ // that resolves after a 100ms timeout.
|
|
|
+ // This can be a server request, or any sort of delayed action.
|
|
|
+ return new Promise( resolve => {
|
|
|
+ setTimeout( () => {
|
|
|
+ resolve( items.filter( isItemMatching ) );
|
|
|
+ }, 100 );
|
|
|
+ } );
|
|
|
|
|
|
-Below is an example of a customized mention feature that:
|
|
|
+ // Filtering function - it uses `name` and `username` properties of an item to find a match.
|
|
|
+ function isItemMatching( item ) {
|
|
|
+ // Make search case-insensitive.
|
|
|
+ const searchString = queryText.toLowerCase();
|
|
|
|
|
|
-- Returns a feed of items with extended properties.
|
|
|
-- Renders custom DOM view in auto-complete suggestion in panel view.
|
|
|
-- Converts mention to an `<a>` element instead of `<span>`.
|
|
|
+ // Include an item in the search results if name or username includes the current user input.
|
|
|
+ return (
|
|
|
+ item.name.toLowerCase().includes( searchString ) ||
|
|
|
+ item.username.toLowerCase().includes( searchString )
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-{@snippet features/mention-customization}
|
|
|
+function customItemRenderer( item ) {
|
|
|
+ const itemElement = document.createElement( 'span' );
|
|
|
+
|
|
|
+ itemElement.classList.add( 'custom-item' );
|
|
|
+ itemElement.id = `mention-list-item-id-${ item.id }`;
|
|
|
+ itemElement.textContent = `${ item.name } `;
|
|
|
+
|
|
|
+ const usernameElement = document.createElement( 'span' );
|
|
|
+
|
|
|
+ usernameElement.classList.add( 'custom-item-username' );
|
|
|
+ usernameElement.textContent = `@${ item.username }`;
|
|
|
+
|
|
|
+ itemElement.appendChild( usernameElement );
|
|
|
+
|
|
|
+ return itemElement;
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
### Colors and styles
|
|
|
|
|
|
@@ -281,17 +389,13 @@ The mention feature is using the power of [CSS variables](https://developer.mozi
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
-<info-box info>
|
|
|
- This feature is enabled by default in all builds. The installation instructions are for developers interested in building their own, custom editor.
|
|
|
-</info-box>
|
|
|
-
|
|
|
To add this feature to your editor, install the [`@ckeditor/ckeditor5-mention`](https://www.npmjs.com/package/@ckeditor/ckeditor5-mention) package:
|
|
|
|
|
|
```bash
|
|
|
npm install --save @ckeditor/ckeditor5-mention
|
|
|
```
|
|
|
|
|
|
-Then add `Mention` to your plugin list and {@link module:mention/mention~MentionConfig configure} the feature (if needed):
|
|
|
+Then add `Mention` to your plugin list and {@link module:mention/mention~MentionConfig configure} the feature:
|
|
|
|
|
|
```js
|
|
|
import Mention from '@ckeditor/ckeditor5-mention/src/mention';
|
|
|
@@ -300,13 +404,17 @@ ClassicEditor
|
|
|
.create( document.querySelector( '#editor' ), {
|
|
|
plugins: [ Mention, ... ],
|
|
|
mention: {
|
|
|
- // configuration...
|
|
|
+ // Configuration...
|
|
|
}
|
|
|
} )
|
|
|
.then( ... )
|
|
|
.catch( ... );
|
|
|
```
|
|
|
|
|
|
+<info-box info>
|
|
|
+ Read more about {@link builds/guides/integration/installing-plugins installing plugins}.
|
|
|
+</info-box>
|
|
|
+
|
|
|
## Common API
|
|
|
|
|
|
The {@link module:mention/mention~Mention} plugin registers:
|