summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/gl_mentions.vue
blob: bbf293664a6f0338a6891e46a0f41a6937627100 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<script>
import escape from 'lodash/escape';
import sanitize from 'sanitize-html';
import Tribute from 'tributejs';
import axios from '~/lib/utils/axios_utils';
import { spriteIcon } from '~/lib/utils/common_utils';

/**
 * Creates the HTML template for each row of the mentions dropdown.
 *
 * @param original An object from the array returned from the `autocomplete_sources/members` API
 * @returns {string} An HTML template
 */
function createMenuItemTemplate({ original }) {
  const rectAvatarClass = original.type === 'Group' ? 'rect-avatar' : '';

  const avatarClasses = `avatar avatar-inline center s26 ${rectAvatarClass}
    align-items-center d-inline-flex justify-content-center`;

  const avatarTag = original.avatar_url
    ? `<img
        src="${original.avatar_url}"
        alt="${original.username}'s avatar"
        class="${avatarClasses}"/>`
    : `<div class="${avatarClasses}">${original.username.charAt(0).toUpperCase()}</div>`;

  const name = escape(sanitize(original.name));

  const count = original.count && !original.mentionsDisabled ? ` (${original.count})` : '';

  const icon = original.mentionsDisabled
    ? spriteIcon('notifications-off', 's16 vertical-align-middle prepend-left-5')
    : '';

  return `${avatarTag}
    ${original.username}
    <small class="small font-weight-normal gl-color-inherit">${name}${count}</small>
    ${icon}`;
}

/**
 * Creates the list of users to show in the mentions dropdown.
 *
 * @param inputText The text entered by the user in the mentions input field
 * @param processValues Callback function to set the list of users to show in the mentions dropdown
 */
function getMembers(inputText, processValues) {
  if (this.members) {
    processValues(this.members);
  } else if (this.dataSources.members) {
    axios
      .get(this.dataSources.members)
      .then(response => {
        this.members = response.data;
        processValues(response.data);
      })
      .catch(() => {});
  } else {
    processValues([]);
  }
}

export default {
  name: 'GlMentions',
  props: {
    dataSources: {
      type: Object,
      required: false,
      default: () => gl.GfmAutoComplete?.dataSources || {},
    },
  },
  data() {
    return {
      members: undefined,
      options: {
        trigger: '@',
        fillAttr: 'username',
        lookup(value) {
          return value.name + value.username;
        },
        menuItemTemplate: createMenuItemTemplate.bind(this),
        values: getMembers.bind(this),
      },
    };
  },
  mounted() {
    const input = this.$slots.default[0].elm;
    this.tribute = new Tribute(this.options);
    this.tribute.attach(input);
  },
  beforeDestroy() {
    const input = this.$slots.default[0].elm;
    if (this.tribute) {
      this.tribute.detach(input);
    }
  },
  render(h) {
    return h('div', this.$slots.default);
  },
};
</script>