From 3b08b8c340bf889c99f7b2fa76cda0f8b2d4b0a1 Mon Sep 17 00:00:00 2001 From: Fawn Date: Thu, 9 Jan 2020 15:03:54 -0500 Subject: refactored dropdown buttons into a buttondropdown component for richtextmenu --- src/client/util/RichTextMenu.tsx | 382 +++++++++++++++------------- src/client/views/nodes/FormattedTextBox.tsx | 1 - 2 files changed, 206 insertions(+), 177 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx index ca6b90e36..2d4f0fc1b 100644 --- a/src/client/util/RichTextMenu.tsx +++ b/src/client/util/RichTextMenu.tsx @@ -34,6 +34,12 @@ export default class RichTextMenu extends AntimodeMenu { private view?: EditorView; private editorProps: FieldViewProps & FormattedTextBoxProps | undefined; + private fontSizeOptions: { mark: Mark | null, title: string, label: string, command: any, hidden?: boolean }[]; + private fontFamilyOptions: { mark: Mark | null, title: string, label: string, command: any, hidden?: boolean }[]; + private listTypeOptions: { node: NodeType | any | null, title: string, label: string, command: any }[]; + private fontColors: (string | undefined)[]; + private highlightColors: (string | undefined)[]; + @observable private activeFontSize: string = ""; @observable private activeFontFamily: string = ""; @observable private activeListType: string = ""; @@ -55,6 +61,69 @@ export default class RichTextMenu extends AntimodeMenu { super(props); RichTextMenu.Instance = this; this._canFade = false; + + this.fontSizeOptions = [ + { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 8 }), title: "Set font size", label: "8pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 9 }), title: "Set font size", label: "8pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 10 }), title: "Set font size", label: "10pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 12 }), title: "Set font size", label: "12pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 14 }), title: "Set font size", label: "14pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 16 }), title: "Set font size", label: "16pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 18 }), title: "Set font size", label: "18pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 20 }), title: "Set font size", label: "20pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 24 }), title: "Set font size", label: "24pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 32 }), title: "Set font size", label: "32pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 48 }), title: "Set font size", label: "48pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 72 }), title: "Set font size", label: "72pt", command: this.changeFontSize }, + { mark: null, title: "", label: "various", command: unimplementedFunction, hidden: true }, + { mark: null, title: "", label: "13pt", command: unimplementedFunction, hidden: true }, // this is here because the default size is 13, but there is no actual 13pt option + ]; + + this.fontFamilyOptions = [ + { mark: schema.marks.pFontFamily.create({ family: "Times New Roman" }), title: "Set font family", label: "Times New Roman", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Arial" }), title: "Set font family", label: "Arial", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Georgia" }), title: "Set font family", label: "Georgia", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Comic Sans MS" }), title: "Set font family", label: "Comic Sans MS", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Tahoma" }), title: "Set font family", label: "Tahoma", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Impact" }), title: "Set font family", label: "Impact", command: this.changeFontFamily }, + { mark: schema.marks.pFontFamily.create({ family: "Crimson Text" }), title: "Set font family", label: "Crimson Text", command: this.changeFontFamily }, + { mark: null, title: "", label: "various", command: unimplementedFunction, hidden: true }, + // { mark: null, title: "", label: "default", command: unimplementedFunction, hidden: true }, + ]; + + this.listTypeOptions = [ + { node: schema.nodes.ordered_list.create({ mapStyle: "bullet" }), title: "Set list type", label: ":", command: this.changeListType }, + { node: schema.nodes.ordered_list.create({ mapStyle: "decimal" }), title: "Set list type", label: "1.1", command: this.changeListType }, + { node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "1.A", command: this.changeListType }, + { node: undefined, title: "Set list type", label: "Remove", command: this.changeListType }, + ]; + + this.fontColors = [ + DarkPastelSchemaPalette.get("pink2"), + DarkPastelSchemaPalette.get("purple4"), + DarkPastelSchemaPalette.get("bluegreen1"), + DarkPastelSchemaPalette.get("yellow4"), + DarkPastelSchemaPalette.get("red2"), + DarkPastelSchemaPalette.get("bluegreen7"), + DarkPastelSchemaPalette.get("bluegreen5"), + DarkPastelSchemaPalette.get("orange1"), + "#757472", + "#000" + ]; + + this.highlightColors = [ + PastelSchemaPalette.get("pink2"), + PastelSchemaPalette.get("purple4"), + PastelSchemaPalette.get("bluegreen1"), + PastelSchemaPalette.get("yellow4"), + PastelSchemaPalette.get("red2"), + PastelSchemaPalette.get("bluegreen7"), + PastelSchemaPalette.get("bluegreen5"), + PastelSchemaPalette.get("orange1"), + "white", + "transparent" + ]; } @action @@ -74,27 +143,23 @@ export default class RichTextMenu extends AntimodeMenu { } this.view = view; const state = view.state; - // DocumentDecorations.Instance.showTextBar(); props && (this.editorProps = props); + // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && lastState.selection.eq(state.selection)) return; - // this.reset_mark_doms(); // update active font family and size const active = this.getActiveFontStylesOnSelection(); const activeFamilies = active && active.get("families"); const activeSizes = active && active.get("sizes"); - console.log("update from dash, activefontsize", this.activeFontSize, activeSizes, activeSizes && activeSizes.length, activeSizes && String(activeSizes[0])); this.activeFontFamily = !activeFamilies || activeFamilies.length === 0 ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; this.activeFontSize = !activeSizes || activeSizes.length === 0 ? "13pt" : activeSizes.length === 1 ? String(activeSizes[0]) + "pt" : "various"; // update link in current selection const targetTitle = await this.getTextLinkTargetTitle(); this.setCurrentLink(targetTitle); - - // this.update_mark_doms(); } setMark = (mark: Mark, state: EditorState, dispatch: any) => { @@ -134,7 +199,7 @@ export default class RichTextMenu extends AntimodeMenu { }); } - let styles = new Map(); + const styles = new Map(); styles.set("families", activeFamilies); styles.set("sizes", activeSizes); return styles; @@ -183,7 +248,6 @@ export default class RichTextMenu extends AntimodeMenu { function onChange(e: React.ChangeEvent) { e.stopPropagation(); e.preventDefault(); - console.log("on change marks"); options.forEach(({ label, mark, command }) => { if (e.target.value === label) { self.view && mark && command(mark, self.view); @@ -230,7 +294,6 @@ export default class RichTextMenu extends AntimodeMenu { changeFontFamily = (mark: Mark, view: EditorView) => { const fontName = mark.attrs.family; - // if (fontName) { this.updateFontStyleDropdown(fontName); } if (this.editorProps) { const ruleProvider = this.editorProps.ruleProvider; const heading = NumCast(this.editorProps.Document.heading); @@ -288,12 +351,6 @@ export default class RichTextMenu extends AntimodeMenu { self.view && self.view.focus(); self.view && self.fillBrush(self.view.state, self.view.dispatch); } - function onDropdownClick(e: React.PointerEvent) { - e.preventDefault(); - e.stopPropagation(); - self.view && self.view.focus(); - self.toggleBrushDropdown(); - } let label = "Stored marks: "; if (this.brushMarks && this.brushMarks.size > 0) { @@ -307,20 +364,20 @@ export default class RichTextMenu extends AntimodeMenu { label = "No marks are currently stored"; } + const button = + ; + + const dropdownContent = +
+

