CommentMentionHelper.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { Editor } from 'codemirror';
  2. import { i18n } from 'next-i18next';
  3. import { debounce } from 'throttle-debounce';
  4. import { apiv3Get } from '~/client/util/apiv3-client';
  5. type UsersListForHints = {
  6. text: string
  7. displayText: string
  8. }
  9. export default class CommentMentionHelper {
  10. editor: Editor;
  11. constructor(editor: Editor) {
  12. this.editor = editor;
  13. }
  14. getUsenameHint = (): void => {
  15. // Get word that contains `@` character at the begining
  16. const currentPos = this.editor.getCursor();
  17. const wordStart = this.editor.findWordAt(currentPos).anchor.ch - 1;
  18. const wordEnd = this.editor.findWordAt(currentPos).head.ch;
  19. const searchFrom = { line: currentPos.line, ch: wordStart };
  20. const searchTo = { line: currentPos.line, ch: wordEnd };
  21. const searchMention = this.editor.getRange(searchFrom, searchTo);
  22. const isMentioning = searchMention.charAt(0) === '@';
  23. // Return nothing if not mentioning
  24. if (!isMentioning) {
  25. return;
  26. }
  27. // Get username after `@` character and search username
  28. const mention = searchMention.slice(1);
  29. this.editor.showHint({
  30. completeSingle: false,
  31. hint: async() => {
  32. if (mention.length > 0) {
  33. const users = await this.getUsersList(mention);
  34. return {
  35. // Returns default value if i18n is null because it cannot do early return.
  36. list: users.length > 0 ? users : [{ text: '', displayText: i18n != null ? i18n.t('page_comment.no_user_found') : 'No user found' }],
  37. from: searchFrom,
  38. to: searchTo,
  39. };
  40. }
  41. },
  42. });
  43. };
  44. getUsersList = async(q: string): Promise<UsersListForHints[]> => {
  45. const limit = 20;
  46. const { data } = await apiv3Get('/users/usernames', { q, limit });
  47. return data.activeUser.usernames.map((username: string) => ({
  48. text: `@${username} `,
  49. displayText: username,
  50. }));
  51. };
  52. showUsernameHint = debounce(800, () => this.getUsenameHint());
  53. }