Chatwoot/app/javascript/dashboard/components/widgets/WootWriter/FullEditor.vue
2022-12-21 20:00:29 +05:30

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>