diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
commit | a7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch) | |
tree | 7452bd5c3545c2fa67a28aa013835fb4fa071baf /app/assets/javascripts/vue_shared/components/gfm_autocomplete | |
parent | ee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff) |
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/gfm_autocomplete')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue | 106 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js | 195 |
2 files changed, 0 insertions, 301 deletions
diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue deleted file mode 100644 index 9ab91e567e6..00000000000 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue +++ /dev/null @@ -1,106 +0,0 @@ -<script> -import Tribute from '@gitlab/tributejs'; -import { - GfmAutocompleteType, - tributeConfig, -} from 'ee_else_ce/vue_shared/components/gfm_autocomplete/utils'; -import * as Emoji from '~/emoji'; -import createFlash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import { __ } from '~/locale'; -import SidebarMediator from '~/sidebar/sidebar_mediator'; - -export default { - errorMessage: __( - 'An error occurred while getting autocomplete data. Please refresh the page and try again.', - ), - props: { - autocompleteTypes: { - type: Array, - required: false, - default: () => Object.values(GfmAutocompleteType), - }, - dataSources: { - type: Object, - required: false, - default: () => gl.GfmAutoComplete?.dataSources || {}, - }, - }, - computed: { - config() { - return this.autocompleteTypes.map((type) => ({ - ...tributeConfig[type].config, - loadingItemTemplate: `<span class="gl-spinner gl-vertical-align-text-bottom gl-ml-3 gl-mr-2"></span>${__( - 'Loading', - )}`, - requireLeadingSpace: true, - values: this.getValues(type), - })); - }, - }, - mounted() { - this.cache = {}; - this.tribute = new Tribute({ collection: this.config }); - - const input = this.$slots.default?.[0]?.elm; - this.tribute.attach(input); - }, - beforeDestroy() { - const input = this.$slots.default?.[0]?.elm; - this.tribute.detach(input); - }, - methods: { - cacheAssignees() { - const isAssigneesLengthSame = - this.assignees?.length === SidebarMediator.singleton?.store?.assignees?.length; - - if (!this.assignees || !isAssigneesLengthSame) { - this.assignees = - SidebarMediator.singleton?.store?.assignees?.map((assignee) => assignee.username) || []; - } - }, - filterValues(type) { - // The assignees AJAX response can come after the user first invokes autocomplete - // so we need to check more than once if we need to update the assignee cache - this.cacheAssignees(); - - return tributeConfig[type].filterValues - ? tributeConfig[type].filterValues({ - assignees: this.assignees, - collection: this.cache[type], - fullText: this.$slots.default?.[0]?.elm?.value, - selectionStart: this.$slots.default?.[0]?.elm?.selectionStart, - }) - : this.cache[type]; - }, - getValues(type) { - return (inputText, processValues) => { - if (this.cache[type]) { - processValues(this.filterValues(type)); - } else if (type === GfmAutocompleteType.Emojis) { - Emoji.initEmojiMap() - .then(() => { - const emojis = Emoji.getValidEmojiNames(); - this.cache[type] = emojis; - processValues(emojis); - }) - .catch(() => createFlash({ message: this.$options.errorMessage })); - } else if (this.dataSources[type]) { - axios - .get(this.dataSources[type]) - .then((response) => { - this.cache[type] = response.data; - processValues(this.filterValues(type)); - }) - .catch(() => createFlash({ message: this.$options.errorMessage })); - } else { - processValues([]); - } - }; - }, - }, - render(createElement) { - return createElement('div', this.$slots.default); - }, -}; -</script> diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js deleted file mode 100644 index 44c3fc34ba6..00000000000 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js +++ /dev/null @@ -1,195 +0,0 @@ -import { escape, last } from 'lodash'; -import * as Emoji from '~/emoji'; -import { spriteIcon } from '~/lib/utils/common_utils'; - -const groupType = 'Group'; // eslint-disable-line @gitlab/require-i18n-strings - -// Number of users to show in the autocomplete menu to avoid doing a mass fetch of 100+ avatars -const memberLimit = 10; - -const nonWordOrInteger = /\W|^\d+$/; - -export const menuItemLimit = 100; - -export const GfmAutocompleteType = { - Emojis: 'emojis', - Issues: 'issues', - Labels: 'labels', - Members: 'members', - MergeRequests: 'mergeRequests', - Milestones: 'milestones', - QuickActions: 'commands', - Snippets: 'snippets', -}; - -function doesCurrentLineStartWith(searchString, fullText, selectionStart) { - const currentLineNumber = fullText.slice(0, selectionStart).split('\n').length; - const currentLine = fullText.split('\n')[currentLineNumber - 1]; - return currentLine.startsWith(searchString); -} - -export const tributeConfig = { - [GfmAutocompleteType.Emojis]: { - config: { - trigger: ':', - lookup: (value) => value, - menuItemLimit, - menuItemTemplate: ({ original }) => `${original} ${Emoji.glEmojiTag(original)}`, - selectTemplate: ({ original }) => `:${original}:`, - }, - }, - - [GfmAutocompleteType.Issues]: { - config: { - trigger: '#', - lookup: (value) => `${value.iid}${value.title}`, - menuItemLimit, - menuItemTemplate: ({ original }) => - `<small>${original.reference || original.iid}</small> ${escape(original.title)}`, - selectTemplate: ({ original }) => original.reference || `#${original.iid}`, - }, - }, - - [GfmAutocompleteType.Labels]: { - config: { - trigger: '~', - lookup: 'title', - menuItemLimit, - menuItemTemplate: ({ original }) => ` - <span class="dropdown-label-box" style="background: ${escape(original.color)};"></span> - ${escape(original.title)}`, - selectTemplate: ({ original }) => - nonWordOrInteger.test(original.title) - ? `~"${escape(original.title)}"` - : `~${escape(original.title)}`, - }, - filterValues({ collection, fullText, selectionStart }) { - if (doesCurrentLineStartWith('/label', fullText, selectionStart)) { - return collection.filter((label) => !label.set); - } - - if (doesCurrentLineStartWith('/unlabel', fullText, selectionStart)) { - return collection.filter((label) => label.set); - } - - return collection; - }, - }, - - [GfmAutocompleteType.Members]: { - config: { - trigger: '@', - fillAttr: 'username', - lookup: (value) => - value.type === groupType ? last(value.name.split(' / ')) : `${value.name}${value.username}`, - menuItemLimit: memberLimit, - menuItemTemplate: ({ original }) => { - const commonClasses = 'gl-avatar gl-avatar-s32 gl-flex-shrink-0'; - const noAvatarClasses = `${commonClasses} gl-rounded-small - gl-display-flex gl-align-items-center gl-justify-content-center`; - - const avatar = original.avatar_url - ? `<img class="${commonClasses} gl-avatar-circle" src="${original.avatar_url}" alt="" />` - : `<div class="${noAvatarClasses}" aria-hidden="true"> - ${original.username.charAt(0).toUpperCase()}</div>`; - - let displayName = original.name; - let parentGroupOrUsername = `@${original.username}`; - - if (original.type === groupType) { - const splitName = original.name.split(' / '); - displayName = splitName.pop(); - parentGroupOrUsername = splitName.pop(); - } - - const count = original.count && !original.mentionsDisabled ? ` (${original.count})` : ''; - - const disabledMentionsIcon = original.mentionsDisabled - ? spriteIcon('notifications-off', 's16 gl-ml-3') - : ''; - - return ` - <div class="gl-display-flex gl-align-items-center"> - ${avatar} - <div class="gl-line-height-normal gl-ml-4"> - <div>${escape(displayName)}${count}</div> - <div class="gl-text-gray-700">${escape(parentGroupOrUsername)}</div> - </div> - ${disabledMentionsIcon} - </div> - `; - }, - }, - filterValues({ assignees, collection, fullText, selectionStart }) { - if (doesCurrentLineStartWith('/assign', fullText, selectionStart)) { - return collection.filter((member) => !assignees.includes(member.username)); - } - - if (doesCurrentLineStartWith('/unassign', fullText, selectionStart)) { - return collection.filter((member) => assignees.includes(member.username)); - } - - return collection; - }, - }, - - [GfmAutocompleteType.MergeRequests]: { - config: { - trigger: '!', - lookup: (value) => `${value.iid}${value.title}`, - menuItemLimit, - menuItemTemplate: ({ original }) => - `<small>${original.reference || original.iid}</small> ${escape(original.title)}`, - selectTemplate: ({ original }) => original.reference || `!${original.iid}`, - }, - }, - - [GfmAutocompleteType.Milestones]: { - config: { - trigger: '%', - lookup: 'title', - menuItemLimit, - menuItemTemplate: ({ original }) => escape(original.title), - selectTemplate: ({ original }) => `%"${escape(original.title)}"`, - }, - }, - - [GfmAutocompleteType.QuickActions]: { - config: { - trigger: '/', - fillAttr: 'name', - lookup: (value) => `${value.name}${value.aliases.join()}`, - menuItemLimit, - menuItemTemplate: ({ original }) => { - const aliases = original.aliases.length - ? `<small>(or /${original.aliases.join(', /')})</small>` - : ''; - - const params = original.params.length ? `<small>${original.params.join(' ')}</small>` : ''; - - let description = ''; - - if (original.warning) { - const confidentialIcon = - original.icon === 'confidential' ? spriteIcon('eye-slash', 's16 gl-mr-2') : ''; - description = `<small>${confidentialIcon}<em>${original.warning}</em></small>`; - } else if (original.description) { - description = `<small><em>${original.description}</em></small>`; - } - - return `<div>/${original.name} ${aliases} ${params}</div> - <div>${description}</div>`; - }, - }, - }, - - [GfmAutocompleteType.Snippets]: { - config: { - trigger: '$', - fillAttr: 'id', - lookup: (value) => `${value.id}${value.title}`, - menuItemLimit, - menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`, - }, - }, -}; |