debian-mirror-gitlab/app/assets/javascripts/vue_shared/components/markdown/header.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

316 lines
9 KiB
Vue
Raw Normal View History

2017-09-10 17:25:29 +05:30
<script>
2022-04-04 11:22:00 +05:30
import { GlPopover, GlButton, GlTooltipDirective, GlTabs, GlTab } from '@gitlab/ui';
2021-03-11 19:13:27 +05:30
import $ from 'jquery';
2022-05-07 20:08:51 +05:30
import {
keysFor,
BOLD_TEXT,
ITALIC_TEXT,
STRIKETHROUGH_TEXT,
LINK_TEXT,
} from '~/behaviors/shortcuts/keybindings';
2020-10-24 23:57:45 +05:30
import { getSelectedFragment } from '~/lib/utils/common_utils';
2022-04-04 11:22:00 +05:30
import { s__, __ } from '~/locale';
2022-06-21 17:19:12 +05:30
import { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm';
2018-12-13 13:39:08 +05:30
import ToolbarButton from './toolbar_button.vue';
2017-09-10 17:25:29 +05:30
2018-12-13 13:39:08 +05:30
export default {
components: {
ToolbarButton,
2019-09-04 21:01:54 +05:30
GlPopover,
2020-10-24 23:57:45 +05:30
GlButton,
2022-04-04 11:22:00 +05:30
GlTabs,
GlTab,
2018-12-13 13:39:08 +05:30
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
previewMarkdown: {
type: Boolean,
required: true,
2017-09-10 17:25:29 +05:30
},
2019-02-15 15:39:39 +05:30
lineContent: {
type: String,
required: false,
default: '',
},
canSuggest: {
type: Boolean,
required: false,
default: true,
},
2019-09-04 21:01:54 +05:30
showSuggestPopover: {
type: Boolean,
required: false,
default: false,
},
2021-04-29 21:17:54 +05:30
suggestionStartIndex: {
type: Number,
required: false,
default: 0,
},
2022-05-07 20:08:51 +05:30
enablePreview: {
type: Boolean,
required: false,
default: true,
},
2018-12-13 13:39:08 +05:30
},
2020-10-24 23:57:45 +05:30
data() {
return {
tag: '> ',
2021-10-27 15:23:28 +05:30
suggestPopoverVisible: false,
2020-10-24 23:57:45 +05:30
};
},
2018-12-13 13:39:08 +05:30
computed: {
mdTable() {
return [
2019-10-12 21:52:04 +05:30
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
2020-04-22 19:07:51 +05:30
'| header | header |', // eslint-disable-line @gitlab/require-i18n-strings
2018-12-13 13:39:08 +05:30
'| ------ | ------ |',
2020-04-22 19:07:51 +05:30
'| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings
'| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings
2018-12-13 13:39:08 +05:30
].join('\n');
2017-09-10 17:25:29 +05:30
},
2019-02-15 15:39:39 +05:30
mdSuggestion() {
2021-04-29 21:17:54 +05:30
return [['```', `suggestion:-${this.suggestionStartIndex}+0`].join(''), `{text}`, '```'].join(
'\n',
);
2019-02-15 15:39:39 +05:30
},
2021-06-08 01:23:25 +05:30
mdCollapsibleSection() {
return ['<details><summary>Click to expand</summary>', `{text}`, '</details>'].join('\n');
},
2020-11-24 15:15:51 +05:30
isMac() {
// Accessing properties using ?. to allow tests to use
// this component without setting up window.gl.client.
// In production, window.gl.client should always be present.
return Boolean(window.gl?.client?.isMac);
},
modifierKey() {
return this.isMac ? '⌘' : s__('KeyboardKey|Ctrl+');
},
2018-12-13 13:39:08 +05:30
},
2021-10-27 15:23:28 +05:30
watch: {
showSuggestPopover() {
this.updateSuggestPopoverVisibility();
},
},
2018-12-13 13:39:08 +05:30
mounted() {
$(document).on('markdown-preview:show.vue', this.previewMarkdownTab);
$(document).on('markdown-preview:hide.vue', this.writeMarkdownTab);
2021-10-27 15:23:28 +05:30
this.updateSuggestPopoverVisibility();
2018-12-13 13:39:08 +05:30
},
beforeDestroy() {
$(document).off('markdown-preview:show.vue', this.previewMarkdownTab);
$(document).off('markdown-preview:hide.vue', this.writeMarkdownTab);
},
methods: {
2021-10-27 15:23:28 +05:30
async updateSuggestPopoverVisibility() {
await this.$nextTick();
this.suggestPopoverVisible = this.showSuggestPopover && this.canSuggest;
},
2018-12-13 13:39:08 +05:30
isValid(form) {
return (
!form ||
(form.find('.js-vue-markdown-field').length && $(this.$el).closest('form')[0] === form[0])
);
2017-09-10 17:25:29 +05:30
},
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
previewMarkdownTab(event, form) {
if (event.target.blur) event.target.blur();
if (!this.isValid(form)) return;
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
this.$emit('preview-markdown');
},
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
writeMarkdownTab(event, form) {
if (event.target.blur) event.target.blur();
if (!this.isValid(form)) return;
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
this.$emit('write-markdown');
2017-09-10 17:25:29 +05:30
},
2019-09-04 21:01:54 +05:30
handleSuggestDismissed() {
this.$emit('handleSuggestDismissed');
},
2020-10-24 23:57:45 +05:30
handleQuote() {
const documentFragment = getSelectedFragment();
if (!documentFragment || !documentFragment.textContent) {
this.tag = '> ';
return;
}
this.tag = '';
const transformed = CopyAsGFM.transformGFMSelection(documentFragment);
const area = this.$el.parentNode.querySelector('textarea');
CopyAsGFM.nodeToGFM(transformed)
2021-03-08 18:12:59 +05:30
.then((gfm) => {
2020-10-24 23:57:45 +05:30
CopyAsGFM.insertPastedText(area, documentFragment.textContent, CopyAsGFM.quoted(gfm));
})
.catch(() => {});
},
2018-12-13 13:39:08 +05:30
},
2021-04-29 21:17:54 +05:30
shortcuts: {
bold: keysFor(BOLD_TEXT),
italic: keysFor(ITALIC_TEXT),
2022-05-07 20:08:51 +05:30
strikethrough: keysFor(STRIKETHROUGH_TEXT),
2021-04-29 21:17:54 +05:30
link: keysFor(LINK_TEXT),
},
2022-04-04 11:22:00 +05:30
i18n: {
writeTabTitle: __('Write'),
previewTabTitle: __('Preview'),
},
2018-12-13 13:39:08 +05:30
};
2017-09-10 17:25:29 +05:30
</script>
<template>
<div class="md-header">
2022-04-04 11:22:00 +05:30
<gl-tabs content-class="gl-display-none">
<gl-tab
title-link-class="gl-pt-3 gl-px-3 js-md-write-button"
:title="$options.i18n.writeTabTitle"
:active="!previewMarkdown"
data-testid="write-tab"
@click="writeMarkdownTab($event)"
/>
<gl-tab
2022-05-07 20:08:51 +05:30
v-if="enablePreview"
2022-04-04 11:22:00 +05:30
title-link-class="gl-pt-3 gl-px-3 js-md-preview-button"
:title="$options.i18n.previewTabTitle"
:active="previewMarkdown"
data-testid="preview-tab"
@click="previewMarkdownTab($event)"
/>
<template #tabs-end>
<div
data-testid="md-header-toolbar"
2022-06-21 17:19:12 +05:30
:class="{ 'gl-display-none!': previewMarkdown }"
2022-04-04 11:22:00 +05:30
class="md-header-toolbar gl-ml-auto gl-pb-3 gl-justify-content-center"
2018-03-17 18:26:18 +05:30
>
2019-09-04 21:01:54 +05:30
<toolbar-button
2022-04-04 11:22:00 +05:30
tag="**"
:button-title="
sprintf(s__('MarkdownEditor|Add bold text (%{modifierKey}B)'), { modifierKey })
"
:shortcuts="$options.shortcuts.bold"
icon="bold"
/>
<toolbar-button
tag="_"
:button-title="
sprintf(s__('MarkdownEditor|Add italic text (%{modifierKey}I)'), { modifierKey })
"
:shortcuts="$options.shortcuts.italic"
icon="italic"
/>
2022-05-07 20:08:51 +05:30
<toolbar-button
tag="~~"
:button-title="
sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)'), {
modifierKey,
})
"
:shortcuts="$options.shortcuts.strikethrough"
icon="strikethrough"
/>
2022-04-04 11:22:00 +05:30
<toolbar-button
2019-09-04 21:01:54 +05:30
:prepend="true"
2022-04-04 11:22:00 +05:30
:tag="tag"
:button-title="__('Insert a quote')"
icon="quote"
@click="handleQuote"
2019-09-04 21:01:54 +05:30
/>
2022-04-04 11:22:00 +05:30
<template v-if="canSuggest">
<toolbar-button
ref="suggestButton"
:tag="mdSuggestion"
:prepend="true"
:button-title="__('Insert suggestion')"
:cursor-offset="4"
:tag-content="lineContent"
icon="doc-code"
data-qa-selector="suggestion_button"
class="js-suggestion-btn"
2019-09-04 21:01:54 +05:30
@click="handleSuggestDismissed"
2022-04-04 11:22:00 +05:30
/>
<gl-popover
v-if="suggestPopoverVisible"
:target="$refs.suggestButton.$el"
:css-classes="['diff-suggest-popover']"
placement="bottom"
:show="suggestPopoverVisible"
2019-09-04 21:01:54 +05:30
>
2022-04-04 11:22:00 +05:30
<strong>{{ __('New! Suggest changes directly') }}</strong>
<p class="mb-2">
{{
__(
'Suggest code changes which can be immediately applied in one click. Try it out!',
)
}}
</p>
<gl-button
variant="info"
category="primary"
size="small"
@click="handleSuggestDismissed"
>
{{ __('Got it') }}
</gl-button>
</gl-popover>
</template>
<toolbar-button tag="`" tag-block="```" :button-title="__('Insert code')" icon="code" />
<toolbar-button
tag="[{text}](url)"
tag-select="url"
:button-title="
sprintf(s__('MarkdownEditor|Add a link (%{modifierKey}K)'), { modifierKey })
"
:shortcuts="$options.shortcuts.link"
icon="link"
/>
<toolbar-button
:prepend="true"
tag="- "
:button-title="__('Add a bullet list')"
icon="list-bulleted"
/>
<toolbar-button
:prepend="true"
tag="1. "
:button-title="__('Add a numbered list')"
icon="list-numbered"
/>
<toolbar-button
:prepend="true"
tag="- [ ] "
:button-title="__('Add a task list')"
icon="list-task"
/>
<toolbar-button
:tag="mdCollapsibleSection"
:prepend="true"
tag-select="Click to expand"
:button-title="__('Add a collapsible section')"
icon="details-block"
/>
<toolbar-button
:tag="mdTable"
:prepend="true"
:button-title="__('Add a table')"
icon="table"
/>
<toolbar-button
class="js-zen-enter"
:prepend="true"
:button-title="__('Go full screen')"
icon="maximize"
/>
</div>
</template>
</gl-tabs>
2017-09-10 17:25:29 +05:30
</div>
</template>