diff options
author | Lionel Han <47760119+IGoByJoe@users.noreply.github.com> | 2020-09-04 19:02:50 -0700 |
---|---|---|
committer | Lionel Han <47760119+IGoByJoe@users.noreply.github.com> | 2020-09-04 19:02:50 -0700 |
commit | e11c71a94016e3fe2529d0523fd62401baf90093 (patch) | |
tree | 3364d6a9ab147247b90ce9e390f4aef945afd0c5 /src/client/views/nodes/formattedText/RichTextMenu.tsx | |
parent | 4767a10336309c679da60fd244548414c055ac50 (diff) | |
parent | 2ef7900d1210bc0e5261e1d1f8fd1ba5f3a0ee4c (diff) |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into new_audio
Diffstat (limited to 'src/client/views/nodes/formattedText/RichTextMenu.tsx')
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.tsx | 107 |
1 files changed, 62 insertions, 45 deletions
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index b683fb25d..307238ea1 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -1,8 +1,8 @@ import React = require("react"); -import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faBold, faCaretDown, faChevronLeft, faEyeDropper, faHighlighter, faOutdent, faIndent, faHandPointLeft, faHandPointRight, faItalic, faLink, faPaintRoller, faPalette, faStrikethrough, faSubscript, faSuperscript, faUnderline } from "@fortawesome/free-solid-svg-icons"; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, IReactionDisposer, reaction } from "mobx"; +import { Tooltip } from "@material-ui/core"; +import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { lift, wrapIn } from "prosemirror-commands"; import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos } from "prosemirror-model"; @@ -11,31 +11,28 @@ import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { Doc } from "../../../../fields/Doc"; import { DarkPastelSchemaPalette, PastelSchemaPalette } from '../../../../fields/SchemaHeaderField'; -import { Cast, StrCast, BoolCast, NumCast } from "../../../../fields/Types"; +import { Cast, StrCast } from "../../../../fields/Types"; +import { TraceMobx } from "../../../../fields/util"; import { unimplementedFunction, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { LinkManager } from "../../../util/LinkManager"; import { SelectionManager } from "../../../util/SelectionManager"; -import AntimodeMenu from "../../AntimodeMenu"; +import { undoBatch, UndoManager } from "../../../util/UndoManager"; +import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; import { FieldViewProps } from "../FieldView"; import { FormattedTextBox, FormattedTextBoxProps } from "./FormattedTextBox"; import { updateBullets } from "./ProsemirrorExampleTransfer"; import "./RichTextMenu.scss"; import { schema } from "./schema_rts"; -import { TraceMobx } from "../../../../fields/util"; -import { UndoManager, undoBatch } from "../../../util/UndoManager"; -import { Tooltip } from "@material-ui/core"; const { toggleMark } = require("prosemirror-commands"); -library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faOutdent, faIndent, faHandPointLeft, faHandPointRight, faEyeDropper, faCaretDown, faPalette, faHighlighter, faLink, faPaintRoller); - @observer -export default class RichTextMenu extends AntimodeMenu { +export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { static Instance: RichTextMenu; public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable - private view?: EditorView; + public view?: EditorView; public editorProps: FieldViewProps & FormattedTextBoxProps | undefined; public _brushMap: Map<string, Set<Mark>> = new Map(); @@ -78,7 +75,7 @@ export default class RichTextMenu extends AntimodeMenu { RichTextMenu.Instance = this; this._canFade = false; //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]); - this.Pinned = true; + runInAction(() => this.Pinned = true); this.fontSizeOptions = [ { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize }, @@ -156,22 +153,8 @@ export default class RichTextMenu extends AntimodeMenu { public delayHide = () => this._delayHide = true; @action - changeView(view: EditorView) { - if ((view as any)?.TextView?.props.isSelected(true)) { - this.view = view; - } - } - - update(view: EditorView, lastState: EditorState | undefined) { - RichTextMenu.Instance.updateFromDash(view, lastState, this.editorProps); - } - - @action - public async updateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) { - RichTextMenu.Instance.finalUpdateFromDash(view, lastState, props); - } - public async finalUpdateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) { - if (!view || !(view as any).TextView?.props.isSelected(true)) { + public updateMenu(view: EditorView, lastState: EditorState | undefined, props: any) { + if (!view || !(view as any).TextView?.props.isSelected(true) || !view.hasFocus()) { return; } this.view = view; @@ -199,8 +182,7 @@ export default class RichTextMenu extends AntimodeMenu { this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length === 1 ? String(activeHighlights[0]) : "..."; // update link in current selection - const targetTitle = await this.getTextLinkTargetTitle(); - this.setCurrentLink(targetTitle); + this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle)); } setMark = (mark: Mark, state: EditorState<any>, dispatch: any, dontToggle: boolean = false) => { @@ -268,7 +250,9 @@ export default class RichTextMenu extends AntimodeMenu { const pos = this.view.state.selection.$from; const ref_node = this.reference_node(pos); if (ref_node && ref_node !== this.view.state.doc && ref_node.isText) { - ref_node.marks.forEach(m => { + const marks = Array.from(ref_node.marks); + marks.push(...(this.view.state.storedMarks as any)); + marks.forEach(m => { m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family); m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color); m.type === state.schema.marks.pFontSize && activeSizes.push(String(m.attrs.fontSize) + "pt"); @@ -443,14 +427,20 @@ export default class RichTextMenu extends AntimodeMenu { if ((this.view?.state.selection.$from.pos || 0) < 2) { this.TextView.layoutDoc._fontSize = mark.attrs.fontSize; } - this.setMark(view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }), view.state, view.dispatch, true); + const fmark = view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }); + this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true); + view.focus(); + this.updateMenu(view, undefined, this.props); } changeFontFamily = (mark: Mark, view: EditorView) => { if ((this.view?.state.selection.$from.pos || 0) < 2) { this.TextView.layoutDoc._fontFamily = mark.attrs.family; } - this.setMark(view.state.schema.marks.pFontFamily.create({ family: mark.attrs.family }), view.state, view.dispatch, true); + const fmark = view.state.schema.marks.pFontFamily.create({ family: mark.attrs.family }); + this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true); + view.focus(); + this.updateMenu(view, undefined, this.props); } // TODO: remove doesn't work @@ -486,6 +476,8 @@ export default class RichTextMenu extends AntimodeMenu { this.view.dispatch(tx3); } } + this.view.focus(); + this.updateMenu(this.view, undefined, this.props); } insertSummarizer(state: EditorState<any>, dispatch: any) { @@ -690,16 +682,22 @@ export default class RichTextMenu extends AntimodeMenu { e.preventDefault(); e.stopPropagation(); self.TextView.endUndoTypingBatch(); - UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); - self.TextView.EditorView!.focus(); + if (self.view) { + UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); + self.view.focus(); + self.updateMenu(self.view, undefined, self.props); + } } function changeColor(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); self.setActiveColor(color); self.TextView.endUndoTypingBatch(); - UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); - self.TextView.EditorView!.focus(); + if (self.view) { + UndoManager.RunInBatch(() => self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch), "rt menu color"); + self.view.focus(); + self.updateMenu(self.view, undefined, self.props); + } } // onPointerDown={onColorClick} @@ -812,7 +810,7 @@ export default class RichTextMenu extends AntimodeMenu { <div className="dropdown link-menu"> <p>Linked to:</p> <input value={link} placeholder="Enter URL" onChange={onLinkChange} /> - <button className="make-button" onPointerDown={e => this.makeLinkToURL(link, "onRight")}>Apply hyperlink</button> + <button className="make-button" onPointerDown={e => this.makeLinkToURL(link, "add:right")}>Apply hyperlink</button> <div className="divider"></div> <button className="remove-button" onPointerDown={e => this.deleteLink()}>Remove link</button> </div>; @@ -859,7 +857,7 @@ export default class RichTextMenu extends AntimodeMenu { // TODO: should check for valid URL @undoBatch makeLinkToURL = (target: string, lcoation: string) => { - ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRight", "", target); + ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRadd:rightight", "", target); } @undoBatch @@ -988,7 +986,7 @@ export default class RichTextMenu extends AntimodeMenu { {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => this.activeFontSize = val)), this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => this.activeFontFamily = val)), <div className="richTextMenu-divider" key="divider 4" />, - this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", action((val: string) => this.activeListType = val)), + this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", () => ({})), this.createButton("sort-amount-down", "Summarize", undefined, this.insertSummarizer), this.createButton("quote-left", "Blockquote", undefined, this.insertBlockquote), this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule), @@ -1020,6 +1018,7 @@ interface ButtonDropdownProps { dropdownContent: JSX.Element; openDropdownOnButton?: boolean; link?: boolean; + pdf?: boolean; } @observer @@ -1059,15 +1058,33 @@ export class ButtonDropdown extends React.Component<ButtonDropdownProps> { }, 0); } + render() { return ( <div className="button-dropdown-wrapper" ref={node => this.ref = node}> - <div className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.onDropdownClick}> - {this.props.button} - <div style={{ marginTop: "-8.5" }}><FontAwesomeIcon icon="caret-down" size="sm" /></div> - </div> + {!this.props.pdf ? + <div className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.onDropdownClick}> + {this.props.button} + <div style={{ marginTop: "-8.5" }}><FontAwesomeIcon icon="caret-down" size="sm" /></div> + </div> + : + <> + {this.props.button} + <button className="dropdown-button antimodeMenu-button" key="antimodebutton" onPointerDown={this.onDropdownClick}> + <FontAwesomeIcon icon="caret-down" size="sm" /> + </button> + </>} {this.showDropdown ? this.props.dropdownContent : (null)} </div> ); } +} + + +interface RichTextMenuPluginProps { + editorProps: any; +} +export class RichTextMenuPlugin extends React.Component<RichTextMenuPluginProps> { + render() { return null; } + update(view: EditorView, lastState: EditorState | undefined) { RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps); } }
\ No newline at end of file |