From 15514b0f3d685764d1bd7ebeac9cdee1f778e184 Mon Sep 17 00:00:00 2001
From: laurawilsonri <laura_wilson@brown.edu>
Date: Thu, 11 Apr 2019 12:06:46 -0400
Subject: font style and size dropdowns work

---
 src/client/util/TooltipTextMenu.tsx | 173 ++++++++++++++++++++++++++----------
 1 file changed, 124 insertions(+), 49 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 82e9d1bac..777abe030 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -1,12 +1,12 @@
 import { action, IReactionDisposer, reaction } from "mobx";
-import { Dropdown, DropdownSubmenu, MenuItem } from "prosemirror-menu";
+import { Dropdown, DropdownSubmenu, MenuItem, MenuItemSpec, renderGrouped, icons, } from "prosemirror-menu"; //no import css
 import { baseKeymap, lift } from "prosemirror-commands";
 import { history, redo, undo } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { EditorState, Transaction, NodeSelection } from "prosemirror-state";
+import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { schema } from "./RichTextSchema";
-import { Schema, NodeType } from "prosemirror-model";
+import { Schema, NodeType, MarkType } from "prosemirror-model";
 import React = require("react");
 import "./TooltipTextMenu.scss";
 const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands");
@@ -24,8 +24,12 @@ export class TooltipTextMenu {
 
     private tooltip: HTMLElement;
     private num_icons = 0;
+    private view: EditorView;
+    private fontStyles: MarkType[];
+    private fontSizes: MarkType[];
 
     constructor(view: EditorView) {
+        this.view = view;
         this.tooltip = document.createElement("div");
         this.tooltip.className = "tooltipMenu";
 
@@ -34,7 +38,6 @@ export class TooltipTextMenu {
 
         //add additional icons
         library.add(faListUl);
-
         //add the buttons to the tooltip
         let items = [
             { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") },
@@ -44,44 +47,142 @@ export class TooltipTextMenu {
             { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") },
             { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") },
             { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") },
-            { command: toggleMark(schema.marks.timesNewRoman), dom: this.icon("x", "TNR") },
             { command: lift, dom: this.icon("<", "lift") },
         ]
         //add menu items
         items.forEach(({ dom, command }) => {
             this.tooltip.appendChild(dom);
-        });
 
-        //add dropdowns
-
-        //pointer down handler to activate button effects
-        this.tooltip.addEventListener("pointerdown", e => {
-            e.preventDefault();
-            view.focus();
-            //update view of icons
-            this.num_icons = 0;
-            items.forEach(({ command, dom }) => {
-                if (e.srcElement && dom.contains(e.srcElement as Node)) {
-                    //let active = command(view.state, view.dispatch, view);
-                    let active = command(view.state, view.dispatch, view);
-                    //uncomment this if we want the bullet button to disappear if current selection is bulleted
-                    //dom.style.display = active ? "" : "none";
-                }
+            //pointer down handler to activate button effects
+            dom.addEventListener("pointerdown", e => {
+                e.preventDefault();
+                view.focus();
+                command(view.state, view.dispatch, view);
             })
-        })
+
+        });
+
+        //dropdowns
+        //list of font btns to add
+        this.fontStyles = [
+            schema.marks.timesNewRoman,
+            schema.marks.arial,
+            schema.marks.georgia,
+            schema.marks.comicSans,
+            schema.marks.tahoma,
+            schema.marks.impact,
+        ]
+        this.fontSizes = [
+            schema.marks.p10,
+            schema.marks.p12,
+            schema.marks.p16,
+            schema.marks.p24,
+            schema.marks.p32,
+            schema.marks.p48,
+            schema.marks.p72,
+        ]
+        this.addFontDropdowns();
 
         this.update(view, undefined);
     }
 
+    //adds font size and font style dropdowns
+    addFontDropdowns() {
+        //filtering function - might be unecessary
+        let cut = (arr: MenuItem[]) => arr.filter(x => x);
+        let fontBtns = [
+            this.dropdownBtn("Times New Roman", "font-family: Times New Roman, Times, serif; width: 120px;", schema.marks.timesNewRoman, this.view, this.changeToMarkInGroup, this.fontStyles),
+            this.dropdownBtn("Arial", "font-family: Arial, Helvetica, sans-serif; width: 120px;", schema.marks.arial, this.view, this.changeToMarkInGroup, this.fontStyles),
+            this.dropdownBtn("Georgia", "font-family: Georgia, serif; width: 120px; width: 120px;", schema.marks.georgia, this.view, this.changeToMarkInGroup, this.fontStyles),
+            this.dropdownBtn("ComicSans", "font-family: Comic Sans MS, cursive, sans-serif; width: 120px;", schema.marks.comicSans, this.view, this.changeToMarkInGroup, this.fontStyles),
+            this.dropdownBtn("Tahoma", "font-family: Tahoma, Geneva, sans-serif; width: 120px;", schema.marks.tahoma, this.view, this.changeToMarkInGroup, this.fontStyles),
+            this.dropdownBtn("Impact", "font-family: Impact, Charcoal, sans-serif; width: 120px;", schema.marks.impact, this.view, this.changeToMarkInGroup, this.fontStyles),
+        ]
+
+        let fontSizeBtns = [
+            this.dropdownBtn("10", "width: 50px;", schema.marks.p10, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("12", "width: 50px;", schema.marks.p12, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("16", "width: 50px;", schema.marks.p16, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("24", "width: 50px;", schema.marks.p24, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("32", "width: 50px;", schema.marks.p32, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("48", "width: 50px;", schema.marks.p48, this.view, this.changeToMarkInGroup, this.fontSizes),
+            this.dropdownBtn("72", "width: 50px;", schema.marks.p72, this.view, this.changeToMarkInGroup, this.fontSizes),
+        ]
+
+        //dropdown to hold font btns
+        let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem;
+        let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white;" }) as MenuItem;
+        this.tooltip.appendChild(dd_fontStyle.render(this.view).dom);
+        this.tooltip.appendChild(dd_fontSize.render(this.view).dom);
+    }
+
+    //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text
+    changeToMarkInGroup(markType: MarkType, view: EditorView, fontMarks: MarkType[]) {
+        let { empty, $cursor, ranges } = view.state.selection as TextSelection;
+        let state = view.state;
+        let dispatch = view.dispatch;
+
+        //remove all other active font marks
+        fontMarks.forEach((type) => {
+            if (dispatch) {
+                if ($cursor) {
+                    if (type.isInSet(state.storedMarks || $cursor.marks())) {
+                        dispatch(state.tr.removeStoredMark(type));
+                    }
+                } else {
+                    let has = false, tr = state.tr
+                    for (let i = 0; !has && i < ranges.length; i++) {
+                        let { $from, $to } = ranges[i]
+                        has = state.doc.rangeHasMark($from.pos, $to.pos, type)
+                    }
+                    for (let i = 0; i < ranges.length; i++) {
+                        let { $from, $to } = ranges[i]
+                        if (has) {
+                            toggleMark(type)(view.state, view.dispatch, view);
+                        }
+                    }
+                }
+            }
+        }); //actually apply font
+        return toggleMark(markType)(view.state, view.dispatch, view);
+    }
+
+    //makes a button for the drop down
+    //css is the style you want applied to the button
+    dropdownBtn(label: string, css: string, markType: MarkType, view: EditorView, changeToMarkInGroup: (markType: MarkType<any>, view: EditorView, groupMarks: MarkType[]) => any, groupMarks: MarkType[]) {
+        return new MenuItem({
+            title: "",
+            label: label,
+            execEvent: "",
+            class: "menuicon",
+            css: css,
+            enable(state) { return true; },
+            run() {
+                changeToMarkInGroup(markType, view, groupMarks);
+            }
+        });
+    }
     // Helper function to create menu icons
     icon(text: string, name: string) {
         let span = document.createElement("span");
         span.className = "menuicon " + name;
         span.title = name;
         span.textContent = text;
+        span.style.color = "white";
         return span;
     }
 
+    //method for checking whether node can be inserted
+    canInsert(state: EditorState, nodeType: NodeType<Schema<string, string>>) {
+        let $from = state.selection.$from
+        for (let d = $from.depth; d >= 0; d--) {
+            let index = $from.index(d)
+            if ($from.node(d).canReplaceWith(index, index, nodeType)) return true
+        }
+        return false
+    }
+
+
     //adapted this method - use it to check if block has a tag (ie bulleting)
     blockActive(type: NodeType<Schema<string, string>>, state: EditorState) {
         let attrs = {};
@@ -100,30 +201,6 @@ export class TooltipTextMenu {
         }
     }
 
-    //this doesn't currently work but could be used to use icons for buttons
-    unorderedListIcon(): HTMLSpanElement {
-        let span = document.createElement("span");
-        //let icon = document.createElement("FontAwesomeIcon");
-        //icon.className = "menuicon";
-        //icon.style.color = "white";
-        //span.appendChild(<i style={{ color: "white" }} icon="list-ul" size="lg" />);
-        let i = document.createElement("i");
-        i.className = "fa falist-ul";
-        span.appendChild(i);
-        //span.appendChild(icon);
-        //return liftItem.spec.icon.sty
-
-        //let sym = document.createElementNS(SVG, "symbol")
-        // sym.id = name
-        //sym.style.color = "white";
-        //width then height
-        //sym.setAttribute("viewBox", "0 0 " + 1024 + " " + 1024);
-        //let path = sym.appendChild(document.createElementNS(SVG, "path"));
-        //path.setAttribute("d", "M219 310v329q0 7-5 12t-12 5q-8 0-13-5l-164-164q-5-5-5-13t5-13l164-164q5-5 13-5 7 0 12 5t5 12zM1024 749v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12zM1024 530v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 310v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 91v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12z");
-        //span.appendChild(sym);
-        return span;
-    }
-
     // Create an icon for a heading at the given level
     heading(level: number) {
         return {
@@ -156,10 +233,8 @@ export class TooltipTextMenu {
         let left = Math.max((start.left + end.left) / 2, start.left + 3)
         this.tooltip.style.left = (left - box.left) + "px"
         //let width = Math.abs(start.left - end.left) / 2;
-        let width = 8 * 16 + 15;
+        let width = 220;
         let mid = Math.min(start.left, end.left) + width;
-
-        //THIS WIDTH IS 15 * NUMBER OF ICONS + 15
         this.tooltip.style.width = width + "px";
         this.tooltip.style.bottom = (box.bottom - start.top) + "px";
     }
-- 
cgit v1.2.3-70-g09d2

