diff --git a/src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue b/src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue index 90eb9e6f..2a1ce759 100644 --- a/src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue +++ b/src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue @@ -6,6 +6,7 @@ v-for="item in presetStyles" :key="item.label" :style="item.style" + @click="emitBatchRichTextCommand(item.cmd)" >{{item.label}} @@ -229,6 +230,12 @@ const presetStyles = [ fontSize: '30px', fontWeight: 700, }, + cmd: [ + { command: 'clear' }, + { command: 'fontsize', value: '48px' }, + { command: 'align', value: 'center' }, + { command: 'bold' }, + ], }, { label: '小标题', @@ -236,12 +243,22 @@ const presetStyles = [ fontSize: '24px', fontWeight: 700, }, + cmd: [ + { command: 'clear' }, + { command: 'fontsize', value: '36px' }, + { command: 'align', value: 'center' }, + { command: 'bold' }, + ], }, { label: '正文', style: { fontSize: '20px', }, + cmd: [ + { command: 'clear' }, + { command: 'fontsize', value: '20px' }, + ], }, { label: '注释', @@ -249,9 +266,19 @@ const presetStyles = [ fontSize: '16px', fontStyle: 'italic', }, + cmd: [ + { command: 'clear' }, + { command: 'fontsize', value: '16px' }, + { command: 'em' }, + ], }, ] +interface CommandPayload { + command: string; + value?: string; +} + export default defineComponent({ name: 'text-style-panel', components: { @@ -312,6 +339,10 @@ export default defineComponent({ emitter.emit(EmitterEvents.EXEC_TEXT_COMMAND, { command, value }) } + const emitBatchRichTextCommand = (payload: CommandPayload[]) => { + emitter.emit(EmitterEvents.EXEC_TEXT_COMMAND, payload) + } + const { addHistorySnapshot } = useHistorySnapshot() const updateLineHeight = (value: number) => { @@ -345,6 +376,7 @@ export default defineComponent({ updateWordSpace, updateFill, emitRichTextCommand, + emitBatchRichTextCommand, presetStyles, } }, diff --git a/src/views/components/element/TextElement/index.vue b/src/views/components/element/TextElement/index.vue index 4ed3895c..0ffc2189 100644 --- a/src/views/components/element/TextElement/index.vue +++ b/src/views/components/element/TextElement/index.vue @@ -42,18 +42,18 @@ import debounce from 'lodash/debounce' import { useStore } from 'vuex' import { MutationTypes, State } from '@/store' import { EditorView } from 'prosemirror-view' +import { toggleMark, wrapIn, selectAll } from 'prosemirror-commands' import { PPTTextElement } from '@/types/slides' import { ContextmenuItem } from '@/components/Contextmenu/types' import { initProsemirrorEditor } from '@/prosemirror/' import { getTextAttrs } from '@/prosemirror/utils' import emitter, { EmitterEvents } from '@/utils/emitter' import useElementShadow from '@/views/components/element/hooks/useElementShadow' +import { alignmentCommand } from '@/prosemirror/commands/setTextAlign' +import { toggleList } from '@/prosemirror/commands/toggleList' import useHistorySnapshot from '@/hooks/useHistorySnapshot' import ElementOutline from '@/views/components/element/ElementOutline.vue' -import { toggleMark, wrapIn } from 'prosemirror-commands' -import { alignmentCommand } from '@/prosemirror/commands/setTextAlign' -import { toggleList } from '@/prosemirror/commands/toggleList' interface CommandPayload { command: string; @@ -195,69 +195,91 @@ export default defineComponent({ const handleElementId = computed(() => store.state.handleElementId) - const execCommand = (payload: CommandPayload) => { + const execCommand = (payload: CommandPayload | CommandPayload[]) => { if(handleElementId.value !== props.elementInfo.id) return - if(payload.command === 'fontname' && payload.value) { - const mark = editorView.state.schema.marks.fontname.create({ fontname: payload.value }) - const { $from, $to } = editorView.state.selection - editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) - } - else if(payload.command === 'fontsize' && payload.value) { - const mark = editorView.state.schema.marks.fontsize.create({ fontsize: payload.value }) - const { $from, $to } = editorView.state.selection - editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) - } - else if(payload.command === 'color' && payload.value) { - const mark = editorView.state.schema.marks.forecolor.create({ color: payload.value }) - const { $from, $to } = editorView.state.selection - editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) - } - else if(payload.command === 'backcolor' && payload.value) { - const mark = editorView.state.schema.marks.backcolor.create({ backcolor: payload.value }) - const { $from, $to } = editorView.state.selection - editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) - } - else if(payload.command === 'bold') { - toggleMark(editorView.state.schema.marks.strong)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'em') { - toggleMark(editorView.state.schema.marks.em)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'underline') { - toggleMark(editorView.state.schema.marks.underline)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'strikethrough') { - toggleMark(editorView.state.schema.marks.strikethrough)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'subscript') { - toggleMark(editorView.state.schema.marks.subscript)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'superscript') { - toggleMark(editorView.state.schema.marks.superscript)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'blockquote') { - wrapIn(editorView.state.schema.nodes.blockquote)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'code') { - toggleMark(editorView.state.schema.marks.code)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'align' && payload.value) { - alignmentCommand(editorView, payload.value) - } - else if(payload.command === 'bulletList') { - const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes - toggleList(bulletList, listItem)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'orderedList') { - const { ordered_list: orderedList, list_item: listItem } = editorView.state.schema.nodes - toggleList(orderedList, listItem)(editorView.state, editorView.dispatch) - } - else if(payload.command === 'clear') { - if(editorView.state.selection.empty) return false - const { $from, $to } = editorView.state.selection - editorView.dispatch(editorView.state.tr.removeMark($from.pos, $to.pos)) + const commands = ('command' in payload) ? [payload] : payload + + for(const item of commands) { + if(item.command === 'fontname' && item.value) { + const mark = editorView.state.schema.marks.fontname.create({ fontname: item.value }) + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + const { $from, $to } = editorView.state.selection + editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) + } + else if(item.command === 'fontsize' && item.value) { + const mark = editorView.state.schema.marks.fontsize.create({ fontsize: item.value }) + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + const { $from, $to } = editorView.state.selection + editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) + } + else if(item.command === 'color' && item.value) { + const mark = editorView.state.schema.marks.forecolor.create({ color: item.value }) + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + const { $from, $to } = editorView.state.selection + editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) + } + else if(item.command === 'backcolor' && item.value) { + const mark = editorView.state.schema.marks.backcolor.create({ backcolor: item.value }) + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + const { $from, $to } = editorView.state.selection + editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark)) + } + else if(item.command === 'bold') { + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + toggleMark(editorView.state.schema.marks.strong)(editorView.state, editorView.dispatch) + } + else if(item.command === 'em') { + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + toggleMark(editorView.state.schema.marks.em)(editorView.state, editorView.dispatch) + } + else if(item.command === 'underline') { + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + toggleMark(editorView.state.schema.marks.underline)(editorView.state, editorView.dispatch) + } + else if(item.command === 'strikethrough') { + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + toggleMark(editorView.state.schema.marks.strikethrough)(editorView.state, editorView.dispatch) + } + else if(item.command === 'subscript') { + toggleMark(editorView.state.schema.marks.subscript)(editorView.state, editorView.dispatch) + } + else if(item.command === 'superscript') { + toggleMark(editorView.state.schema.marks.superscript)(editorView.state, editorView.dispatch) + } + else if(item.command === 'blockquote') { + wrapIn(editorView.state.schema.nodes.blockquote)(editorView.state, editorView.dispatch) + } + else if(item.command === 'code') { + toggleMark(editorView.state.schema.marks.code)(editorView.state, editorView.dispatch) + } + else if(item.command === 'align' && item.value) { + alignmentCommand(editorView, item.value) + } + else if(item.command === 'bulletList') { + const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes + toggleList(bulletList, listItem)(editorView.state, editorView.dispatch) + } + else if(item.command === 'orderedList') { + const { ordered_list: orderedList, list_item: listItem } = editorView.state.schema.nodes + toggleList(orderedList, listItem)(editorView.state, editorView.dispatch) + } + else if(item.command === 'clear') { + const { empty } = editorView.state.selection + if(empty) selectAll(editorView.state, editorView.dispatch) + const { $from, $to } = editorView.state.selection + editorView.dispatch(editorView.state.tr.removeMark($from.pos, $to.pos)) + } } + editorView.focus() handleInput() handleClick()