gitlab-ce/app/assets/javascripts/pages/shared/wikis/components/wiki_template.vue

100 lines
2.6 KiB
Vue

<script>
import { GlCollapsibleListbox } from '@gitlab/ui';
import { escape } from 'lodash';
import { __, sprintf } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { InternalEvents } from '~/tracking';
const trackingMixin = InternalEvents.mixin();
export default {
components: {
GlCollapsibleListbox,
},
directives: {
SafeHtml,
},
mixins: [trackingMixin],
props: {
templates: {
type: Array,
required: true,
},
format: {
type: String,
required: true,
},
},
data() {
return {
searchTerm: '',
selectedTemplate: null,
};
},
computed: {
templatesList() {
return this.templates
.filter((template) => template.format === this.format)
.map((template) => ({
text: template.title,
value: `${template.path}/raw`,
}))
.filter(({ text }) => text.toLowerCase().includes(this.searchTerm.toLowerCase()));
},
toggleText() {
const selectedTemplateLabel = this.templatesList.find(
({ value }) => value === this.selectedTemplate,
)?.text;
return selectedTemplateLabel
? sprintf(__('Template: %{title}'), { title: selectedTemplateLabel })
: __('Choose a template');
},
},
methods: {
filterTemplates(searchTerm) {
this.searchTerm = searchTerm;
},
async selectTemplate(templatePath) {
const template = await axios.get(templatePath);
this.trackEvent('apply_wiki_template');
this.$emit('input', template.data);
},
highlight(text) {
return this.searchTerm
? String(escape(text)).replace(
new RegExp(this.searchTerm, 'i'),
(match) => `<strong>${match}</strong>`,
)
: escape(text);
},
},
i18n: {
searchTemplates: __('Search templates'),
noMatchingTemplates: __('No matching templates'),
chooseTemplate: __('Choose a template'),
},
safeHtmlConfig: { ALLOWED_TAGS: ['strong'] },
};
</script>
<template>
<gl-collapsible-listbox
v-model="selectedTemplate"
:items="templatesList"
searchable
block
:toggle-text="toggleText"
:search-placeholder="$options.i18n.searchTemplates"
:no-results-text="$options.i18n.noMatchingTemplates"
:header-text="$options.i18n.chooseTemplate"
@search="filterTemplates"
@select="selectTemplate"
>
<template #list-item="{ item }">
<span v-safe-html:[$options.safeHtmlConfig]="highlight(item.text)"> </span>
</template>
</gl-collapsible-listbox>
</template>