202 lines
4.6 KiB
Vue
202 lines
4.6 KiB
Vue
<template>
|
|
<div>
|
|
<div class="editor-root">
|
|
<div ref="editor" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { EditorView } from 'prosemirror-view';
|
|
|
|
import { schema, defaultMarkdownSerializer } from 'prosemirror-markdown';
|
|
|
|
import { EditorState, Selection } from 'prosemirror-state';
|
|
import { defaultMarkdownParser } from 'prosemirror-markdown';
|
|
import { wootWriterSetup } from '@chatwoot/prosemirror-schema';
|
|
import { buildMenuItems } from './src/menu';
|
|
import marksFormattingRules from './src/marksInputRules';
|
|
import blockFormattingRules from './src/blockInputRules';
|
|
|
|
import '@chatwoot/prosemirror-schema/src/woot-editor.css';
|
|
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
|
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
|
|
const createState = (content, placeholder, plugins = []) => {
|
|
return EditorState.create({
|
|
doc: defaultMarkdownParser.parse(content),
|
|
plugins: wootWriterSetup({
|
|
schema,
|
|
placeholder,
|
|
plugins,
|
|
menuContent: buildMenuItems(schema).fullMenu,
|
|
}),
|
|
});
|
|
};
|
|
|
|
export default {
|
|
name: 'WootMessageEditor',
|
|
mixins: [eventListenerMixins, uiSettingsMixin],
|
|
props: {
|
|
value: { type: String, default: '' },
|
|
editorId: { type: String, default: '' },
|
|
placeholder: { type: String, default: '' },
|
|
isPrivate: { type: Boolean, default: false },
|
|
},
|
|
data() {
|
|
return {
|
|
showCannedMenu: false,
|
|
mentionSearchKey: '',
|
|
cannedSearchTerm: '',
|
|
editorView: null,
|
|
range: null,
|
|
state: undefined,
|
|
};
|
|
},
|
|
computed: {
|
|
contentFromEditor() {
|
|
return defaultMarkdownSerializer.serialize(this.editorView.state.doc);
|
|
},
|
|
plugins() {
|
|
return [blockFormattingRules(schema), marksFormattingRules(schema)];
|
|
},
|
|
},
|
|
watch: {
|
|
value(newValue = '') {
|
|
if (newValue !== this.contentFromEditor) {
|
|
this.reloadState();
|
|
}
|
|
},
|
|
editorId() {
|
|
this.reloadState();
|
|
},
|
|
},
|
|
created() {
|
|
this.state = createState(this.value, this.placeholder, this.plugins);
|
|
},
|
|
mounted() {
|
|
this.createEditorView();
|
|
this.editorView.updateState(this.state);
|
|
this.focusEditorInputField();
|
|
},
|
|
methods: {
|
|
addBold() {
|
|
const { state, dispatch } = this.editorView;
|
|
const { tr } = state;
|
|
tr.insertText('**bold**');
|
|
dispatch(tr);
|
|
},
|
|
reloadState() {
|
|
this.state = createState(this.value, this.placeholder, this.plugins);
|
|
this.editorView.updateState(this.state);
|
|
this.focusEditorInputField();
|
|
},
|
|
createEditorView() {
|
|
this.editorView = new EditorView(this.$refs.editor, {
|
|
state: this.state,
|
|
dispatchTransaction: tx => {
|
|
this.state = this.state.apply(tx);
|
|
this.emitOnChange();
|
|
},
|
|
handleDOMEvents: {
|
|
keyup: () => {
|
|
this.onKeyup();
|
|
},
|
|
keydown: (view, event) => {
|
|
this.onKeydown(event);
|
|
},
|
|
focus: () => {
|
|
this.onFocus();
|
|
},
|
|
blur: () => {
|
|
this.onBlur();
|
|
},
|
|
},
|
|
});
|
|
},
|
|
|
|
handleKeyEvents() {},
|
|
focusEditorInputField() {
|
|
const { tr } = this.editorView.state;
|
|
const selection = Selection.atEnd(tr.doc);
|
|
|
|
this.editorView.dispatch(tr.setSelection(selection));
|
|
this.editorView.focus();
|
|
},
|
|
|
|
emitOnChange() {
|
|
this.editorView.updateState(this.state);
|
|
|
|
this.$emit('input', this.contentFromEditor);
|
|
},
|
|
|
|
onKeyup() {},
|
|
onKeydown() {},
|
|
onBlur() {
|
|
this.$emit('blur');
|
|
},
|
|
onFocus() {
|
|
this.$emit('focus');
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.ProseMirror-menubar-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
> .ProseMirror {
|
|
padding: 0;
|
|
word-break: break-word;
|
|
}
|
|
}
|
|
|
|
.editor-root {
|
|
width: 100%;
|
|
}
|
|
|
|
.ProseMirror-woot-style {
|
|
min-height: 8rem;
|
|
max-height: 12rem;
|
|
overflow: auto;
|
|
}
|
|
|
|
.ProseMirror-prompt {
|
|
z-index: var(--z-index-highest);
|
|
background: var(--color-background-light);
|
|
border-radius: var(--border-radius-normal);
|
|
border: 1px solid var(--color-border);
|
|
}
|
|
|
|
.is-private {
|
|
.prosemirror-mention-node {
|
|
font-weight: var(--font-weight-medium);
|
|
background: var(--s-50);
|
|
color: var(--s-900);
|
|
padding: 0 var(--space-smaller);
|
|
}
|
|
}
|
|
|
|
.editor-wrap {
|
|
margin-bottom: var(--space-normal);
|
|
}
|
|
|
|
.message-editor {
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--border-radius-normal);
|
|
padding: 0 var(--space-slab);
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.editor_warning {
|
|
border: 1px solid var(--r-400);
|
|
}
|
|
|
|
.editor-warning__message {
|
|
color: var(--r-400);
|
|
font-weight: var(--font-weight-normal);
|
|
padding: var(--space-smaller) 0 0 0;
|
|
}
|
|
</style>
|