gitlab-org--gitlab-foss/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue

204 lines
5.4 KiB
Vue

<script>
import { GlSegmentedControl } from '@gitlab/ui';
import { __ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import axios from '~/lib/utils/axios_utils';
import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '../../constants';
import MarkdownField from './field.vue';
export default {
components: {
MarkdownField,
LocalStorageSync,
GlSegmentedControl,
ContentEditor: () =>
import(
/* webpackChunkName: 'content_editor' */ '~/content_editor/components/content_editor.vue'
),
},
props: {
value: {
type: String,
required: true,
},
renderMarkdownPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
uploadsPath: {
type: String,
required: false,
default: () => window.uploads_path,
},
enableContentEditor: {
type: Boolean,
required: false,
default: true,
},
formFieldId: {
type: String,
required: true,
},
formFieldName: {
type: String,
required: true,
},
enablePreview: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
formFieldPlaceholder: {
type: String,
required: false,
default: '',
},
formFieldAriaLabel: {
type: String,
required: false,
default: '',
},
initOnAutofocus: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
editingMode: EDITING_MODE_MARKDOWN_FIELD,
switchEditingControlEnabled: true,
autofocus: this.initOnAutofocus,
};
},
computed: {
isContentEditorActive() {
return this.enableContentEditor && this.editingMode === EDITING_MODE_CONTENT_EDITOR;
},
contentEditorAutofocus() {
// Match textarea focus behavior
return this.autofocus ? 'end' : false;
},
},
mounted() {
this.autofocusTextarea(this.editingMode);
},
methods: {
updateMarkdownFromContentEditor({ markdown }) {
this.$emit('input', markdown);
},
updateMarkdownFromMarkdownField({ target }) {
this.$emit('input', target.value);
},
enableSwitchEditingControl() {
this.switchEditingControlEnabled = true;
},
disableSwitchEditingControl() {
this.switchEditingControlEnabled = false;
},
renderMarkdown(markdown) {
return axios.post(this.renderMarkdownPath, { text: markdown }).then(({ data }) => data.body);
},
onEditingModeChange(editingMode) {
this.notifyEditingModeChange(editingMode);
this.enableAutofocus(editingMode);
},
onEditingModeRestored(editingMode) {
this.notifyEditingModeChange(editingMode);
},
notifyEditingModeChange(editingMode) {
this.$emit(editingMode);
},
enableAutofocus(editingMode) {
this.autofocus = true;
this.autofocusTextarea(editingMode);
},
autofocusTextarea(editingMode) {
if (this.autofocus && editingMode === EDITING_MODE_MARKDOWN_FIELD) {
this.$refs.textarea.focus();
}
},
},
switchEditingControlOptions: [
{ text: __('Source'), value: EDITING_MODE_MARKDOWN_FIELD },
{ text: __('Rich text'), value: EDITING_MODE_CONTENT_EDITOR },
],
};
</script>
<template>
<div>
<div class="gl-display-flex gl-justify-content-start gl-mb-3">
<gl-segmented-control
v-model="editingMode"
data-testid="toggle-editing-mode-button"
data-qa-selector="editing_mode_button"
class="gl-display-flex"
:options="$options.switchEditingControlOptions"
:disabled="!enableContentEditor || !switchEditingControlEnabled"
@change="onEditingModeChange"
/>
</div>
<local-storage-sync
v-model="editingMode"
storage-key="gl-wiki-content-editor-enabled"
@input="onEditingModeRestored"
/>
<markdown-field
v-if="!isContentEditorActive"
:markdown-preview-path="renderMarkdownPath"
can-attach-file
:enable-autocomplete="enableAutocomplete"
:textarea-value="value"
:markdown-docs-path="markdownDocsPath"
:uploads-path="uploadsPath"
:enable-preview="enablePreview"
class="bordered-box"
>
<template #textarea>
<textarea
:id="formFieldId"
ref="textarea"
:value="value"
:name="formFieldName"
class="note-textarea js-gfm-input js-autosize markdown-area"
dir="auto"
data-supports-quick-actions="false"
data-qa-selector="markdown_editor_form_field"
:aria-label="formFieldAriaLabel"
:placeholder="formFieldPlaceholder"
@input="updateMarkdownFromMarkdownField"
>
</textarea>
</template>
</markdown-field>
<div v-else>
<content-editor
:render-markdown="renderMarkdown"
:uploads-path="uploadsPath"
:markdown="value"
:autofocus="contentEditorAutofocus"
@change="updateMarkdownFromContentEditor"
@loading="disableSwitchEditingControl"
@loadingSuccess="enableSwitchEditingControl"
@loadingError="enableSwitchEditingControl"
/>
<input
:id="formFieldId"
:value="value"
:name="formFieldName"
data-qa-selector="markdown_editor_form_field"
type="hidden"
/>
</div>
</div>
</template>