{label}

+ + {/* */} +
; + return ( -
- - - {this.showBrushDropdown ? - (
-

{label}

- - {/* */} -
) - : <>} -
+ ); } @@ -340,7 +397,6 @@ export default class RichTextMenu extends AntimodeMenu { this.brushMarks = selected_marks; this.brushIsEmpty = !this.brushIsEmpty; } - // } } else { const { from, to, $from } = this.view.state.selection; @@ -369,12 +425,6 @@ export default class RichTextMenu extends AntimodeMenu { self.view && self.view.focus(); self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); } - function onDropdownClick(e: React.PointerEvent) { - e.preventDefault(); - e.stopPropagation(); - self.view && self.view.focus(); - self.toggleColorDropdown(); - } function changeColor(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); @@ -383,41 +433,28 @@ export default class RichTextMenu extends AntimodeMenu { self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); } - const colors = [ - DarkPastelSchemaPalette.get("pink2"), - DarkPastelSchemaPalette.get("purple4"), - DarkPastelSchemaPalette.get("bluegreen1"), - DarkPastelSchemaPalette.get("yellow4"), - DarkPastelSchemaPalette.get("red2"), - DarkPastelSchemaPalette.get("bluegreen7"), - DarkPastelSchemaPalette.get("bluegreen5"), - DarkPastelSchemaPalette.get("orange1"), - "#757472", - "#000" - ]; + const button = + ; + + const dropdownContent = +
+

