mention-customization.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* globals ClassicEditor, console, window, document, setTimeout */
  6. import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
  7. ClassicEditor
  8. .create( document.querySelector( '#snippet-mention-customization' ), {
  9. cloudServices: CS_CONFIG,
  10. extraPlugins: [ MentionCustomization ],
  11. toolbar: {
  12. items: [
  13. 'heading', '|', 'bold', 'italic', '|', 'undo', 'redo'
  14. ],
  15. viewportTopOffset: window.getViewportTopOffsetConfig(),
  16. },
  17. mention: {
  18. feeds: [
  19. {
  20. marker: '@',
  21. feed: getFeedItems,
  22. itemRenderer: customItemRenderer,
  23. minimumCharacters: 1
  24. }
  25. ]
  26. }
  27. } )
  28. .then( editor => {
  29. window.editor = editor;
  30. } )
  31. .catch( err => {
  32. console.error( err.stack );
  33. } );
  34. function MentionCustomization( editor ) {
  35. // The upcast converter will convert <a class="mention" href="" data-user-id="">
  36. // elements to the model 'mention' attribute.
  37. editor.conversion.for( 'upcast' ).elementToAttribute( {
  38. view: {
  39. name: 'a',
  40. key: 'data-mention',
  41. classes: 'mention',
  42. attributes: {
  43. href: true,
  44. 'data-user-id': true
  45. }
  46. },
  47. model: {
  48. key: 'mention',
  49. value: viewItem => {
  50. // The mention feature expects that the mention attribute value
  51. // in the model is a plain object:
  52. const mentionValue = {
  53. // The name attribute is required.
  54. name: viewItem.getAttribute( 'data-mention' ),
  55. // Add any other properties that you need.
  56. link: viewItem.getAttribute( 'href' ),
  57. id: viewItem.getAttribute( 'data-user-id' )
  58. };
  59. return mentionValue;
  60. }
  61. },
  62. converterPriority: 'high'
  63. } );
  64. // Do not forget to define a downcast converter as well:
  65. editor.conversion.for( 'downcast' ).attributeToElement( {
  66. model: 'mention',
  67. view: ( modelAttributeValue, viewWriter ) => {
  68. // Do not convert empty attributes (lack of value means no mention).
  69. if ( !modelAttributeValue ) {
  70. return;
  71. }
  72. return viewWriter.createAttributeElement( 'a', {
  73. class: 'mention',
  74. 'data-mention': modelAttributeValue.name,
  75. 'data-user-id': modelAttributeValue.id,
  76. 'href': modelAttributeValue.link
  77. } );
  78. },
  79. converterPriority: 'high'
  80. } );
  81. }
  82. const items = [
  83. { id: '1', name: 'Barney Stinson', username: 'swarley', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
  84. { id: '2', name: 'Lily Aldrin', username: 'lilypad', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
  85. { id: '3', name: 'Marshall Eriksen', username: 'marshmallow', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' },
  86. { id: '4', name: 'Robin Scherbatsky', username: 'rsparkles', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' },
  87. { id: '5', name: 'Ted Mosby', username: 'tdog', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
  88. ];
  89. function getFeedItems( queryText ) {
  90. // As an example of an asynchronous action, let's return a promise
  91. // that resolves after a 100ms timeout.
  92. // This can be a server request, or any sort of delayed action.
  93. return new Promise( resolve => {
  94. setTimeout( () => {
  95. resolve( items.filter( isItemMatching ) );
  96. }, 100 );
  97. } );
  98. // Filtering function - it uses `name` and `username` properties of an item to find a match.
  99. function isItemMatching( item ) {
  100. // Make search case-insensitive.
  101. const searchString = queryText.toLowerCase();
  102. // Include an item in the search results if name or username includes the current user input.
  103. return (
  104. item.name.toLowerCase().includes( searchString ) ||
  105. item.username.toLowerCase().includes( searchString )
  106. );
  107. }
  108. }
  109. function customItemRenderer( item ) {
  110. const itemElement = document.createElement( 'span' );
  111. itemElement.classList.add( 'custom-item' );
  112. itemElement.id = `mention-list-item-id-${ item.id }`;
  113. itemElement.textContent = `${ item.name } `;
  114. const usernameElement = document.createElement( 'span' );
  115. usernameElement.classList.add( 'custom-item-username' );
  116. usernameElement.textContent = `@${ item.username }`;
  117. itemElement.appendChild( usernameElement );
  118. return itemElement;
  119. }