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

140 lines
3.2 KiB
Vue
Raw Normal View History

2020-05-24 23:13:21 +05:30
<script>
import 'codemirror/lib/codemirror.css';
import '@toast-ui/editor/dist/toastui-editor.css';
2020-07-28 23:09:34 +05:30
import AddImageModal from './modals/add_image/add_image_modal.vue';
2020-06-23 00:09:42 +05:30
import {
EDITOR_OPTIONS,
EDITOR_TYPES,
EDITOR_HEIGHT,
EDITOR_PREVIEW_STYLE,
CUSTOM_EVENTS,
} from './constants';
import {
2020-07-28 23:09:34 +05:30
registerHTMLToMarkdownRenderer,
2020-06-23 00:09:42 +05:30
addCustomEventListener,
removeCustomEventListener,
addImage,
getMarkdown,
2020-07-28 23:09:34 +05:30
} from './services/editor_service';
2020-05-24 23:13:21 +05:30
export default {
components: {
ToastEditor: () =>
import(/* webpackChunkName: 'toast_editor' */ '@toast-ui/vue-editor').then(
toast => toast.Editor,
),
2020-06-23 00:09:42 +05:30
AddImageModal,
2020-05-24 23:13:21 +05:30
},
props: {
2020-07-28 23:09:34 +05:30
content: {
2020-05-24 23:13:21 +05:30
type: String,
required: true,
},
options: {
type: Object,
required: false,
default: () => EDITOR_OPTIONS,
},
initialEditType: {
type: String,
required: false,
default: EDITOR_TYPES.wysiwyg,
},
height: {
type: String,
required: false,
default: EDITOR_HEIGHT,
},
previewStyle: {
type: String,
required: false,
default: EDITOR_PREVIEW_STYLE,
},
2020-07-28 23:09:34 +05:30
imageRoot: {
type: String,
required: true,
validator: prop => prop.endsWith('/'),
},
2020-05-24 23:13:21 +05:30
},
2020-06-23 00:09:42 +05:30
data() {
return {
editorApi: null,
previousMode: null,
};
},
2020-05-24 23:13:21 +05:30
computed: {
editorOptions() {
return { ...EDITOR_OPTIONS, ...this.options };
},
2020-06-23 00:09:42 +05:30
editorInstance() {
return this.$refs.editor;
},
},
beforeDestroy() {
2020-07-28 23:09:34 +05:30
this.removeListeners();
2020-05-24 23:13:21 +05:30
},
methods: {
2020-07-28 23:09:34 +05:30
addListeners(editorApi) {
addCustomEventListener(editorApi, CUSTOM_EVENTS.openAddImageModal, this.onOpenAddImageModal);
editorApi.eventManager.listen('changeMode', this.onChangeMode);
},
removeListeners() {
removeCustomEventListener(
this.editorApi,
CUSTOM_EVENTS.openAddImageModal,
this.onOpenAddImageModal,
);
this.editorApi.eventManager.removeEventHandler('changeMode', this.onChangeMode);
},
resetInitialValue(newVal) {
this.editorInstance.invoke('setMarkdown', newVal);
},
2020-05-24 23:13:21 +05:30
onContentChanged() {
2020-06-23 00:09:42 +05:30
this.$emit('input', getMarkdown(this.editorInstance));
},
onLoad(editorApi) {
this.editorApi = editorApi;
2020-07-28 23:09:34 +05:30
registerHTMLToMarkdownRenderer(editorApi);
2020-06-23 00:09:42 +05:30
2020-07-28 23:09:34 +05:30
this.addListeners(editorApi);
2020-06-23 00:09:42 +05:30
},
onOpenAddImageModal() {
this.$refs.addImageModal.show();
},
2020-07-28 23:09:34 +05:30
onAddImage({ imageUrl, altText, file }) {
const image = { imageUrl, altText };
if (file) {
this.$emit('uploadImage', { file, imageUrl });
// TODO - ensure that the actual repo URL for the image is used in Markdown mode
}
2020-06-23 00:09:42 +05:30
addImage(this.editorInstance, image);
2020-05-24 23:13:21 +05:30
},
2020-06-23 00:09:42 +05:30
onChangeMode(newMode) {
this.$emit('modeChange', newMode);
2020-05-24 23:13:21 +05:30
},
},
};
</script>
<template>
2020-06-23 00:09:42 +05:30
<div>
<toast-editor
ref="editor"
2020-07-28 23:09:34 +05:30
:initial-value="content"
2020-06-23 00:09:42 +05:30
:options="editorOptions"
:preview-style="previewStyle"
:initial-edit-type="initialEditType"
:height="height"
@change="onContentChanged"
@load="onLoad"
/>
2020-07-28 23:09:34 +05:30
<add-image-modal ref="addImageModal" :image-root="imageRoot" @addImage="onAddImage" />
2020-06-23 00:09:42 +05:30
</div>
2020-05-24 23:13:21 +05:30
</template>