Change font color:

+
+ {this.fontColors.map(color => { + if (color) { + return this.activeFontColor === color ? + : + ; + } + })} +
+
; return ( -
- - - {this.showColorDropdown ? - (
-

Change font color:

-
- {colors.map(color => { - if (color) { - return this.activeFontColor === color ? - : - ; - } - })} -
-
) - : <>} -
+ ); } @@ -441,12 +478,6 @@ export default class RichTextMenu extends AntimodeMenu { self.view && self.view.focus(); self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); } - function onDropdownClick(e: React.PointerEvent) { - e.preventDefault(); - e.stopPropagation(); - self.view && self.view.focus(); - self.toggleHighlightDropdown(); - } function changeHighlight(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); @@ -455,41 +486,28 @@ export default class RichTextMenu extends AntimodeMenu { self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); } - const colors = [ - PastelSchemaPalette.get("pink2"), - PastelSchemaPalette.get("purple4"), - PastelSchemaPalette.get("bluegreen1"), - PastelSchemaPalette.get("yellow4"), - PastelSchemaPalette.get("red2"), - PastelSchemaPalette.get("bluegreen7"), - PastelSchemaPalette.get("bluegreen5"), - PastelSchemaPalette.get("orange1"), - "white", - "transparent" - ]; + const button = + ; + + const dropdownContent = +
+

Change highlight color:

