<template> <div class="comment comment--new" @keydown.esc.stop="cancelNewComment"> <div class="comment__header flex flex--row flex--space-between flex--align-center"> <div class="comment__user flex flex--row flex--align-center"> <div class="comment__user-image"> <user-image :user-id="userId"></user-image> </div> <span class="user-name">{{loginToken.name}}</span> </div> </div> <div class="comment__text"> <div class="comment__text-inner"> <pre class="markdown-highlighting"></pre> </div> </div> <div class="comment__buttons flex flex--row flex--end"> <button class="comment__button button" @click="cancelNewComment">取消</button> <button class="comment__button button" @click="addComment">确认</button> </div> </div> </template> <script> import { mapGetters, mapMutations, mapActions } from 'vuex'; import Prism from 'prismjs'; import UserImage from '../UserImage'; import cledit from '../../services/editor/cledit'; import editorSvc from '../../services/editorSvc'; import markdownConversionSvc from '../../services/markdownConversionSvc'; import utils from '../../services/utils'; import userSvc from '../../services/userSvc'; import store from '../../store'; import badgeSvc from '../../services/badgeSvc'; export default { components: { UserImage, }, computed: { ...mapGetters('workspace', [ 'loginToken', ]), userId() { return userSvc.getCurrentUserId(); }, }, methods: { ...mapMutations('discussion', [ 'setNewCommentFocus', ]), ...mapActions('discussion', [ 'cancelNewComment', ]), addComment() { const text = store.state.discussion.newCommentText.trim(); if (text.length) { if (text.length > 2000) { store.dispatch('notification/error', 'Comment is too long.'); } else { // Create comment const discussionId = store.state.discussion.currentDiscussionId; const comment = { discussionId, sub: this.userId, text, created: Date.now(), }; const patch = { comments: { ...store.getters['content/current'].comments, [utils.uid()]: comment, }, }; if (discussionId === store.state.discussion.newDiscussionId) { // Create discussion patch.discussions = { ...store.getters['content/current'].discussions, [discussionId]: store.getters['discussion/newDiscussion'], }; badgeSvc.addBadge('createDiscussion'); } else { badgeSvc.addBadge('addComment'); } store.dispatch('content/patchCurrent', patch); store.commit('discussion/setNewCommentText'); store.commit('discussion/setIsCommenting'); } } }, }, mounted() { const preElt = this.$el.querySelector('pre.markdown-highlighting'); const scrollerElt = this.$el.querySelector('.comment__text-inner'); const clEditor = cledit(preElt, scrollerElt, true); clEditor.init({ sectionHighlighter: section => Prism.highlight( section.text, editorSvc.prismGrammars[section.data], ), sectionParser: text => markdownConversionSvc .parseSections(editorSvc.converter, text).sections, content: store.state.discussion.newCommentText, selectionStart: store.state.discussion.newCommentSelection.start, selectionEnd: store.state.discussion.newCommentSelection.end, getCursorFocusRatio: () => 0.2, }); clEditor.on('focus', () => this.setNewCommentFocus(true)); // Save typed content and selection clEditor.on('contentChanged', value => store.commit('discussion/setNewCommentText', value)); clEditor.selectionMgr.on('selectionChanged', (start, end) => store.commit('discussion/setNewCommentSelection', { start, end, })); const isSticky = this.$el.parentNode.classList.contains('sticky-comment'); const isVisible = () => isSticky || store.state.discussion.stickyComment === null; this.$watch( () => store.state.discussion.currentDiscussionId, () => this.$nextTick(() => { if (isVisible() && store.state.discussion.newCommentFocus) { clEditor.focus(); } }), { immediate: true }, ); if (isSticky) { let scrollerMirrorElt; const getScrollerMirrorElt = () => { if (!scrollerMirrorElt) { scrollerMirrorElt = document.querySelector('.comment-list .comment--new .comment__text-inner'); } return scrollerMirrorElt || { scrollTop: 0 }; }; scrollerElt.scrollTop = getScrollerMirrorElt().scrollTop; scrollerElt.addEventListener('scroll', () => { getScrollerMirrorElt().scrollTop = scrollerElt.scrollTop; }); } else { // Maintain the state with the sticky comment this.$watch( () => isVisible(), (visible) => { clEditor.toggleEditable(visible); if (visible) { const text = store.state.discussion.newCommentText; clEditor.setContent(text); const selection = store.state.discussion.newCommentSelection; clEditor.selectionMgr.setSelectionStartEnd(selection.start, selection.end); if (store.state.discussion.newCommentFocus) { clEditor.focus(); } } }, { immediate: true }, ); this.$watch( () => store.state.discussion.newCommentText, newCommentText => clEditor.setContent(newCommentText), ); } }, }; </script>