diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue b/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue new file mode 100644 index 00000000000..a4b509f8656 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue @@ -0,0 +1,117 @@ +<script> +import { GlSafeHtmlDirective as SafeHtml, GlDrawer, GlAlert, GlSkeletonLoader } from '@gitlab/ui'; +import $ from 'jquery'; +import '~/behaviors/markdown/render_gfm'; +import { s__ } from '~/locale'; +import { contentTop } from '~/lib/utils/common_utils'; +import { getRenderedMarkdown } from './utils/fetch'; + +export const cache = {}; + +export default { + name: 'MarkdownDrawer', + components: { + GlDrawer, + GlAlert, + GlSkeletonLoader, + }, + directives: { + SafeHtml, + }, + i18n: { + alert: s__('MardownDrawer|Could not fetch help contents.'), + }, + props: { + documentPath: { + type: String, + required: true, + }, + }, + data() { + return { + loading: false, + hasFetchError: false, + title: '', + body: null, + open: false, + }; + }, + computed: { + drawerOffsetTop() { + return `${contentTop()}px`; + }, + }, + watch: { + documentPath: { + immediate: true, + handler: 'fetchMarkdown', + }, + open(open) { + if (open && this.body) { + this.renderGLFM(); + } + }, + }, + methods: { + async fetchMarkdown() { + const cached = cache[this.documentPath]; + this.hasFetchError = false; + this.title = ''; + if (cached) { + this.title = cached.title; + this.body = cached.body; + if (this.open) { + this.renderGLFM(); + } + } else { + this.loading = true; + const { body, title, hasFetchError } = await getRenderedMarkdown(this.documentPath); + this.title = title; + this.body = body; + this.loading = false; + this.hasFetchError = hasFetchError; + if (this.open) { + this.renderGLFM(); + } + cache[this.documentPath] = { title, body }; + } + }, + renderGLFM() { + this.$nextTick(() => { + $(this.$refs['content-element']).renderGFM(); + }); + }, + closeDrawer() { + this.open = false; + }, + toggleDrawer() { + this.open = !this.open; + }, + openDrawer() { + this.open = true; + }, + }, + safeHtmlConfig: { + ADD_TAGS: ['copy-code'], + }, +}; +</script> +<template> + <gl-drawer :header-height="drawerOffsetTop" :open="open" header-sticky @close="closeDrawer"> + <template #title> + <h4 data-testid="title-element" class="gl-m-0">{{ title }}</h4> + </template> + <template #default> + <div v-if="hasFetchError"> + <gl-alert :dismissible="false" variant="danger">{{ $options.i18n.alert }}</gl-alert> + </div> + <gl-skeleton-loader v-else-if="loading" /> + <div + v-else + ref="content-element" + v-safe-html:[$options.safeHtmlConfig]="body" + class="md" + ></div> + </template> + </gl-drawer> +</template> |