+
+ {this.highlightColors.map(color => { + if (color) { + return this.activeHighlightColor === color ? + : + ; + } + })} +
+
; return ( -
- - - {this.showHighlightDropdown ? - (
-

Change highlight color:

-
- {colors.map(color => { - if (color) { - return this.activeHighlightColor === color ? - : - ; - } - })} -
-
) - : <>} -
+ ); } @@ -503,32 +521,26 @@ export default class RichTextMenu extends AntimodeMenu { createLinkButton() { const self = this; - function onDropdownClick(e: React.PointerEvent) { - e.preventDefault(); - e.stopPropagation(); - self.view && self.view.focus(); - self.toggleLinkDropdown(); - } + function onLinkChange(e: React.ChangeEvent) { self.setCurrentLink(e.target.value); } const link = this.currentLink ? this.currentLink : ""; + const button = ; + + const dropdownContent = +
+

Linked to:

+ + +
+ +
; + return ( -
- - - {this.showLinkDropdown ? - (
-

Linked to:

- - -
- -
) - : <>} -
+ ); } @@ -598,7 +610,7 @@ export default class RichTextMenu extends AntimodeMenu { } } else { if (node) { - let extension = this.linkExtend(this.view!.state.selection.$anchor, href); + const extension = this.linkExtend(this.view!.state.selection.$anchor, href); this.view!.dispatch(this.view!.state.tr.removeMark(extension.from, extension.to, this.view!.state.schema.marks.link)); } } @@ -617,7 +629,7 @@ export default class RichTextMenu extends AntimodeMenu { let startPos = $start.start(); let endPos = startPos; for (let i = 0; i < endIndex; i++) { - let size = $start.parent.child(i).nodeSize; + const size = $start.parent.child(i).nodeSize; if (i < startIndex) startPos += size; endPos += size; } @@ -665,43 +677,6 @@ export default class RichTextMenu extends AntimodeMenu { render() { - const fontSizeOptions = [ - { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 8 }), title: "Set font size", label: "8pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 9 }), title: "Set font size", label: "8pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 10 }), title: "Set font size", label: "10pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 12 }), title: "Set font size", label: "12pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 14 }), title: "Set font size", label: "14pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 16 }), title: "Set font size", label: "16pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 18 }), title: "Set font size", label: "18pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 20 }), title: "Set font size", label: "20pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 24 }), title: "Set font size", label: "24pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 32 }), title: "Set font size", label: "32pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 48 }), title: "Set font size", label: "48pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 72 }), title: "Set font size", label: "72pt", command: this.changeFontSize }, - { mark: null, title: "", label: "various", command: unimplementedFunction, hidden: true }, - { mark: null, title: "", label: "13pt", command: unimplementedFunction, hidden: true }, // this is here because the default size is 13, but there is no actual 13pt option - ]; - - const fontFamilyOptions = [ - { mark: schema.marks.pFontFamily.create({ family: "Times New Roman" }), title: "Set font family", label: "Times New Roman", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Arial" }), title: "Set font family", label: "Arial", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Georgia" }), title: "Set font family", label: "Georgia", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Comic Sans MS" }), title: "Set font family", label: "Comic Sans MS", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Tahoma" }), title: "Set font family", label: "Tahoma", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Impact" }), title: "Set font family", label: "Impact", command: this.changeFontFamily }, - { mark: schema.marks.pFontFamily.create({ family: "Crimson Text" }), title: "Set font family", label: "Crimson Text", command: this.changeFontFamily }, - { mark: null, title: "", label: "various", command: unimplementedFunction, hidden: true }, - // { mark: null, title: "", label: "default", command: unimplementedFunction, hidden: true }, - ]; - - const listTypeOptions = [ - { node: schema.nodes.ordered_list.create({ mapStyle: "bullet" }), title: "Set list type", label: ":", command: this.changeListType }, - { node: schema.nodes.ordered_list.create({ mapStyle: "decimal" }), title: "Set list type", label: "1.1", command: this.changeListType }, - { node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "1.A", command: this.changeListType }, - { node: undefined, title: "Set list type", label: "Remove", command: this.changeListType }, - ]; - const row1 =
{[ this.createButton("bold", "Bold", toggleMark(schema.marks.strong)), this.createButton("italic", "Italic", toggleMark(schema.marks.em)), @@ -714,30 +689,85 @@ export default class RichTextMenu extends AntimodeMenu { this.createLinkButton(), this.createBrushButton(), this.createButton("indent", "Summarize", undefined, this.insertSummarizer), - ]}
+ ]}; const row2 =
-
{[ - this.createMarksDropdown(this.activeFontSize, fontSizeOptions), - this.createMarksDropdown(this.activeFontFamily, fontFamilyOptions), - this.createNodesDropdown(this.activeListType, listTypeOptions), - ]}
+
+ {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions), + this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions), + this.createNodesDropdown(this.activeListType, this.listTypeOptions)]} +
{this.getDragger()}
-
- - const buttons = [ - row1, row2 - ]; + ; return (
- {this.getElementWithRows(buttons, 2, false)} + {this.getElementWithRows([row1, row2], 2, false)}
); } +} + +interface ButtonDropdownProps { + // Document: Doc; + // remove: (self: ImportMetadataEntry) => void; + // next: () => void; + view?: EditorView; + button: JSX.Element; + dropdownContent: JSX.Element; + openDropdownOnButton?: boolean; +} + +@observer +class ButtonDropdown extends React.Component { + + @observable private showDropdown: boolean = false; + private ref: HTMLDivElement | null = null; + + componentDidMount() { + document.addEventListener("pointerdown", this.onBlur); + } + + componentWillUnmount() { + document.removeEventListener("pointerdown", this.onBlur); + } + + @action + setShowDropdown(show: boolean) { + this.showDropdown = show; + } + @action + toggleDropdown() { + this.showDropdown = !this.showDropdown; + } + + onDropdownClick = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.props.view && this.props.view.focus(); + this.toggleDropdown(); + } + + onBlur = (e: PointerEvent) => { + setTimeout(() => { + if (this.ref !== null && !this.ref.contains(e.target as Node)) { + this.setShowDropdown(false); + } + }, 0); + } + + render() { + return ( +
this.ref = node}> + {this.props.openDropdownOnButton ?
{this.props.button}
: this.props.button} + + {this.showDropdown ? this.props.dropdownContent : <>} +
+ ) + } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 027bd492c..df055a2ab 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1057,7 +1057,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & }); } onBlur = (e: any) => { - console.log("formated blur"); //DictationManager.Controls.stop(false); if (this._undoTyping) { this._undoTyping.end(); -- cgit v1.2.3-70-g09d2