diff options
Diffstat (limited to 'src/client/views/nodes/formattedText/RichTextMenu.tsx')
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.tsx | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index a06fcec9a..7c7a76e1b 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faBold, faCaretDown, faChevronLeft, faEyeDropper, faHighlighter, faIndent, faItalic, faLink, faPaintRoller, faPalette, faStrikethrough, faSubscript, faSuperscript, faUnderline } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable } from "mobx"; +import { action, observable, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { lift, wrapIn } from "prosemirror-commands"; import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos } from "prosemirror-model"; @@ -23,6 +23,7 @@ import { updateBullets } from "./ProsemirrorExampleTransfer"; import "./RichTextMenu.scss"; import { schema } from "./schema_rts"; import { TraceMobx } from "../../../../fields/util"; +import { UndoManager } from "../../../util/UndoManager"; const { toggleMark } = require("prosemirror-commands"); library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faHighlighter, faLink, faPaintRoller); @@ -68,6 +69,8 @@ export default class RichTextMenu extends AntimodeMenu { @observable private currentLink: string | undefined = ""; @observable private showLinkDropdown: boolean = false; + _reaction: IReactionDisposer | undefined; + _delayHide = false; constructor(props: Readonly<{}>) { super(props); RichTextMenu.Instance = this; @@ -138,6 +141,16 @@ export default class RichTextMenu extends AntimodeMenu { ]; } + componentDidMount() { + this._reaction = reaction(() => SelectionManager.SelectedDocuments(), + () => this._delayHide && !(this._delayHide = false) && this.fadeOut(true)); + } + componentWillUnmount() { + this._reaction?.(); + } + + public delayHide = () => { this._delayHide = true; } + @action changeView(view: EditorView) { this.view = view; @@ -147,16 +160,6 @@ export default class RichTextMenu extends AntimodeMenu { this.updateFromDash(view, lastState, this.editorProps); } - public MakeLinkToSelection = (linkDocId: string, title: string, location: string, targetDocId: string): string => { - if (this.view) { - const link = this.view.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + linkDocId), title: title, location: location, linkId: linkDocId, targetId: targetDocId }); - this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link). - addMark(this.view.state.selection.from, this.view.state.selection.to, link)); - return this.view.state.selection.$from.nodeAfter?.text || ""; - } - return ""; - } - @action public async updateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) { if (!view) { @@ -310,8 +313,11 @@ export default class RichTextMenu extends AntimodeMenu { function onClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && command && command(self.view.state, self.view.dispatch, self.view); - self.view && onclick && onclick(self.view.state, self.view.dispatch, self.view); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => { + self.view && command && command(self.view.state, self.view.dispatch, self.view); + self.view && onclick && onclick(self.view.state, self.view.dispatch, self.view); + }, "rich text menu command"); self.setActiveMarkButtons(self.getActiveMarksOnSelection()); } @@ -338,9 +344,10 @@ export default class RichTextMenu extends AntimodeMenu { function onChange(e: React.ChangeEvent<HTMLSelectElement>) { e.stopPropagation(); e.preventDefault(); + self.TextView.endUndoTypingBatch(); options.forEach(({ label, mark, command }) => { if (e.target.value === label) { - self.view && mark && command(mark, self.view); + UndoManager.RunInBatch(() => self.view && mark && command(mark, self.view), "text mark dropdown"); } }); } @@ -361,9 +368,10 @@ export default class RichTextMenu extends AntimodeMenu { const self = this; function onChange(val: string) { + self.TextView.endUndoTypingBatch(); options.forEach(({ label, node, command }) => { if (val === label) { - self.view && node && command(node); + UndoManager.RunInBatch(() => self.view && node && command(node), "nodes dropdown"); } }); } @@ -461,7 +469,8 @@ export default class RichTextMenu extends AntimodeMenu { function onBrushClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.fillBrush(self.view.state, self.view.dispatch); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.view && self.fillBrush(self.view.state, self.view.dispatch), "rt brush"); } let label = "Stored marks: "; @@ -528,19 +537,24 @@ export default class RichTextMenu extends AntimodeMenu { @action toggleColorDropdown() { this.showColorDropdown = !this.showColorDropdown; } @action setActiveColor(color: string) { this.activeFontColor = color; } + get TextView() { return (this.view as any).TextView as FormattedTextBox } createColorButton() { const self = this; function onColorClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); + self.TextView.EditorView!.focus() } function changeColor(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); self.setActiveColor(color); - self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); + self.TextView.EditorView!.focus() } const button = @@ -585,13 +599,15 @@ export default class RichTextMenu extends AntimodeMenu { function onHighlightClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch), "rt highligher"); } function changeHighlight(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); self.setActiveHighlight(color); - self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch), "rt highlighter"); } const button = @@ -631,7 +647,8 @@ export default class RichTextMenu extends AntimodeMenu { const self = this; function onLinkChange(e: React.ChangeEvent<HTMLInputElement>) { - self.setCurrentLink(e.target.value); + self.TextView.endUndoTypingBatch(); + UndoManager.RunInBatch(() => self.setCurrentLink(e.target.value), "link change"); } const link = this.currentLink ? this.currentLink : ""; @@ -766,7 +783,7 @@ export default class RichTextMenu extends AntimodeMenu { return ref_node; } - @action onPointerEnter(e: React.PointerEvent) { RichTextMenu.Instance.overMenu = true; } + @action onPointerEnter(e: React.PointerEvent) { RichTextMenu.Instance.overMenu = false; } @action onPointerLeave(e: React.PointerEvent) { RichTextMenu.Instance.overMenu = false; } @action |