mentioncommand.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module mention/mentioncommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
  10. import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
  11. import { _addMentionAttributes } from './mentionediting';
  12. /**
  13. * The mention command.
  14. *
  15. * The command is registered by {@link module:mention/mentionediting~MentionEditing} as `'mention'`.
  16. *
  17. * To insert a mention onto a range, execute the command and specify a mention object with a range to replace:
  18. *
  19. * const focus = editor.model.document.selection.focus;
  20. *
  21. * // It will replace one character before the selection focus with the '#1234' text
  22. * // with the mention attribute filled with passed attributes.
  23. * editor.execute( 'mention', {
  24. * marker: '#',
  25. * mention: {
  26. * id: '#1234',
  27. * name: 'Foo',
  28. * title: 'Big Foo'
  29. * },
  30. * range: model.createRange( focus, focus.getShiftedBy( -1 ) )
  31. * } );
  32. *
  33. * // It will replace one character before the selection focus with the 'The "Big Foo"' text
  34. * // with the mention attribute filled with passed attributes.
  35. * editor.execute( 'mention', {
  36. * marker: '#',
  37. * mention: {
  38. * id: '#1234',
  39. * name: 'Foo',
  40. * title: 'Big Foo'
  41. * },
  42. * text: 'The "Big Foo"',
  43. * range: model.createRange( focus, focus.getShiftedBy( -1 ) )
  44. * } );
  45. *
  46. * @extends module:core/command~Command
  47. */
  48. export default class MentionCommand extends Command {
  49. /**
  50. * @inheritDoc
  51. */
  52. refresh() {
  53. const model = this.editor.model;
  54. const doc = model.document;
  55. this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'mention' );
  56. }
  57. /**
  58. * Executes the command.
  59. *
  60. * @param {Object} [options] Options for the executed command.
  61. * @param {Object|String} options.mention The mention object to insert. When a string is passed, it will be used to create a plain
  62. * object with the name attribute that equals the passed string.
  63. * @param {String} options.marker The marker character (e.g. `'@'`).
  64. * @param {String} [options.text] The text of the inserted mention. Defaults to the full mention string composed from `marker` and
  65. * `mention` string or `mention.id` if an object is passed.
  66. * @param {String} [options.range] The range to replace. Note that the replaced range might be shorter than the inserted text with the
  67. * mention attribute.
  68. * @fires execute
  69. */
  70. execute( options ) {
  71. const model = this.editor.model;
  72. const document = model.document;
  73. const selection = document.selection;
  74. const mentionData = typeof options.mention == 'string' ? { id: options.mention } : options.mention;
  75. const mentionID = mentionData.id;
  76. const range = options.range || selection.getFirstRange();
  77. const mentionText = options.text || mentionID;
  78. const mention = _addMentionAttributes( { _text: mentionText, id: mentionID }, mentionData );
  79. if ( options.marker.length != 1 ) {
  80. /**
  81. * The marker must be a single character.
  82. *
  83. * Correct markers: `'@'`, `'#'`.
  84. *
  85. * Incorrect markers: `'$$'`, `'[@'`.
  86. *
  87. * See {@link module:mention/mention~MentionConfig}.
  88. *
  89. * @error mentioncommand-incorrect-marker
  90. */
  91. throw new CKEditorError(
  92. 'mentioncommand-incorrect-marker: The marker must be a single character.',
  93. this
  94. );
  95. }
  96. if ( mentionID.charAt( 0 ) != options.marker ) {
  97. /**
  98. * The feed item ID must start with the marker character.
  99. *
  100. * Correct mention feed setting:
  101. *
  102. * mentions: [
  103. * {
  104. * marker: '@',
  105. * feed: [ '@Ann', '@Barney', ... ]
  106. * }
  107. * ]
  108. *
  109. * Incorrect mention feed setting:
  110. *
  111. * mentions: [
  112. * {
  113. * marker: '@',
  114. * feed: [ 'Ann', 'Barney', ... ]
  115. * }
  116. * ]
  117. *
  118. * See {@link module:mention/mention~MentionConfig}.
  119. *
  120. * @error mentioncommand-incorrect-id
  121. */
  122. throw new CKEditorError(
  123. 'mentioncommand-incorrect-id: The item id must start with the marker character.',
  124. this
  125. );
  126. }
  127. model.change( writer => {
  128. const currentAttributes = toMap( selection.getAttributes() );
  129. const attributesWithMention = new Map( currentAttributes.entries() );
  130. attributesWithMention.set( 'mention', mention );
  131. // Replace a range with the text with a mention.
  132. model.insertContent( writer.createText( mentionText, attributesWithMention ), range );
  133. model.insertContent( writer.createText( ' ', currentAttributes ), range.start.getShiftedBy( mentionText.length ) );
  134. } );
  135. }
  136. }