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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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>
|