Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #2 from ckeditor/t/ckeditor5/998
Browse files Browse the repository at this point in the history
Feature: The mentions feature. Closes ckeditor/ckeditor5#998.
  • Loading branch information
Reinmar committed Mar 27, 2019
2 parents f2e46c7 + fd28b05 commit 3118814
Show file tree
Hide file tree
Showing 34 changed files with 3,719 additions and 1 deletion.
Empty file.
13 changes: 13 additions & 0 deletions docs/_snippets/features/build-mention-source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals window */

import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
import Mention from '@ckeditor/ckeditor5-mention/src/mention';

ClassicEditor.builtinPlugins.push( Mention );

window.ClassicEditor = ClassicEditor;
14 changes: 14 additions & 0 deletions docs/_snippets/features/custom-mention-colors-variables.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<style>
/* We are not using here :root because of many instances of editor */
#snippet-mention-custom-colors + .ck-editor {
/* Make mention background blue. */
--ck-color-mention-background: hsla(220, 100%, 54%, 0.4);

/* Make mention text dark grey. */
--ck-color-mention-text: hsl(0, 0%, 15%);
}
</style>

<div id="snippet-mention-custom-colors">
<p>Hello <span class="mention" data-mention="Ted">@Ted</span>.</p>
</div>
31 changes: 31 additions & 0 deletions docs/_snippets/features/custom-mention-colors-variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals ClassicEditor, console, window, document */

import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';

ClassicEditor
.create( document.querySelector( '#snippet-mention-custom-colors' ), {
cloudServices: CS_CONFIG,
toolbar: {
items: [
'heading', '|', 'bold', 'italic', '|', 'undo', 'redo'
],
viewportTopOffset: window.getViewportTopOffsetConfig()
},
mention: [
{
marker: '@',
feed: [ 'Barney', 'Lily', 'Marshall', 'Robin', 'Ted' ]
}
]
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err.stack );
} );
22 changes: 22 additions & 0 deletions docs/_snippets/features/mention-customization.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div id="snippet-mention-customization">
<p>Hello <a class="mention" data-mention="Ted Mosby" data-user-id="5" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">@Ted Mosby</a>!</p>
</div>

<style>
.custom-item {
display: block;
padding: 1em;
}

.custom-item.ck-on {
color: white;
}

.custom-item .custom-item-username {
color: #666;
}

.custom-item.ck-on .custom-item-username{
color: #ddd;
}
</style>
153 changes: 153 additions & 0 deletions docs/_snippets/features/mention-customization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals ClassicEditor, console, window, document, setTimeout */

import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';

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( '#snippet-mention-customization' ), {
cloudServices: CS_CONFIG,
extraPlugins: [ CustomMention ],
toolbar: {
items: [
'heading', '|', 'bold', 'italic', '|', 'undo', 'redo'
],
viewportTopOffset: window.getViewportTopOffsetConfig(),
},
mention: [
{
marker: '@',
feed: getFeedItems,
itemRenderer: customItemRenderer,
minimumCharacters: 1
}
]
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err.stack );
} );

function CustomMention( editor ) {
// 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,
'data-user-id': 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 );
const dataMention = viewElement.getAttribute( 'data-mention' );

// Do not parse empty mentions.
if ( !textNode || !textNode.is( 'text' ) ) {
return false;
}

const mentionString = textNode.data;

// Assume that mention is set as marker + mention name.
const name = mentionString.slice( 1 );

// Do not upcast partial mentions - might come from copy-paste of partially selected mention.
return name == dataMention;
}

// 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
} );
}

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' }
];

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( isItemMatching ) );
}, 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 );
}
}

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;
}
3 changes: 3 additions & 0 deletions docs/_snippets/features/mention.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div id="snippet-mention">
<p>Hello <span class="mention" data-mention="Ted">@Ted</span>.</p>
</div>
31 changes: 31 additions & 0 deletions docs/_snippets/features/mention.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals ClassicEditor, console, window, document */

import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';

ClassicEditor
.create( document.querySelector( '#snippet-mention' ), {
cloudServices: CS_CONFIG,
toolbar: {
items: [
'heading', '|', 'bold', 'italic', '|', 'undo', 'redo'
],
viewportTopOffset: window.getViewportTopOffsetConfig()
},
mention: [
{
marker: '@',
feed: [ 'Barney', 'Lily', 'Marshall', 'Robin', 'Ted' ]
}
]
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err.stack );
} );
34 changes: 34 additions & 0 deletions docs/api/mention.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
category: api-reference
---

# Mention feature for CKEditor 5

[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-mention.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-mention)

This package implements the mention feature for CKEditor 5. This features provides smart completion functionality for custom text matches based on user input.

## Demo

Check out the {@link features/mention#demo demo in the Mention feature} guide.

## Documentation

See the {@link features/mention Mention feature} guide and the {@link module:mention/mention~Mention} plugin documentation.

## Installation

```bash
npm install --save @ckeditor/ckeditor5-mention
```

## Contribute

The source code of this package is available on GitHub in https://github.com/ckeditor/ckeditor5-mention.

## External links

* [`@ckeditor/ckeditor5-mention` on npm](https://www.npmjs.com/package/@ckeditor/ckeditor5-mention)
* [`ckeditor/ckeditor5-mention` on GitHub](https://github.com/ckeditor/ckeditor5-mention)
* [Issue tracker](https://github.com/ckeditor/ckeditor5-mention/issues)
* [Changelog](https://github.com/ckeditor/ckeditor5-mention/blob/master/CHANGELOG.md)
Loading

0 comments on commit 3118814

Please sign in to comment.