From 03b2c984d581e18ed898cb097b12ab3ec70c833d Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Tue, 2 Apr 2019 18:31:37 -0400 Subject: bullets work --- src/client/util/TooltipTextMenu.tsx | 52 ++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 2a613ba8b..eaf18825c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,25 +1,29 @@ import { action, IReactionDisposer, reaction } from "mobx"; -import { baseKeymap } from "prosemirror-commands"; +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 { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType } from "prosemirror-model" -import React = require("react") +import { Schema, NodeType } from "prosemirror-model"; +import { liftItem } from "prosemirror-menu"; +import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core' -import { wrapInList, bulletList } from 'prosemirror-schema-list' +import { wrapInList, bulletList, liftListItem, listItem } from 'prosemirror-schema-list' import { faListUl, } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +const SVG = "http://www.w3.org/2000/svg" //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { private tooltip: HTMLElement; + private num_icons = 0; constructor(view: EditorView) { this.tooltip = document.createElement("div"); @@ -39,20 +43,28 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough") }, { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, - //this doesn't work currently - look into notion of active block { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, + //{ command: lift, dom: this.icon("<", "unindent") }, + + { command: lift, dom: this.unorderedListIcon() }, ] - items.forEach(({ dom }) => this.tooltip.appendChild(dom)); + //add menu items + items.forEach(({ dom, command }) => { + this.tooltip.appendChild(dom); + }); //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 (dom.contains(e.srcElement)) { + //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" + //dom.style.display = active ? "" : "none"; } }) }) @@ -90,9 +102,24 @@ 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 fa fa-smile-o"; - span.appendChild(icon); + //let icon = document.createElement("FontAwesomeIcon"); + //icon.className = "menuicon"; + //icon.style.color = "white"; + //span.appendChild(); + 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; } @@ -127,11 +154,12 @@ export class TooltipTextMenu { // crossing lines, end may be more to the left) 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 = Math.abs(start.left - end.left) / 2; + let width = 8 * 16 + 15; let mid = Math.min(start.left, end.left) + width; //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 - this.tooltip.style.width = 122 + "px"; + this.tooltip.style.width = width + "px"; this.tooltip.style.bottom = (box.bottom - start.top) + "px"; } -- cgit v1.2.3-70-g09d2 From b3246c495a1e116abe7ab7abea347126eead4e0d Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 8 Apr 2019 18:24:06 -0400 Subject: bulleting works with some bugsbugs, font styles in progress --- src/client/util/RichTextSchema.tsx | 10 +++++++++- src/client/util/TooltipTextMenu.tsx | 9 +++++---- .../files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg | Bin 0 -> 26946 bytes .../files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg | Bin 0 -> 45309 bytes .../files/upload_2045f363aa9cf281407703ca242aad1a.jpg | Bin 0 -> 9009 bytes .../files/upload_25bffd90c080c27f5ac822984406b958.jpg | Bin 0 -> 43534 bytes .../files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg | Bin 0 -> 27259 bytes .../files/upload_26bcc62639141ba64e603daebb5bf5d3.png | Bin 0 -> 2757327 bytes .../files/upload_2d77d0773612e4723b78118ac50a2929.jpg | Bin 0 -> 1805512 bytes .../files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg | Bin 0 -> 77462 bytes .../files/upload_4abb568aa7cce9d291532c3d0da97102.jpg | Bin 0 -> 22445 bytes .../files/upload_54c34aaca5a7bf510cebad461ec39512.png | Bin 0 -> 2757327 bytes .../files/upload_562b1e527300df8b350eeab094b3e1f1.jpg | Bin 0 -> 15988 bytes .../files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg | Bin 0 -> 45025 bytes .../files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg | Bin 0 -> 18041 bytes .../files/upload_8155b5b0f57da107bb07083c04e78943.jpg | Bin 0 -> 31103 bytes .../files/upload_88f588574e0efc415186af935114af9a.jpg | Bin 0 -> 40249 bytes .../files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png | Bin 0 -> 2757327 bytes .../files/upload_9ef80158609f5ff739087aecad367b9d.jpg | Bin 0 -> 28523 bytes .../files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg | Bin 0 -> 13811 bytes .../files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg | Bin 0 -> 28566 bytes .../files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg | Bin 0 -> 21995 bytes .../files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg | Bin 0 -> 22125 bytes .../files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg | Bin 0 -> 18964 bytes 24 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg create mode 100644 src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg create mode 100644 src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg create mode 100644 src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg create mode 100644 src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg create mode 100644 src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png create mode 100644 src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg create mode 100644 src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg create mode 100644 src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg create mode 100644 src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png create mode 100644 src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg create mode 100644 src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg create mode 100644 src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg create mode 100644 src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg create mode 100644 src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg create mode 100644 src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png create mode 100644 src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg create mode 100644 src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg create mode 100644 src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg create mode 100644 src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg create mode 100644 src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg create mode 100644 src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg (limited to 'src/client/util') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2a3c1da6e..98c22204a 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -222,7 +222,15 @@ export const marks: { [index: string]: MarkSpec } = { code: { parseDOM: [{ tag: "code" }], toDOM() { return codeDOM } - } + }, + + + timesNewRoman: { + parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Times New Roman", Times, serif;' + }] + }, } // :: Schema diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index eaf18825c..3f37d5fb8 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,4 +1,5 @@ import { action, IReactionDisposer, reaction } from "mobx"; +import { Dropdown, DropdownSubmenu, MenuItem } from "prosemirror-menu"; import { baseKeymap, lift } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; @@ -6,7 +7,6 @@ import { EditorState, Transaction, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; import { Schema, NodeType } from "prosemirror-model"; -import { liftItem } from "prosemirror-menu"; import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); @@ -44,15 +44,16 @@ 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: lift, dom: this.icon("<", "unindent") }, - - { command: lift, dom: this.unorderedListIcon() }, + { 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(); diff --git a/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg b/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg new file mode 100644 index 000000000..aeb10c4b0 Binary files /dev/null and b/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg differ diff --git a/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg b/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg new file mode 100644 index 000000000..a2c1d8a46 Binary files /dev/null and b/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg differ diff --git a/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg b/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg new file mode 100644 index 000000000..c19b31a38 Binary files /dev/null and b/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg differ diff --git a/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg b/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg new file mode 100644 index 000000000..3614b42eb Binary files /dev/null and b/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg differ diff --git a/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg b/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg new file mode 100644 index 000000000..ecd12d9cb Binary files /dev/null and b/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg differ diff --git a/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png b/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png new file mode 100644 index 000000000..e2297cb3c Binary files /dev/null and b/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png differ diff --git a/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg b/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg new file mode 100644 index 000000000..261a0ceff Binary files /dev/null and b/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg differ diff --git a/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg b/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg new file mode 100644 index 000000000..6b6ec3c3f Binary files /dev/null and b/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg differ diff --git a/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg b/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg new file mode 100644 index 000000000..f6332670c Binary files /dev/null and b/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg differ diff --git a/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png b/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png new file mode 100644 index 000000000..e2297cb3c Binary files /dev/null and b/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png differ diff --git a/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg b/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg new file mode 100644 index 000000000..db40705dd Binary files /dev/null and b/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg differ diff --git a/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg b/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg new file mode 100644 index 000000000..f0417a752 Binary files /dev/null and b/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg differ diff --git a/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg b/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg new file mode 100644 index 000000000..395f8ec21 Binary files /dev/null and b/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg differ diff --git a/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg b/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg new file mode 100644 index 000000000..53d9315a9 Binary files /dev/null and b/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg differ diff --git a/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg b/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg new file mode 100644 index 000000000..b72dbc482 Binary files /dev/null and b/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg differ diff --git a/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png b/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png new file mode 100644 index 000000000..e2297cb3c Binary files /dev/null and b/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png differ diff --git a/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg b/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg new file mode 100644 index 000000000..84423538c Binary files /dev/null and b/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg differ diff --git a/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg b/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg new file mode 100644 index 000000000..dc7ec2f33 Binary files /dev/null and b/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg differ diff --git a/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg b/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg new file mode 100644 index 000000000..4422124a1 Binary files /dev/null and b/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg differ diff --git a/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg b/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg new file mode 100644 index 000000000..3747ca985 Binary files /dev/null and b/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg differ diff --git a/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg b/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg new file mode 100644 index 000000000..95053d772 Binary files /dev/null and b/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg differ diff --git a/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg b/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg new file mode 100644 index 000000000..9841bad3f Binary files /dev/null and b/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg differ -- cgit v1.2.3-70-g09d2 From 4790fd3ff75ace158c47823b5619440d8fd1d879 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 8 Apr 2019 18:55:53 -0400 Subject: beginning keyboard shortcuts --- src/client/util/RichTextSchema.tsx | 1 - src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/InkingCanvas.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 98c22204a..489c22a57 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -9,7 +9,6 @@ import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] - // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes: { [index: string]: NodeSpec } = { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 3f37d5fb8..4715fcc14 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -61,7 +61,7 @@ export class TooltipTextMenu { //update view of icons this.num_icons = 0; items.forEach(({ command, dom }) => { - if (dom.contains(e.srcElement)) { + 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 diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 123ff679b..3189e8a5f 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -24,7 +24,7 @@ export class InkingCanvas extends React.Component { return stroke.pathData.reduce((inside, val) => inside || (selRect.left < val.x - InkingCanvas.InkOffset && selRect.left + selRect.width > val.x - InkingCanvas.InkOffset && selRect.top < val.y - InkingCanvas.InkOffset && selRect.top + selRect.height > val.y - InkingCanvas.InkOffset) - , false); + , false as boolean); } @computed diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 28a1f9757..12208714d 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -151,7 +151,7 @@ export class PDFBox extends React.Component { */ makeEditableAndHighlight = (colour: string) => { var range, sel = window.getSelection(); - if (sel.rangeCount && sel.getRangeAt) { + if (sel && sel.rangeCount && sel.getRangeAt) { range = sel.getRangeAt(0); } document.designMode = "on"; @@ -159,7 +159,7 @@ export class PDFBox extends React.Component { document.execCommand("HiliteColor", false, colour); } - if (range) { + if (range && sel) { sel.removeAllRanges(); sel.addRange(range); -- cgit v1.2.3-70-g09d2 From 218a3bdff2f7c4888b5f21466dee65c36a76ea00 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 8 Apr 2019 18:56:40 -0400 Subject: work on dropdown --- src/client/util/TooltipTextMenu.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/client/util') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 3f37d5fb8..8c4470f23 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -53,6 +53,18 @@ export class TooltipTextMenu { }); //add dropdowns + let cut = arr => arr.filter(x => x); + let config = { + + } + let tnr = new MenuItem({ + title: "tnr", + label: "Times New Roman", + css: "font-family: Times New Roman, Times, serif; ", + enable(state) { return canInsert(state, hr) }, + run(state, dispatch) { dispatch(state.tr.replaceSelectionWith(hr.create())) } + }) + new Dropdown(cut([schema.marks.timesNewRoman, r.insertHorizontalRule]), { label: "Insert" }) //pointer down handler to activate button effects this.tooltip.addEventListener("pointerdown", e => { -- cgit v1.2.3-70-g09d2 From b7d02ec188ecf043300ed858fdb68148b3e52a71 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 9 Apr 2019 17:24:11 -0400 Subject: exploring in-editor undo-redo --- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4715fcc14..e84d48ce3 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -45,7 +45,7 @@ export class TooltipTextMenu { { 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") }, + { command: undo, dom: this.icon("<", "lift") }, ] //add menu items items.forEach(({ dom, command }) => { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 512ad7d70..be534099c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -15,6 +15,7 @@ import { Decoration, DecorationSet } from 'prosemirror-view' import { TooltipTextMenu } from "../../util/TooltipTextMenu" import { ContextMenu } from "../../views/ContextMenu"; import { inpRules } from "../../util/RichTextRules"; +import { Schema } from "prosemirror-model"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -61,6 +62,12 @@ export class FormattedTextBox extends React.Component { } } + undo = (state: EditorState, dispatch?: (tr: Transaction) => void): boolean => { + console.log(state); + console.log(dispatch); + return true; + } + componentDidMount() { let state: EditorState; const config = { @@ -68,7 +75,7 @@ export class FormattedTextBox extends React.Component { inpRules, //these currently don't do anything, but could eventually be helpful plugins: [ history(), - keymap({ "Mod-z": undo, "Mod-y": redo }), + keymap({ "Mod-z": this.undo, "Mod-y": redo }), keymap(baseKeymap), this.tooltipMenuPlugin() ] @@ -151,7 +158,7 @@ export class FormattedTextBox extends React.Component { e.stopPropagation(); } - tooltipMenuPlugin() { + tooltipMenuPlugin(): Plugin { return new Plugin({ view(_editorView) { return new TooltipTextMenu(_editorView) -- cgit v1.2.3-70-g09d2 From 15514b0f3d685764d1bd7ebeac9cdee1f778e184 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Thu, 11 Apr 2019 12:06:46 -0400 Subject: font style and size dropdowns work --- package.json | 332 +++++++++--------- src/client/util/RichTextSchema.tsx | 507 ++++++++++++++++------------ src/client/util/TooltipTextMenu.scss | 238 ++++++++++++- src/client/util/TooltipTextMenu.tsx | 173 +++++++--- src/client/views/nodes/FormattedTextBox.tsx | 7 +- 5 files changed, 830 insertions(+), 427 deletions(-) (limited to 'src/client/util') diff --git a/package.json b/package.json index 135bd4a91..11eb6f0f5 100644 --- a/package.json +++ b/package.json @@ -1,168 +1,168 @@ { - "name": "dash", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts", - "build": "webpack --env production", - "test": "mocha -r ts-node/register test/**/*.ts", - "tsc": "tsc" - }, - "devDependencies": { - "@types/chai": "^4.1.7", - "@types/mocha": "^5.2.6", - "@types/react-dom": "^16.8.2", - "@types/webpack-dev-middleware": "^2.0.2", - "@types/webpack-hot-middleware": "^2.16.4", - "awesome-typescript-loader": "^5.2.1", - "chai": "^4.2.0", - "copy-webpack-plugin": "^4.6.0", - "css-loader": "^2.1.1", - "file-loader": "^3.0.1", - "mocha": "^5.2.0", - "sass-loader": "^7.1.0", - "scss-loader": "0.0.1", - "style-loader": "^0.23.1", - "ts-node": "^7.0.1", - "typescript": "^3.4.1", - "webpack": "^4.29.6", - "webpack-cli": "^3.2.3", - "webpack-dev-middleware": "^3.6.1", - "webpack-dev-server": "^3.2.1", - "webpack-hot-middleware": "^2.24.3" - }, - "dependencies": { - "@fortawesome/fontawesome-free-solid": "^5.0.13", - "@fortawesome/fontawesome-svg-core": "^1.2.15", - "@fortawesome/free-solid-svg-icons": "^5.7.2", - "@fortawesome/react-fontawesome": "^0.1.4", - "@hig/flyout": "^1.0.3", - "@hig/theme-context": "^2.1.3", - "@hig/theme-data": "^2.3.3", - "@trendmicro/react-dropdown": "^1.3.0", - "@types/async": "^2.4.1", - "@types/bcrypt-nodejs": "0.0.30", - "@types/bluebird": "^3.5.25", - "@types/body-parser": "^1.17.0", - "@types/connect-flash": "0.0.34", - "@types/cookie-parser": "^1.4.1", - "@types/cookie-session": "^2.0.36", - "@types/d3-format": "^1.3.1", - "@types/express": "^4.16.1", - "@types/express-flash": "0.0.0", - "@types/express-session": "^1.15.12", - "@types/express-validator": "^3.0.0", - "@types/formidable": "^1.0.31", - "@types/jquery": "^3.3.29", - "@types/jsonwebtoken": "^8.3.2", - "@types/lodash": "^4.14.121", - "@types/mobile-detect": "^1.3.4", - "@types/mongodb": "^3.1.22", - "@types/mongoose": "^5.3.21", - "@types/node": "^10.12.30", - "@types/nodemailer": "^4.6.6", - "@types/passport": "^1.0.0", - "@types/passport-local": "^1.0.33", - "@types/prosemirror-commands": "^1.0.1", - "@types/prosemirror-history": "^1.0.1", - "@types/prosemirror-inputrules": "^1.0.2", - "@types/prosemirror-keymap": "^1.0.1", - "@types/prosemirror-menu": "^1.0.1", - "@types/prosemirror-model": "^1.7.0", - "@types/prosemirror-schema-basic": "^1.0.1", - "@types/prosemirror-schema-list": "^1.0.1", - "@types/prosemirror-state": "^1.2.3", - "@types/prosemirror-transform": "^1.1.0", - "@types/prosemirror-view": "^1.3.1", - "@types/pug": "^2.0.4", - "@types/react": "^16.8.7", - "@types/react-color": "^2.14.1", - "@types/react-measure": "^2.0.4", - "@types/react-table": "^6.7.22", - "@types/request": "^2.48.1", - "@types/request-promise": "^4.1.42", - "@types/socket.io": "^2.1.2", - "@types/socket.io-client": "^1.4.32", - "@types/typescript": "^2.0.0", - "@types/uuid": "^3.4.4", - "@types/webpack": "^4.4.25", - "async": "^2.6.2", - "babel-runtime": "^6.26.0", - "bcrypt-nodejs": "0.0.3", - "bluebird": "^3.5.3", - "body-parser": "^1.18.3", - "bootstrap": "^4.3.1", - "class-transformer": "^0.2.0", - "connect-flash": "^0.1.1", - "connect-mongo": "^2.0.3", - "cookie-parser": "^1.4.4", - "cookie-session": "^2.0.0-beta.3", - "crypto-browserify": "^3.11.0", - "d3-format": "^1.3.2", - "express": "^4.16.4", - "express-flash": "0.0.2", - "express-session": "^1.15.6", - "express-validator": "^5.3.1", - "expressjs": "^1.0.1", - "flexlayout-react": "^0.3.3", - "font-awesome": "^4.7.0", - "formidable": "^1.2.1", - "golden-layout": "^1.5.9", - "html-to-image": "^0.1.0", - "i": "^0.3.6", - "jsonwebtoken": "^8.5.0", - "jsx-to-string": "^1.4.0", - "lodash": "^4.17.11", - "mobile-detect": "^1.4.3", - "mobx": "^5.9.0", - "mobx-react": "^5.3.5", - "mobx-react-devtools": "^6.1.1", - "mongodb": "^3.1.13", - "mongoose": "^5.4.18", - "node-sass": "^4.11.0", - "nodemailer": "^5.1.1", - "nodemon": "^1.18.10", - "normalize.css": "^8.0.1", - "npm": "^6.9.0", - "passport": "^0.4.0", - "passport-local": "^1.0.0", - "prosemirror-commands": "^1.0.7", - "prosemirror-example-setup": "^1.0.1", - "prosemirror-history": "^1.0.4", - "prosemirror-keymap": "^1.0.1", - "prosemirror-model": "^1.7.0", - "prosemirror-schema-basic": "^1.0.0", - "prosemirror-schema-list": "^1.0.2", - "prosemirror-state": "^1.2.2", - "prosemirror-transform": "^1.1.3", - "prosemirror-view": "^1.8.3", - "pug": "^2.0.3", - "raw-loader": "^1.0.0", - "react": "^16.8.4", - "react-bootstrap": "^1.0.0-beta.5", - "react-bootstrap-dropdown-menu": "^1.1.15", - "react-color": "^2.17.0", - "react-dimensions": "^1.3.1", - "react-dom": "^16.8.4", - "react-golden-layout": "^1.0.6", - "react-image-lightbox": "^5.1.0", - "react-jsx-parser": "^1.15.0", - "react-measure": "^2.2.4", - "react-mosaic": "0.0.20", - "react-pdf": "^4.0.2", - "react-pdf-highlighter": "^2.1.2", - "react-pdf-js": "^4.0.2", - "react-simple-dropdown": "^3.2.3", - "react-split-pane": "^0.1.85", - "react-table": "^6.9.2", - "request": "^2.88.0", - "request-promise": "^4.2.4", - "socket.io": "^2.2.0", - "socket.io-client": "^2.2.0", - "typescript-collections": "^1.3.2", - "url-loader": "^1.1.2", - "uuid": "^3.3.2", - "xoauth2": "^1.2.0" - } + "name": "dash", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts", + "build": "webpack --env production", + "test": "mocha -r ts-node/register test/**/*.ts", + "tsc": "tsc" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", + "@types/react-dom": "^16.8.2", + "@types/webpack-dev-middleware": "^2.0.2", + "@types/webpack-hot-middleware": "^2.16.4", + "awesome-typescript-loader": "^5.2.1", + "chai": "^4.2.0", + "copy-webpack-plugin": "^4.6.0", + "css-loader": "^2.1.1", + "file-loader": "^3.0.1", + "mocha": "^5.2.0", + "sass-loader": "^7.1.0", + "scss-loader": "0.0.1", + "style-loader": "^0.23.1", + "ts-node": "^7.0.1", + "typescript": "^3.4.1", + "webpack": "^4.29.6", + "webpack-cli": "^3.2.3", + "webpack-dev-middleware": "^3.6.1", + "webpack-dev-server": "^3.2.1", + "webpack-hot-middleware": "^2.24.3" + }, + "dependencies": { + "@fortawesome/fontawesome-free-solid": "^5.0.13", + "@fortawesome/fontawesome-svg-core": "^1.2.15", + "@fortawesome/free-solid-svg-icons": "^5.7.2", + "@fortawesome/react-fontawesome": "^0.1.4", + "@hig/flyout": "^1.0.3", + "@hig/theme-context": "^2.1.3", + "@hig/theme-data": "^2.3.3", + "@trendmicro/react-dropdown": "^1.3.0", + "@types/async": "^2.4.1", + "@types/bcrypt-nodejs": "0.0.30", + "@types/bluebird": "^3.5.25", + "@types/body-parser": "^1.17.0", + "@types/connect-flash": "0.0.34", + "@types/cookie-parser": "^1.4.1", + "@types/cookie-session": "^2.0.36", + "@types/d3-format": "^1.3.1", + "@types/express": "^4.16.1", + "@types/express-flash": "0.0.0", + "@types/express-session": "^1.15.12", + "@types/express-validator": "^3.0.0", + "@types/formidable": "^1.0.31", + "@types/jquery": "^3.3.29", + "@types/jsonwebtoken": "^8.3.2", + "@types/lodash": "^4.14.121", + "@types/mobile-detect": "^1.3.4", + "@types/mongodb": "^3.1.22", + "@types/mongoose": "^5.3.21", + "@types/node": "^10.12.30", + "@types/nodemailer": "^4.6.6", + "@types/passport": "^1.0.0", + "@types/passport-local": "^1.0.33", + "@types/prosemirror-commands": "^1.0.1", + "@types/prosemirror-history": "^1.0.1", + "@types/prosemirror-inputrules": "^1.0.2", + "@types/prosemirror-keymap": "^1.0.1", + "@types/prosemirror-menu": "^1.0.1", + "@types/prosemirror-model": "^1.7.0", + "@types/prosemirror-schema-basic": "^1.0.1", + "@types/prosemirror-schema-list": "^1.0.1", + "@types/prosemirror-state": "^1.2.3", + "@types/prosemirror-transform": "^1.1.0", + "@types/prosemirror-view": "^1.3.1", + "@types/pug": "^2.0.4", + "@types/react": "^16.8.7", + "@types/react-color": "^2.14.1", + "@types/react-measure": "^2.0.4", + "@types/react-table": "^6.7.22", + "@types/request": "^2.48.1", + "@types/request-promise": "^4.1.42", + "@types/socket.io": "^2.1.2", + "@types/socket.io-client": "^1.4.32", + "@types/typescript": "^2.0.0", + "@types/uuid": "^3.4.4", + "@types/webpack": "^4.4.25", + "async": "^2.6.2", + "babel-runtime": "^6.26.0", + "bcrypt-nodejs": "0.0.3", + "bluebird": "^3.5.3", + "body-parser": "^1.18.3", + "bootstrap": "^4.3.1", + "class-transformer": "^0.2.0", + "connect-flash": "^0.1.1", + "connect-mongo": "^2.0.3", + "cookie-parser": "^1.4.4", + "cookie-session": "^2.0.0-beta.3", + "crypto-browserify": "^3.11.0", + "d3-format": "^1.3.2", + "express": "^4.16.4", + "express-flash": "0.0.2", + "express-session": "^1.15.6", + "express-validator": "^5.3.1", + "expressjs": "^1.0.1", + "flexlayout-react": "^0.3.3", + "font-awesome": "^4.7.0", + "formidable": "^1.2.1", + "golden-layout": "^1.5.9", + "html-to-image": "^0.1.0", + "i": "^0.3.6", + "jsonwebtoken": "^8.5.0", + "jsx-to-string": "^1.4.0", + "lodash": "^4.17.11", + "mobile-detect": "^1.4.3", + "mobx": "^5.9.0", + "mobx-react": "^5.3.5", + "mobx-react-devtools": "^6.1.1", + "mongodb": "^3.1.13", + "mongoose": "^5.4.18", + "node-sass": "^4.11.0", + "nodemailer": "^5.1.1", + "nodemon": "^1.18.10", + "normalize.css": "^8.0.1", + "npm": "^6.9.0", + "passport": "^0.4.0", + "passport-local": "^1.0.0", + "prosemirror-commands": "^1.0.7", + "prosemirror-example-setup": "^1.0.1", + "prosemirror-history": "^1.0.4", + "prosemirror-keymap": "^1.0.1", + "prosemirror-model": "^1.7.0", + "prosemirror-schema-basic": "^1.0.0", + "prosemirror-schema-list": "^1.0.2", + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.1.3", + "prosemirror-view": "^1.8.3", + "pug": "^2.0.3", + "raw-loader": "^1.0.0", + "react": "^16.8.4", + "react-bootstrap": "^1.0.0-beta.5", + "react-bootstrap-dropdown-menu": "^1.1.15", + "react-color": "^2.17.0", + "react-dimensions": "^1.3.1", + "react-dom": "^16.8.4", + "react-golden-layout": "^1.0.6", + "react-image-lightbox": "^5.1.0", + "react-jsx-parser": "^1.15.0", + "react-measure": "^2.2.4", + "react-mosaic": "0.0.20", + "react-pdf": "^4.0.2", + "react-pdf-highlighter": "^2.1.2", + "react-pdf-js": "^4.0.2", + "react-simple-dropdown": "^3.2.3", + "react-split-pane": "^0.1.85", + "react-table": "^6.9.2", + "request": "^2.88.0", + "request-promise": "^4.2.4", + "socket.io": "^2.2.0", + "socket.io-client": "^2.2.0", + "typescript-collections": "^1.3.2", + "url-loader": "^1.1.2", + "uuid": "^3.3.2", + "xoauth2": "^1.2.0" + } } diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 489c22a57..765ac0ae3 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -7,134 +7,134 @@ import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes: { [index: string]: NodeSpec } = { - // :: NodeSpec The top level document node. - doc: { - content: "block+" - }, - - // :: NodeSpec A plain paragraph textblock. Represented in the DOM - // as a `

` element. - paragraph: { - content: "inline*", - group: "block", - parseDOM: [{ tag: "p" }], - toDOM() { return pDOM } - }, - - // :: NodeSpec A blockquote (`

`) wrapping one or more blocks. - blockquote: { - content: "block+", - group: "block", - defining: true, - parseDOM: [{ tag: "blockquote" }], - toDOM() { return blockquoteDOM } - }, - - // :: NodeSpec A horizontal rule (`
`). - horizontal_rule: { - group: "block", - parseDOM: [{ tag: "hr" }], - toDOM() { return hrDOM } - }, - - // :: NodeSpec A heading textblock, with a `level` attribute that - // should hold the number 1 to 6. Parsed and serialized as `

` to - // `

` elements. - heading: { - attrs: { level: { default: 1 } }, - content: "inline*", - group: "block", - defining: true, - parseDOM: [{ tag: "h1", attrs: { level: 1 } }, - { tag: "h2", attrs: { level: 2 } }, - { tag: "h3", attrs: { level: 3 } }, - { tag: "h4", attrs: { level: 4 } }, - { tag: "h5", attrs: { level: 5 } }, - { tag: "h6", attrs: { level: 6 } }], - toDOM(node: any) { return ["h" + node.attrs.level, 0] } - }, - - // :: NodeSpec A code listing. Disallows marks or non-text inline - // nodes by default. Represented as a `
` element with a
-  // `` element inside of it.
-  code_block: {
-    content: "text*",
-    marks: "",
-    group: "block",
-    code: true,
-    defining: true,
-    parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
-    toDOM() { return preDOM }
-  },
-
-  // :: NodeSpec The text node.
-  text: {
-    group: "inline"
-  },
-
-  // :: NodeSpec An inline image (``) node. Supports `src`,
-  // `alt`, and `href` attributes. The latter two default to the empty
-  // string.
-  image: {
-    inline: true,
-    attrs: {
-      src: {},
-      alt: { default: null },
-      title: { default: null }
-    },
-    group: "inline",
-    draggable: true,
-    parseDOM: [{
-      tag: "img[src]", getAttrs(dom: any) {
-        return {
-          src: dom.getAttribute("src"),
-          title: dom.getAttribute("title"),
-          alt: dom.getAttribute("alt")
-        }
-      }
-    }],
-    toDOM(node: any) { return ["img", node.attrs] }
-  },
-
-  // :: NodeSpec A hard line break, represented in the DOM as `
`. - hard_break: { - inline: true, - group: "inline", - selectable: false, - parseDOM: [{ tag: "br" }], - toDOM() { return brDOM } - }, - - ordered_list: { - ...orderedList, - content: 'list_item+', - group: 'block' - }, - //this doesn't currently work for some reason - bullet_list: { - ...bulletList, - content: 'list_item+', - group: 'block', - // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], - // toDOM() { return ulDOM } - }, - //bullet_list: { - // content: 'list_item+', - // group: 'block', - //active: blockActive(schema.nodes.bullet_list), - //enable: wrapInList(schema.nodes.bullet_list), - //run: wrapInList(schema.nodes.bullet_list), - //select: state => true, - // }, - list_item: { - ...listItem, - content: 'paragraph block*' - } + // :: NodeSpec The top level document node. + doc: { + content: "block+" + }, + + // :: NodeSpec A plain paragraph textblock. Represented in the DOM + // as a `

` element. + paragraph: { + content: "inline*", + group: "block", + parseDOM: [{ tag: "p" }], + toDOM() { return pDOM } + }, + + // :: NodeSpec A blockquote (`

`) wrapping one or more blocks. + blockquote: { + content: "block+", + group: "block", + defining: true, + parseDOM: [{ tag: "blockquote" }], + toDOM() { return blockquoteDOM } + }, + + // :: NodeSpec A horizontal rule (`
`). + horizontal_rule: { + group: "block", + parseDOM: [{ tag: "hr" }], + toDOM() { return hrDOM } + }, + + // :: NodeSpec A heading textblock, with a `level` attribute that + // should hold the number 1 to 6. Parsed and serialized as `

` to + // `

` elements. + heading: { + attrs: { level: { default: 1 } }, + content: "inline*", + group: "block", + defining: true, + parseDOM: [{ tag: "h1", attrs: { level: 1 } }, + { tag: "h2", attrs: { level: 2 } }, + { tag: "h3", attrs: { level: 3 } }, + { tag: "h4", attrs: { level: 4 } }, + { tag: "h5", attrs: { level: 5 } }, + { tag: "h6", attrs: { level: 6 } }], + toDOM(node: any) { return ["h" + node.attrs.level, 0] } + }, + + // :: NodeSpec A code listing. Disallows marks or non-text inline + // nodes by default. Represented as a `
` element with a
+    // `` element inside of it.
+    code_block: {
+        content: "text*",
+        marks: "",
+        group: "block",
+        code: true,
+        defining: true,
+        parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
+        toDOM() { return preDOM }
+    },
+
+    // :: NodeSpec The text node.
+    text: {
+        group: "inline"
+    },
+
+    // :: NodeSpec An inline image (``) node. Supports `src`,
+    // `alt`, and `href` attributes. The latter two default to the empty
+    // string.
+    image: {
+        inline: true,
+        attrs: {
+            src: {},
+            alt: { default: null },
+            title: { default: null }
+        },
+        group: "inline",
+        draggable: true,
+        parseDOM: [{
+            tag: "img[src]", getAttrs(dom: any) {
+                return {
+                    src: dom.getAttribute("src"),
+                    title: dom.getAttribute("title"),
+                    alt: dom.getAttribute("alt")
+                }
+            }
+        }],
+        toDOM(node: any) { return ["img", node.attrs] }
+    },
+
+    // :: NodeSpec A hard line break, represented in the DOM as `
`. + hard_break: { + inline: true, + group: "inline", + selectable: false, + parseDOM: [{ tag: "br" }], + toDOM() { return brDOM } + }, + + ordered_list: { + ...orderedList, + content: 'list_item+', + group: 'block' + }, + //this doesn't currently work for some reason + bullet_list: { + ...bulletList, + content: 'list_item+', + group: 'block', + // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], + // toDOM() { return ulDOM } + }, + //bullet_list: { + // content: 'list_item+', + // group: 'block', + //active: blockActive(schema.nodes.bullet_list), + //enable: wrapInList(schema.nodes.bullet_list), + //run: wrapInList(schema.nodes.bullet_list), + //select: state => true, + // }, + list_item: { + ...listItem, + content: 'paragraph block*' + } } const emDOM: DOMOutputSpecArray = ["em", 0]; @@ -144,92 +144,179 @@ const underlineDOM: DOMOutputSpecArray = ["underline", 0]; // :: Object [Specs](#model.MarkSpec) for the marks in the schema. export const marks: { [index: string]: MarkSpec } = { - // :: MarkSpec A link. Has `href` and `title` attributes. `title` - // defaults to the empty string. Rendered and parsed as an `` - // element. - link: { - attrs: { - href: {}, - title: { default: null } - }, - inclusive: false, - parseDOM: [{ - tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } - } - }], - toDOM(node: any) { return ["a", node.attrs, 0] } - }, - - // :: MarkSpec An emphasis mark. Rendered as an `` element. - // Has parse rules that also match `` and `font-style: italic`. - em: { - parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], - toDOM() { return emDOM } - }, - - // :: MarkSpec A strong mark. Rendered as ``, parse rules - // also match `` and `font-weight: bold`. - strong: { - parseDOM: [{ tag: "strong" }, - { tag: "b" }, - { style: "font-weight" }], - toDOM() { return strongDOM } - }, - - underline: { - parseDOM: [ - { tag: 'u' }, - { style: 'text-decoration=underline' } - ], - toDOM: () => ['span', { - style: 'text-decoration:underline' - }] - }, - - strikethrough: { - parseDOM: [ - { tag: 'strike' }, - { style: 'text-decoration=line-through' }, - { style: 'text-decoration-line=line-through' } - ], - toDOM: () => ['span', { - style: 'text-decoration-line:line-through' - }] - }, - - subscript: { - excludes: 'superscript', - parseDOM: [ - { tag: 'sub' }, - { style: 'vertical-align=sub' } - ], - toDOM: () => ['sub'] - }, - - superscript: { - excludes: 'subscript', - parseDOM: [ - { tag: 'sup' }, - { style: 'vertical-align=super' } - ], - toDOM: () => ['sup'] - }, - - - // :: MarkSpec Code font mark. Represented as a `` element. - code: { - parseDOM: [{ tag: "code" }], - toDOM() { return codeDOM } - }, - - - timesNewRoman: { - parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }], - toDOM: () => ['span', { - style: 'font-family: "Times New Roman", Times, serif;' - }] - }, + // :: MarkSpec A link. Has `href` and `title` attributes. `title` + // defaults to the empty string. Rendered and parsed as an `` + // element. + link: { + attrs: { + href: {}, + title: { default: null } + }, + inclusive: false, + parseDOM: [{ + tag: "a[href]", getAttrs(dom: any) { + return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } + } + }], + toDOM(node: any) { return ["a", node.attrs, 0] } + }, + + // :: MarkSpec An emphasis mark. Rendered as an `` element. + // Has parse rules that also match `` and `font-style: italic`. + em: { + parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], + toDOM() { return emDOM } + }, + + // :: MarkSpec A strong mark. Rendered as ``, parse rules + // also match `` and `font-weight: bold`. + strong: { + parseDOM: [{ tag: "strong" }, + { tag: "b" }, + { style: "font-weight" }], + toDOM() { return strongDOM } + }, + + underline: { + parseDOM: [ + { tag: 'u' }, + { style: 'text-decoration=underline' } + ], + toDOM: () => ['span', { + style: 'text-decoration:underline' + }] + }, + + strikethrough: { + parseDOM: [ + { tag: 'strike' }, + { style: 'text-decoration=line-through' }, + { style: 'text-decoration-line=line-through' } + ], + toDOM: () => ['span', { + style: 'text-decoration-line:line-through' + }] + }, + + subscript: { + excludes: 'superscript', + parseDOM: [ + { tag: 'sub' }, + { style: 'vertical-align=sub' } + ], + toDOM: () => ['sub'] + }, + + superscript: { + excludes: 'subscript', + parseDOM: [ + { tag: 'sup' }, + { style: 'vertical-align=super' } + ], + toDOM: () => ['sup'] + }, + + + // :: MarkSpec Code font mark. Represented as a `` element. + code: { + parseDOM: [{ tag: "code" }], + toDOM() { return codeDOM } + }, + + + /* FONTS */ + timesNewRoman: { + parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Times New Roman", Times, serif;' + }] + }, + + arial: { + parseDOM: [{ style: 'font-family: Arial, Helvetica, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Arial, Helvetica, sans-serif;' + }] + }, + + georgia: { + parseDOM: [{ style: 'font-family: Georgia, serif;' }], + toDOM: () => ['span', { + style: 'font-family: Georgia, serif;' + }] + }, + + comicSans: { + parseDOM: [{ style: 'font-family: "Comic Sans MS", cursive, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Comic Sans MS", cursive, sans-serif;' + }] + }, + + tahoma: { + parseDOM: [{ style: 'font-family: Tahoma, Geneva, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Tahoma, Geneva, sans-serif;' + }] + }, + + impact: { + parseDOM: [{ style: 'font-family: Impact, Charcoal, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Impact, Charcoal, sans-serif;' + }] + }, + + /** FONT SIZES */ + + p10: { + parseDOM: [{ style: 'font-size: 10px;' }], + toDOM: () => ['span', { + style: 'font-size: 10px;' + }] + }, + + p12: { + parseDOM: [{ style: 'font-size: 12px;' }], + toDOM: () => ['span', { + style: 'font-size: 12px;' + }] + }, + + p16: { + parseDOM: [{ style: 'font-size: 16px;' }], + toDOM: () => ['span', { + style: 'font-size: 16px;' + }] + }, + + p24: { + parseDOM: [{ style: 'font-size: 24px;' }], + toDOM: () => ['span', { + style: 'font-size: 24px;' + }] + }, + + p32: { + parseDOM: [{ style: 'font-size: 32px;' }], + toDOM: () => ['span', { + style: 'font-size: 32px;' + }] + }, + + p48: { + parseDOM: [{ style: 'font-size: 48px;' }], + toDOM: () => ['span', { + style: 'font-size: 48px;' + }] + }, + + p72: { + parseDOM: [{ style: 'font-size: 72px;' }], + toDOM: () => ['span', { + style: 'font-size: 72px;' + }] + }, } // :: Schema diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index ea580d104..b23074239 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -1,5 +1,241 @@ @import "../views/global_variables"; +.ProseMirror-textblock-dropdown { + min-width: 3em; + } + + .ProseMirror-menu { + margin: 0 -4px; + line-height: 1; + } + + .ProseMirror-tooltip .ProseMirror-menu { + width: -webkit-fit-content; + width: fit-content; + white-space: pre; + } + + .ProseMirror-menuitem { + margin-right: 3px; + display: inline-block; + } + + .ProseMirror-menuseparator { + // border-right: 1px solid #ddd; + margin-right: 3px; + } + + .ProseMirror-menu-dropdown, .ProseMirror-menu-dropdown-menu { + font-size: 90%; + white-space: nowrap; + } + + .ProseMirror-menu-dropdown { + vertical-align: 1px; + cursor: pointer; + position: relative; + padding-right: 15px; + } + + .ProseMirror-menu-dropdown-wrap { + padding: 1px 0 1px 4px; + display: inline-block; + position: relative; + } + + .ProseMirror-menu-dropdown:after { + content: ""; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid currentColor; + opacity: .6; + position: absolute; + right: 4px; + top: calc(50% - 2px); + } + + .ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu { + position: absolute; + background: $dark-color; + color:white; + border: 1px solid #aaa; + padding: 2px; + } + + .ProseMirror-menu-dropdown-menu { + z-index: 15; + min-width: 6em; + } + + .ProseMirror-menu-dropdown-item { + cursor: pointer; + padding: 2px 8px 2px 4px; + width: auto; + } + + .ProseMirror-menu-dropdown-item:hover { + background: #2e2b2b; + } + + .ProseMirror-menu-submenu-wrap { + position: relative; + margin-right: -4px; + } + + .ProseMirror-menu-submenu-label:after { + content: ""; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-left: 4px solid currentColor; + opacity: .6; + position: absolute; + right: 4px; + top: calc(50% - 4px); + } + + .ProseMirror-menu-submenu { + display: none; + min-width: 4em; + left: 100%; + top: -3px; + } + + .ProseMirror-menu-active { + background: #eee; + border-radius: 4px; + } + + .ProseMirror-menu-active { + background: #eee; + border-radius: 4px; + } + + .ProseMirror-menu-disabled { + opacity: .3; + } + + .ProseMirror-menu-submenu-wrap:hover .ProseMirror-menu-submenu, .ProseMirror-menu-submenu-wrap-active .ProseMirror-menu-submenu { + display: block; + } + + .ProseMirror-menubar { + border-top-left-radius: inherit; + border-top-right-radius: inherit; + position: relative; + min-height: 1em; + color: white; + padding: 1px 6px; + top: 0; left: 0; right: 0; + border-bottom: 1px solid silver; + background:$dark-color; + z-index: 10; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: visible; + } + + .ProseMirror-icon { + display: inline-block; + line-height: .8; + vertical-align: -2px; /* Compensate for padding */ + padding: 2px 8px; + cursor: pointer; + } + + .ProseMirror-menu-disabled.ProseMirror-icon { + cursor: default; + } + + .ProseMirror-icon svg { + fill: currentColor; + height: 1em; + } + + .ProseMirror-icon span { + vertical-align: text-top; + } +.ProseMirror-example-setup-style hr { + padding: 2px 10px; + border: none; + margin: 1em 0; + } + + .ProseMirror-example-setup-style hr:after { + content: ""; + display: block; + height: 1px; + background-color: silver; + line-height: 2px; + } + + .ProseMirror ul, .ProseMirror ol { + padding-left: 30px; + } + + .ProseMirror blockquote { + padding-left: 1em; + border-left: 3px solid #eee; + margin-left: 0; margin-right: 0; + } + + .ProseMirror-example-setup-style img { + cursor: default; + } + + .ProseMirror-prompt { + background: white; + padding: 5px 10px 5px 15px; + border: 1px solid silver; + position: fixed; + border-radius: 3px; + z-index: 11; + box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2); + } + + .ProseMirror-prompt h5 { + margin: 0; + font-weight: normal; + font-size: 100%; + color: #444; + } + + .ProseMirror-prompt input[type="text"], + .ProseMirror-prompt textarea { + background: #eee; + border: none; + outline: none; + } + + .ProseMirror-prompt input[type="text"] { + padding: 0 4px; + } + + .ProseMirror-prompt-close { + position: absolute; + left: 2px; top: 1px; + color: #666; + border: none; background: transparent; padding: 0; + } + + .ProseMirror-prompt-close:after { + content: "✕"; + font-size: 12px; + } + + .ProseMirror-invalid { + background: #ffc; + border: 1px solid #cc7; + border-radius: 4px; + padding: 5px 10px; + position: absolute; + min-width: 10em; + } + + .ProseMirror-prompt-buttons { + margin-top: 5px; + display: none; + } + .tooltipMenu { position: absolute; z-index: 20; @@ -39,7 +275,7 @@ display: inline-block; border-right: 1px solid rgba(0, 0, 0, 0.2); //color: rgb(19, 18, 18); - color: $light-color; + color: white; line-height: 1; padding: 0px 2px; margin: 1px; 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, 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>) { + 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>, 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(); - 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"; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e59179874..fdb1b97be 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -74,7 +74,12 @@ export class FormattedTextBox extends React.Component { history(), keymap({ "Mod-z": undo, "Mod-y": redo }), keymap(baseKeymap), - this.tooltipMenuPlugin() + this.tooltipMenuPlugin(), + new Plugin({ + props: { + attributes: { class: "ProseMirror-example-setup-style" } + } + }) ] }; -- cgit v1.2.3-70-g09d2 From e981d9d228507fc573febc997eb691a5428126e8 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 15 Apr 2019 17:40:38 -0400 Subject: fixed small pointer event bug with tooltip menu --- src/.DS_Store | Bin 6148 -> 6148 bytes src/client/util/TooltipTextMenu.scss | 3 ++- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/util') diff --git a/src/.DS_Store b/src/.DS_Store index 90213270f..d70e95c0a 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index 8fddbd3cf..a9a98c426 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -58,7 +58,7 @@ position: absolute; background: $dark-color; color:white; - border: 1px solid #aaa; + border: 1px solid rgb(223, 223, 223); padding: 2px; } @@ -246,6 +246,7 @@ margin-bottom: 7px; -webkit-transform: translateX(-50%); transform: translateX(-50%); + pointer-events: all; } .tooltipMenu:before { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 3869db41a..a28a8eaeb 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -38,7 +38,7 @@ export class TooltipTextMenu { this.tooltip.className = "tooltipMenu"; //add the div which is the tooltip - view.dom.parentNode!.appendChild(this.tooltip); + view.dom.parentNode!.parentNode!.appendChild(this.tooltip); //add additional icons library.add(faListUl); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 19ed65272..be530416e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -249,7 +249,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte return (
Date: Mon, 15 Apr 2019 18:53:25 -0400 Subject: updated list making and (un)indenting key commands) in prosemirror mapping --- src/client/util/ProsemirrorKeymap.ts | 8 ++++---- src/client/views/nodes/FormattedTextBox.tsx | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/ProsemirrorKeymap.ts b/src/client/util/ProsemirrorKeymap.ts index 7718b3c06..00d086b97 100644 --- a/src/client/util/ProsemirrorKeymap.ts +++ b/src/client/util/ProsemirrorKeymap.ts @@ -50,10 +50,10 @@ export default function buildKeymap>(schema: S, mapKeys?: } if (type = schema.nodes.bullet_list) { - bind("Shift-Ctrl-8", wrapInList(type)); + bind("Ctrl-b", wrapInList(type)); } if (type = schema.nodes.ordered_list) { - bind("Shift-Ctrl-9", wrapInList(type)); + bind("Ctrl-n", wrapInList(type)); } if (type = schema.nodes.blockquote) { bind("Ctrl->", wrapIn(type)); @@ -74,8 +74,8 @@ export default function buildKeymap>(schema: S, mapKeys?: } if (type = schema.nodes.list_item) { bind("Enter", splitListItem(type)); - bind("Mod-[", liftListItem(type)); - bind("Mod-]", sinkListItem(type)); + bind("Shift-Tab", liftListItem(type)); + bind("Tab", sinkListItem(type)); } if (type = schema.nodes.paragraph) { bind("Shift-Ctrl-0", setBlockType(type)); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index be530416e..7e72c6398 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -241,6 +241,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } onKeyPress(e: React.KeyboardEvent) { e.stopPropagation(); + if (e.keyCode === 9) e.preventDefault(); // stop propagation doesn't seem to stop propagation of native keyboard events. // so we set a flag on the native event that marks that the event's been handled. // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true; -- cgit v1.2.3-70-g09d2 From 1439ae372fb6a3cc136dffc0a9e9da3d839dfcff Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 15 Apr 2019 20:07:07 -0400 Subject: beginning linking tooltip --- src/client/util/TooltipLinkingMenu.tsx | 86 +++++++++++++++++++++++++++++ src/client/util/TooltipTextMenu.scss | 4 ++ src/client/views/nodes/FormattedTextBox.tsx | 18 +++++- 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/client/util/TooltipLinkingMenu.tsx (limited to 'src/client/util') diff --git a/src/client/util/TooltipLinkingMenu.tsx b/src/client/util/TooltipLinkingMenu.tsx new file mode 100644 index 000000000..55e0eb909 --- /dev/null +++ b/src/client/util/TooltipLinkingMenu.tsx @@ -0,0 +1,86 @@ +import { action, IReactionDisposer, reaction } from "mobx"; +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, TextSelection } from "prosemirror-state"; +import { EditorView } from "prosemirror-view"; +import { schema } from "./RichTextSchema"; +import { Schema, NodeType, MarkType } from "prosemirror-model"; +import React = require("react"); +import "./TooltipTextMenu.scss"; +const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { wrapInList, bulletList, liftListItem, listItem } from 'prosemirror-schema-list'; +import { + faListUl, +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { FieldViewProps } from "../views/nodes/FieldView"; +import { throwStatement } from "babel-types"; + +const SVG = "http://www.w3.org/2000/svg"; + +//appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. +export class TooltipLinkingMenu { + + private tooltip: HTMLElement; + private view: EditorView; + private editorProps: FieldViewProps; + + constructor(view: EditorView, editorProps: FieldViewProps) { + this.view = view; + this.editorProps = editorProps; + this.tooltip = document.createElement("div"); + this.tooltip.className = "tooltipMenu linking"; + + //add the div which is the tooltip + view.dom.parentNode!.parentNode!.appendChild(this.tooltip); + + let target = "https://www.google.com"; + + let link = document.createElement("a"); + link.href = target; + link.textContent = target; + link.target = "_blank"; + link.style.color = "white"; + this.tooltip.appendChild(link); + + this.update(view, undefined); + } + + //updates the tooltip menu when the selection changes + update(view: EditorView, lastState: EditorState | undefined) { + let state = view.state; + // Don't do anything if the document/selection didn't change + if (lastState && lastState.doc.eq(state.doc) && + lastState.selection.eq(state.selection)) return; + + // Hide the tooltip if the selection is empty + if (state.selection.empty) { + this.tooltip.style.display = "none"; + return; + } + + console.log("STORED:"); + console.log(state.doc.content.firstChild!.content); + + // Otherwise, reposition it and update its content + this.tooltip.style.display = ""; + let { from, to } = state.selection; + let start = view.coordsAtPos(from), end = view.coordsAtPos(to); + // The box in which the tooltip is positioned, to use as base + let box = this.tooltip.offsetParent!.getBoundingClientRect(); + // Find a center-ish x position from the selection endpoints (when + // crossing lines, end may be more to the left) + let left = Math.max((start.left + end.left) / 2, start.left + 3); + this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; + let mid = Math.min(start.left, end.left) + width; + + this.tooltip.style.width = "auto"; + this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + } + + destroy() { this.tooltip.remove(); } +} diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index a9a98c426..3ca3431c0 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -67,6 +67,10 @@ min-width: 6em; } + .linking { + text-align: center; + } + .ProseMirror-menu-dropdown-item { cursor: pointer; padding: 2px 8px 2px 4px; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7e72c6398..6eedf7561 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -19,6 +19,7 @@ import { undoItem } from "prosemirror-menu"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { TextField } from "../../../fields/TextField"; import { KeyStore } from "../../../fields/KeyStore"; +import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -86,7 +87,8 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte history(), keymap(buildKeymap(schema)), keymap(baseKeymap), - this.tooltipMenuPlugin(), + this.tooltipTextMenuPlugin(), + // this.tooltipLinkingMenuPlugin(), new Plugin({ props: { attributes: { class: "ProseMirror-example-setup-style" } @@ -94,7 +96,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte }) ] : [ history(), - keymap({ "Mod-z": undo, "Mod-y": redo }), + keymap(buildKeymap(schema)), keymap(baseKeymap), ] }; @@ -231,7 +233,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte e.stopPropagation(); } - tooltipMenuPlugin() { + tooltipTextMenuPlugin() { let myprops = this.props; return new Plugin({ view(_editorView) { @@ -239,6 +241,16 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } }); } + + tooltipLinkingMenuPlugin() { + let myprops = this.props; + return new Plugin({ + view(_editorView) { + return new TooltipLinkingMenu(_editorView, myprops); + } + }); + } + onKeyPress(e: React.KeyboardEvent) { e.stopPropagation(); if (e.keyCode === 9) e.preventDefault(); -- cgit v1.2.3-70-g09d2 From c93d46a0d0692569d3a3a2a30c909d9ecbc40830 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 15 Apr 2019 20:07:37 -0400 Subject: added a font size indicator --- src/client/util/RichTextSchema.tsx | 7 ++ src/client/util/TooltipTextMenu.scss | 6 +- src/client/util/TooltipTextMenu.tsx | 126 +++++++++++++++++++--------- src/client/views/nodes/FormattedTextBox.tsx | 1 - 4 files changed, 100 insertions(+), 40 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 42bcf2ae2..9ef71e305 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -267,6 +267,13 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + crimson: { + parseDOM: [{ style: 'font-family: "Crimson Text", sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Crimson Text", sans-serif;' + }] + }, + /** FONT SIZES */ p10: { diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index a9a98c426..7e6659a52 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -289,4 +289,8 @@ .underline {text-decoration: underline} .superscript {vertical-align:super} .subscript { vertical-align:sub } - .strikethrough {text-decoration-line:line-through} \ No newline at end of file + .strikethrough {text-decoration-line:line-through} + .font-size-indicator { + font-size: 12px; + padding-right: 0px; + } diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a28a8eaeb..a92cbd263 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -30,9 +30,14 @@ export class TooltipTextMenu { private fontStyles: MarkType[]; private fontSizes: MarkType[]; private editorProps: FieldViewProps; + private state: EditorState; + private fontSizeToNum: Map; + private fontStylesToName: Map; + private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; + this.state = view.state; this.editorProps = editorProps; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; @@ -66,25 +71,28 @@ export class TooltipTextMenu { }); - //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, - ]; + //list of font styles + this.fontStylesToName = new Map(); + this.fontStylesToName.set(schema.marks.timesNewRoman, "Times New Roman"); + this.fontStylesToName.set(schema.marks.arial, "Arial"); + this.fontStylesToName.set(schema.marks.georgia, "Georgia"); + this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans"); + this.fontStylesToName.set(schema.marks.tahoma, "Tahoma"); + this.fontStylesToName.set(schema.marks.impact, "Impact"); + this.fontStylesToName.set(schema.marks.crimson, "Crimson Text"); + this.fontStyles = Array.from(this.fontStylesToName.keys()); + + //font sizes + this.fontSizeToNum = new Map(); + this.fontSizeToNum.set(schema.marks.p10, 10); + this.fontSizeToNum.set(schema.marks.p12, 12); + this.fontSizeToNum.set(schema.marks.p16, 16); + this.fontSizeToNum.set(schema.marks.p24, 24); + this.fontSizeToNum.set(schema.marks.p32, 32); + this.fontSizeToNum.set(schema.marks.p48, 48); + this.fontSizeToNum.set(schema.marks.p72, 72); + this.fontSizes = Array.from(this.fontSizeToNum.keys()); + this.addFontDropdowns(); this.update(view, undefined); @@ -94,30 +102,29 @@ export class TooltipTextMenu { 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), - ]; + //font STYLES + let fontBtns: MenuItem[] = []; + this.fontStylesToName.forEach((name, mark) => { + fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 120px;", mark, 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), - ]; + //font size indicator + this.fontSizeIndicator = this.icon("12", "font-size-indicator"); + + //font SIZES + let fontSizeBtns: MenuItem[] = []; + this.fontSizeToNum.forEach((number, mark) => { + fontSizeBtns.push(this.dropdownBtn(String(number), "width: 50px;", mark, 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; + let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white; margin-left: -6px;" }) as MenuItem; this.tooltip.appendChild(dd_fontStyle.render(this.view).dom); + this.tooltip.appendChild(this.fontSizeIndicator); this.tooltip.appendChild(dd_fontSize.render(this.view).dom); + dd_fontStyle.render(this.view).dom.nodeValue = "TEST"; + console.log(dd_fontStyle.render(this.view).dom.nodeValue); } //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text @@ -169,7 +176,7 @@ export class TooltipTextMenu { // Helper function to create menu icons icon(text: string, name: string) { let span = document.createElement("span"); - span.className = "menuicon " + name; + span.className = name + " menuicon"; span.title = name; span.textContent = text; span.style.color = "white"; @@ -241,6 +248,49 @@ export class TooltipTextMenu { this.tooltip.style.width = 220 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + + let activeStyles = this.activeMarksOnSelection(this.fontStyles); + if (activeStyles.length === 1) { + // if we want to update something somewhere with active font name + let fontName = this.fontStylesToName.get(activeStyles[0]); + } else if (activeStyles.length === 0) { + //crimson on default + } + + //update font size indicator + let activeSizes = this.activeMarksOnSelection(this.fontSizes); + if (activeSizes.length === 1) { //if there's only one active font size + let size = this.fontSizeToNum.get(activeSizes[0]); + if (size) { + this.fontSizeIndicator.innerHTML = String(size); + } + //should be 14 on default + } else if (activeSizes.length === 0) { + this.fontSizeIndicator.innerHTML = "14"; + //multiple font sizes selected + } else { + this.fontSizeIndicator.innerHTML = ""; + } + } + + //finds all active marks on selection + activeMarksOnSelection(markGroup: MarkType[]) { + //current selection + let { empty, $cursor, ranges } = this.view.state.selection as TextSelection; + let state = this.view.state; + let dispatch = this.view.dispatch; + + let activeMarks = markGroup.filter(mark => { + if (dispatch) { + let has = false, tr = state.tr; + for (let i = 0; !has && i < ranges.length; i++) { + let { $from, $to } = ranges[i]; + return state.doc.rangeHasMark($from.pos, $to.pos, mark); + } + } + return false; + }); + return activeMarks; } destroy() { this.tooltip.remove(); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index be530416e..631139d32 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -177,7 +177,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte // doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { - console.log("pointer down"); if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { console.log("first"); e.stopPropagation(); -- cgit v1.2.3-70-g09d2 From feae8f4d314ef389cc544fd3ad0792a6bb04832c Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 16 Apr 2019 12:38:42 -0400 Subject: fixed some text focus issues. fixed contextmenu a bit. removed upload files. --- package.json | 2 +- src/client/util/SelectionManager.ts | 14 ++++++ src/client/views/MainOverlayTextBox.tsx | 1 - src/client/views/_global_variables.ts | 8 --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/FormattedTextBox.scss | 6 ++- src/client/views/nodes/FormattedTextBox.tsx | 55 ++++++++++----------- .../upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg | Bin 26946 -> 0 bytes .../upload_1f1c6cfef33e5992fa860802e8c466a7.jpg | Bin 45309 -> 0 bytes .../upload_2045f363aa9cf281407703ca242aad1a.jpg | Bin 9009 -> 0 bytes .../upload_25bffd90c080c27f5ac822984406b958.jpg | Bin 43534 -> 0 bytes .../upload_261f11dc39ad568212b5c7e39d1e6d13.jpg | Bin 27259 -> 0 bytes .../upload_26bcc62639141ba64e603daebb5bf5d3.png | Bin 2757327 -> 0 bytes .../upload_2d77d0773612e4723b78118ac50a2929.jpg | Bin 1805512 -> 0 bytes .../upload_2de9ad4dc687c53760c39f724c9a08a5.jpg | Bin 77462 -> 0 bytes .../upload_4abb568aa7cce9d291532c3d0da97102.jpg | Bin 22445 -> 0 bytes .../upload_54c34aaca5a7bf510cebad461ec39512.png | Bin 2757327 -> 0 bytes .../upload_562b1e527300df8b350eeab094b3e1f1.jpg | Bin 15988 -> 0 bytes .../upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg | Bin 45025 -> 0 bytes .../upload_70fa5e0c3f393504349d5865e28f4cac.jpg | Bin 18041 -> 0 bytes .../upload_8155b5b0f57da107bb07083c04e78943.jpg | Bin 31103 -> 0 bytes .../upload_88f588574e0efc415186af935114af9a.jpg | Bin 40249 -> 0 bytes .../upload_8d1c253f93f77c69c0c04ae3efb7d714.png | Bin 2757327 -> 0 bytes .../upload_9ef80158609f5ff739087aecad367b9d.jpg | Bin 28523 -> 0 bytes .../upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg | Bin 13811 -> 0 bytes .../upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg | Bin 28566 -> 0 bytes .../upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg | Bin 21995 -> 0 bytes .../upload_cec1cfcc67cfe5889de4098a49fec45e.jpg | Bin 22125 -> 0 bytes .../upload_f27688fe92dc7de398e957e5d96e1a22.jpg | Bin 18964 -> 0 bytes 30 files changed, 48 insertions(+), 43 deletions(-) delete mode 100644 src/client/views/_global_variables.ts delete mode 100644 src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg delete mode 100644 src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg delete mode 100644 src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg delete mode 100644 src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg delete mode 100644 src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg delete mode 100644 src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png delete mode 100644 src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg delete mode 100644 src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg delete mode 100644 src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg delete mode 100644 src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png delete mode 100644 src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg delete mode 100644 src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg delete mode 100644 src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg delete mode 100644 src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg delete mode 100644 src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg delete mode 100644 src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png delete mode 100644 src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg delete mode 100644 src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg delete mode 100644 src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg delete mode 100644 src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg delete mode 100644 src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg delete mode 100644 src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg (limited to 'src/client/util') diff --git a/package.json b/package.json index 489bce7e1..2463afa74 100644 --- a/package.json +++ b/package.json @@ -170,4 +170,4 @@ "uuid": "^3.3.2", "xoauth2": "^1.2.0" } -} \ No newline at end of file +} diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index c56f6a4ff..320553952 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -28,6 +28,16 @@ export namespace SelectionManager { manager.SelectedDocuments = []; MainOverlayTextBox.Instance.SetTextDoc(); } + @action + ReselectAll() { + let sdocs = manager.SelectedDocuments.map(d => d); + manager.SelectedDocuments = []; + return sdocs; + } + @action + ReselectAll2(sdocs: DocumentView[]) { + sdocs.map(s => SelectionManager.SelectDoc(s, false)); + } } const manager = new Manager(); @@ -52,6 +62,10 @@ export namespace SelectionManager { if (found) manager.SelectDoc(found, false); } + export function ReselectAll() { + let sdocs = manager.ReselectAll(); + manager.ReselectAll2(sdocs); + } export function SelectedDocuments(): Array { return manager.SelectedDocuments; } diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 422a45d59..141b3ad74 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -40,7 +40,6 @@ export class MainOverlayTextBox extends React.Component this._textTargetDiv.style.color = this._textColor; } - this.TextDoc = undefined; this.TextDoc = textDoc; this._textFieldKey = textFieldKey!; this._textXf = tx ? tx : Transform.Identity(); diff --git a/src/client/views/_global_variables.ts b/src/client/views/_global_variables.ts deleted file mode 100644 index 10482bc8d..000000000 --- a/src/client/views/_global_variables.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as globalStyleVariables from "../views/globalCssVariables.scss" - -export interface I_globalScss { - contextMenuZindex: string; // context menu shows up over everything -} -let globalStyles = globalStyleVariables as any as I_globalScss; - -export default globalStyles; \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fa3017258..50f0a6164 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -81,7 +81,6 @@ export class CollectionFreeFormView extends CollectionSubView { de.data.droppedDocuments.map(d => { d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX)); d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY)); - console.log("x = " + d.GetNumber(KeyStore.X, 0) + " y = " + d.GetNumber(KeyStore.X, 0)); if (!d.GetNumber(KeyStore.Width, 0)) { d.SetNumber(KeyStore.Width, 300); } @@ -90,6 +89,7 @@ export class CollectionFreeFormView extends CollectionSubView { } this.bringToFront(d); }); + SelectionManager.ReselectAll(); } return true; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0d974c97e..1cbb24223 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -277,11 +277,12 @@ export class DocumentView extends React.Component { @action onContextMenu = (e: React.MouseEvent): void => { e.stopPropagation(); - e.preventDefault(); if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 || e.isDefaultPrevented()) { + e.preventDefault(); return; } + e.preventDefault(); !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: this.minimize }); ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 3978c3d38..5eb2bf7ce 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -10,7 +10,7 @@ outline: none !important; } -.formattedTextBox-cont { +.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden { background: $light-color-secondary; padding: 0.9em; border-width: 0px; @@ -24,6 +24,10 @@ height: 100%; pointer-events: all; } +.formattedTextBox-cont-hidden { + overflow: hidden; + pointer-events: none; +} .menuicon { display: inline-block; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index c380ef650..bff8ca7a4 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,27 +1,24 @@ -import { action, IReactionDisposer, reaction, trace, computed } from "mobx"; +import { action, IReactionDisposer, reaction } from "mobx"; import { baseKeymap } from "prosemirror-commands"; -import { history, redo, undo } from "prosemirror-history"; +import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { FieldWaiting, Opt } from "../../../fields/Field"; +import { KeyStore } from "../../../fields/KeyStore"; import { RichTextField } from "../../../fields/RichTextField"; +import { TextField } from "../../../fields/TextField"; +import { Document } from "../../../fields/Document"; +import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { Schema } from "prosemirror-model"; import { schema } from "../../util/RichTextSchema"; +import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { ContextMenu } from "../../views/ContextMenu"; -import { Main } from "../Main"; +import { MainOverlayTextBox } from "../MainOverlayTextBox"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); -import { undoItem } from "prosemirror-menu"; -import buildKeymap from "../../util/ProsemirrorKeymap"; -import { TextField } from "../../../fields/TextField"; -import { KeyStore } from "../../../fields/KeyStore"; -import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; -import { MainOverlayTextBox } from "../MainOverlayTextBox"; -import { observer } from "mobx-react"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -52,6 +49,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } private _ref: React.RefObject; private _editorView: Opt; + private _gotDown: boolean = false; private _reactionDisposer: Opt; private _inputReactionDisposer: Opt; private _proxyReactionDisposer: Opt; @@ -109,8 +107,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte if (this._editorView) { this._editorView.destroy(); } - - this.setupEditor(config); + this.setupEditor(config, MainOverlayTextBox.Instance.TextDoc); // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox } ); } else { @@ -131,20 +128,18 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } } ); - this.setupEditor(config); + this.setupEditor(config, this.props.Document); } - private setupEditor(config: any) { - let state: EditorState; - let field = this.props.Document ? this.props.Document.GetT(this.props.fieldKey, RichTextField) : undefined; - if (field && field !== FieldWaiting && field.Data) { - state = EditorState.fromJSON(config, JSON.parse(field.Data)); - } else { - state = EditorState.create(config); - } + shouldComponentUpdate() { + return false; + } + + private setupEditor(config: any, doc?: Document) { + let field = doc ? doc.GetT(this.props.fieldKey, RichTextField) : undefined; if (this._ref.current) { this._editorView = new EditorView(this._ref.current, { - state, + state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction }); } @@ -170,10 +165,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } } - shouldComponentUpdate() { - return false; - } - @action onChange(e: React.ChangeEvent) { const { fieldKey, Document } = this.props; @@ -186,6 +177,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte e.stopPropagation(); } if (e.button === 2) { + this._gotDown = true; console.log("second"); e.preventDefault(); } @@ -211,6 +203,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte textCapability = (e: React.MouseEvent): void => { }; specificContextMenu = (e: React.MouseEvent): void => { + if (!this._gotDown) { + e.preventDefault(); + return; + } ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability @@ -262,10 +258,9 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true; } render() { + let style = this.props.isSelected() || this.props.isOverlay ? "scroll" : "hidden"; return ( -
Date: Tue, 16 Apr 2019 18:23:49 -0400 Subject: font dropdowns update now, ui change and bug fix --- src/client/util/TooltipTextMenu.scss | 4 ++ src/client/util/TooltipTextMenu.tsx | 75 +++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 30 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index 5c2d66480..70d9ad772 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -35,6 +35,10 @@ cursor: pointer; position: relative; padding-right: 15px; + margin: 3px; + background: #333333; + border-radius: 3px; + text-align: center; } .ProseMirror-menu-dropdown-wrap { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a92cbd263..4f0eb7d63 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -34,6 +34,9 @@ export class TooltipTextMenu { private fontSizeToNum: Map; private fontStylesToName: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); + //dropdown doms + private fontSizeDom: Node; + private fontStyleDom: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; @@ -76,7 +79,7 @@ export class TooltipTextMenu { this.fontStylesToName.set(schema.marks.timesNewRoman, "Times New Roman"); this.fontStylesToName.set(schema.marks.arial, "Arial"); this.fontStylesToName.set(schema.marks.georgia, "Georgia"); - this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans"); + this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans MS"); this.fontStylesToName.set(schema.marks.tahoma, "Tahoma"); this.fontStylesToName.set(schema.marks.impact, "Impact"); this.fontStylesToName.set(schema.marks.crimson, "Crimson Text"); @@ -93,23 +96,15 @@ export class TooltipTextMenu { this.fontSizeToNum.set(schema.marks.p72, 72); this.fontSizes = Array.from(this.fontSizeToNum.keys()); - this.addFontDropdowns(); + //this.addFontDropdowns(); this.update(view, undefined); } - //adds font size and font style dropdowns - addFontDropdowns() { + //label of dropdown will change to given label + updateFontSizeDropdown(label: string) { //filtering function - might be unecessary let cut = (arr: MenuItem[]) => arr.filter(x => x); - //font STYLES - let fontBtns: MenuItem[] = []; - this.fontStylesToName.forEach((name, mark) => { - fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 120px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); - }); - - //font size indicator - this.fontSizeIndicator = this.icon("12", "font-size-indicator"); //font SIZES let fontSizeBtns: MenuItem[] = []; @@ -117,14 +112,32 @@ export class TooltipTextMenu { fontSizeBtns.push(this.dropdownBtn(String(number), "width: 50px;", mark, 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; margin-left: -6px;" }) as MenuItem; - this.tooltip.appendChild(dd_fontStyle.render(this.view).dom); - this.tooltip.appendChild(this.fontSizeIndicator); - this.tooltip.appendChild(dd_fontSize.render(this.view).dom); - dd_fontStyle.render(this.view).dom.nodeValue = "TEST"; - console.log(dd_fontStyle.render(this.view).dom.nodeValue); + if (this.fontSizeDom) { this.tooltip.removeChild(this.fontSizeDom); } + this.fontSizeDom = (new Dropdown(cut(fontSizeBtns), { + label: label, + css: "color:white; min-width: 60px; padding-left: 5px; margin-right: 0;" + }) as MenuItem).render(this.view).dom; + this.tooltip.appendChild(this.fontSizeDom); + } + + //label of dropdown will change to given label + updateFontStyleDropdown(label: string) { + //filtering function - might be unecessary + let cut = (arr: MenuItem[]) => arr.filter(x => x); + + //font STYLES + let fontBtns: MenuItem[] = []; + this.fontStylesToName.forEach((name, mark) => { + fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); + }); + + if (this.fontStyleDom) { this.tooltip.removeChild(this.fontStyleDom); } + this.fontStyleDom = (new Dropdown(cut(fontBtns), { + label: label, + css: "color:white; width: 125px; margin-left: -3px; padding-left: 2px;" + }) as MenuItem).render(this.view).dom; + + this.tooltip.appendChild(this.fontStyleDom); } //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text @@ -246,30 +259,32 @@ export class TooltipTextMenu { let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; let mid = Math.min(start.left, end.left) + width; - this.tooltip.style.width = 220 + "px"; + this.tooltip.style.width = 225 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + //UPDATE FONT STYLE DROPDOWN let activeStyles = this.activeMarksOnSelection(this.fontStyles); if (activeStyles.length === 1) { // if we want to update something somewhere with active font name let fontName = this.fontStylesToName.get(activeStyles[0]); + if (fontName) { this.updateFontStyleDropdown(fontName); } } else if (activeStyles.length === 0) { //crimson on default + this.updateFontStyleDropdown("Crimson Text"); + } else { + this.updateFontStyleDropdown("Various"); } - //update font size indicator + //UPDATE FONT SIZE DROPDOWN let activeSizes = this.activeMarksOnSelection(this.fontSizes); if (activeSizes.length === 1) { //if there's only one active font size let size = this.fontSizeToNum.get(activeSizes[0]); - if (size) { - this.fontSizeIndicator.innerHTML = String(size); - } - //should be 14 on default + if (size) { this.updateFontSizeDropdown(String(size) + " pt"); } } else if (activeSizes.length === 0) { - this.fontSizeIndicator.innerHTML = "14"; - //multiple font sizes selected - } else { - this.fontSizeIndicator.innerHTML = ""; + //should be 14 on default + this.updateFontSizeDropdown("14 pt"); + } else { //multiple font sizes selected + this.updateFontSizeDropdown("Various"); } } -- cgit v1.2.3-70-g09d2 From 1319573481868f2647259fce37cd15b35c3cafad Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 17 Apr 2019 12:07:55 -0400 Subject: fixed onactivechanged exception. restored preview region --- src/client/util/SelectionManager.ts | 4 ++-- src/client/views/Main.tsx | 2 +- src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/collections/CollectionBaseView.tsx | 8 ++++---- src/client/views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionSchemaView.tsx | 11 +++++------ .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 4 ++-- src/client/views/nodes/KeyValuePair.tsx | 2 +- 10 files changed, 19 insertions(+), 20 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 320553952..b15a93d9f 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -18,13 +18,13 @@ export namespace SelectionManager { if (manager.SelectedDocuments.indexOf(doc) === -1) { manager.SelectedDocuments.push(doc); - doc.props.onActiveChanged(true); + doc.props.whenActiveChanged(true); } } @action DeselectAll(): void { - manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)); + manager.SelectedDocuments.map(dv => dv.props.whenActiveChanged(false)); manager.SelectedDocuments = []; MainOverlayTextBox.Instance.SetTextDoc(); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 0469211fa..84fdeab92 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -190,7 +190,7 @@ export class Main extends React.Component { selectOnLoad={false} focus={emptyDocFunction} parentActive={returnTrue} - onActiveChanged={emptyFunction} + whenActiveChanged={emptyFunction} ContainingCollectionView={undefined} />}
} diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 141b3ad74..8cb01117c 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -101,7 +101,7 @@ export class MainOverlayTextBox extends React.Component return
this._textXf} focus={emptyDocFunction} /> + selectOnLoad={true} ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={() => this._textXf} focus={emptyDocFunction} />
; } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4fda38a26..a8b061b04 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -22,7 +22,7 @@ export interface CollectionRenderProps { removeDocument: (document: Document) => boolean; moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; active: () => boolean; - onActiveChanged: (isActive: boolean) => void; + whenActiveChanged: (isActive: boolean) => void; } export interface CollectionViewProps extends FieldViewProps { @@ -55,9 +55,9 @@ export class CollectionBaseView extends React.Component { //TODO should this be observable? private _isChildActive = false; - onActiveChanged = (isActive: boolean) => { + whenActiveChanged = (isActive: boolean) => { this._isChildActive = isActive; - this.props.onActiveChanged(isActive); + this.props.whenActiveChanged(isActive); } createsCycle(documentToAdd: Document, containerDocument: Document): boolean { @@ -184,7 +184,7 @@ export class CollectionBaseView extends React.Component { removeDocument: this.removeDocument, moveDocument: this.moveDocument, active: this.active, - onActiveChanged: this.onActiveChanged, + whenActiveChanged: this.whenActiveChanged, }; const viewtype = this.collectionViewType; return ( diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2b886adb6..9ec0b3aeb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -363,7 +363,7 @@ export class DockedFrameRenderer extends React.Component { isTopMost={true} selectOnLoad={false} parentActive={returnTrue} - onActiveChanged={emptyFunction} + whenActiveChanged={emptyFunction} focus={emptyDocFunction} ContainingCollectionView={undefined} />
; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 1defdba7e..15b7617ae 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -24,7 +24,7 @@ import { EditableView } from "../EditableView"; import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; -import { CollectionSubView } from "./CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -70,7 +70,6 @@ export class CollectionSchemaView extends CollectionSubView { @computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0); } - renderCell = (rowProps: CellInfo) => { let props: FieldViewProps = { Document: rowProps.value[0], @@ -83,7 +82,7 @@ export class CollectionSchemaView extends CollectionSubView { ScreenToLocalTransform: Transform.Identity, focus: emptyDocFunction, active: returnFalse, - onActiveChanged: emptyFunction, + whenActiveChanged: emptyFunction, }; let contents = ( @@ -285,7 +284,7 @@ export class CollectionSchemaView extends CollectionSubView { this._optionsActivated++; } - @observable previewScript: string = "this"; + @observable previewScript: string = ""; @action onPreviewScriptChange = (e: React.ChangeEvent) => { this.previewScript = e.currentTarget.value; @@ -299,7 +298,7 @@ export class CollectionSchemaView extends CollectionSubView { const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined; //all the keys/columns that will be displayed in the schema const allKeys = this.findAllDocumentKeys; - let doc: any = selected ? selected.Get(new Key(this.previewScript)) : undefined; + let doc: any = selected ? (this.previewScript ? selected.Get(new Key(this.previewScript)) : selected) : undefined; // let doc = CompileScript(this.previewScript, { this: selected }, true)(); let content = this._selectedIndex === -1 || !selected ? (null) : ( @@ -318,7 +317,7 @@ export class CollectionSchemaView extends CollectionSubView { ContainingCollectionView={this.props.CollectionView} focus={emptyDocFunction} parentActive={this.props.active} - onActiveChanged={this.props.onActiveChanged} /> : null} + whenActiveChanged={this.props.whenActiveChanged} /> : null}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 97708ce19..80322c900 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -248,7 +248,7 @@ export class CollectionFreeFormView extends CollectionSubView { ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, parentActive: this.props.active, - onActiveChanged: this.props.active, + whenActiveChanged: this.props.active, }; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b99e449be..d74f9fc57 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -39,7 +39,7 @@ export interface DocumentViewProps { focus: (doc: Document) => void; selectOnLoad: boolean; parentActive: () => boolean; - onActiveChanged: (isActive: boolean) => void; + whenActiveChanged: (isActive: boolean) => void; } export interface JsxArgs extends DocumentViewProps { Keys: { [name: string]: Key }; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ebd25f937..e9f6950ff 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -43,7 +43,7 @@ export interface FieldViewProps { moveDocument?: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; ScreenToLocalTransform: () => Transform; active: () => boolean; - onActiveChanged: (isActive: boolean) => void; + whenActiveChanged: (isActive: boolean) => void; focus: (doc: Document) => void; } @@ -95,7 +95,7 @@ export class FieldView extends React.Component { layoutKey={KeyStore.Layout} ContainingCollectionView={this.props.ContainingCollectionView} parentActive={this.props.active} - onActiveChanged={this.props.onActiveChanged} /> + whenActiveChanged={this.props.whenActiveChanged} /> ); } else if (field instanceof ListField) { diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 5d69f23b2..d480eb5af 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -48,7 +48,7 @@ export class KeyValuePair extends React.Component { isTopMost: false, selectOnLoad: false, active: returnFalse, - onActiveChanged: emptyFunction, + whenActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyDocFunction, }; -- cgit v1.2.3-70-g09d2 From 0bd545674070fe90836912c7171642cf09e82696 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Apr 2019 11:21:58 -0400 Subject: reenabled zoon fading. added Esc. --- src/client/util/DragManager.ts | 6 ++++-- src/client/util/SelectionManager.ts | 1 + src/client/views/Main.tsx | 17 ++++++++++++----- src/client/views/collections/CollectionBaseView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++------ .../views/nodes/CollectionFreeFormDocumentView.tsx | 20 ++++++++++---------- src/client/views/nodes/FormattedTextBox.tsx | 4 ++++ 7 files changed, 37 insertions(+), 24 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4bd654e15..64ea4342e 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -269,20 +269,22 @@ export namespace DragManager { ); }; - const abortDrag = () => { + AbortDrag = () => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); dragElements.map(dragElement => dragDiv.removeChild(dragElement)); eles.map(ele => (ele.hidden = false)); }; const upHandler = (e: PointerEvent) => { - abortDrag(); + AbortDrag(); FinishDrag(eles, e, dragData, options, finishDrag); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } + export let AbortDrag: () => void = emptyFunction; + function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { let removed = dragEles.map(dragEle => { let parent = dragEle.parentElement; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index b15a93d9f..20319dff9 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -3,6 +3,7 @@ import { DocumentView } from "../views/nodes/DocumentView"; import { Document } from "../../fields/Document"; import { Main } from "../views/Main"; import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; +import { DragManager } from "./DragManager"; export namespace SelectionManager { class Manager { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 5cae4fdaf..503a11b35 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -27,7 +27,7 @@ import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; import { Server } from '../Server'; -import { SetupDrag } from '../util/DragManager'; +import { SetupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; @@ -38,6 +38,7 @@ import "./Main.scss"; import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; +import { SelectionManager } from '../util/SelectionManager'; @observer @@ -84,11 +85,11 @@ export class Main extends React.Component { this.initEventListeners(); this.initAuthenticationRouters(); - try { - this.initializeNorthstar(); - } catch (e) { + // try { + // this.initializeNorthstar(); + // } catch (e) { - } + // } } componentDidMount() { window.onpopstate = this.onHistory; } @@ -111,6 +112,12 @@ export class Main extends React.Component { // window.addEventListener("pointermove", (e) => this.reportLocation(e)) window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler + window.addEventListener("keydown", (e) => { + if (e.key == "Escape") { + DragManager.AbortDrag(); + SelectionManager.DeselectAll() + } + }, false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", action(function (e: PointerEvent) { if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index a8b061b04..4755b2d57 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -90,7 +90,7 @@ export class CollectionBaseView extends React.Component { let props = this.props; var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); - if (this.isAnnotationOverlay) { + if (true || this.isAnnotationOverlay) { doc.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); } if (curPage >= 0) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 228fc937e..159db6279 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,5 @@ import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import Measure from "react-measure"; import { Document } from "../../../../fields/Document"; import { KeyStore } from "../../../../fields/KeyStore"; import { emptyFunction, returnFalse, returnOne } from "../../../../Utils"; @@ -49,9 +48,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.addDocument(newBox, false); } private addDocument = (newBox: Document, allowDuplicates: boolean) => { - if (this.isAnnotationOverlay) { - newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); - } + newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); return this.props.addDocument(this.bringToFront(newBox), false); } private selectDocuments = (docs: Document[]) => { @@ -187,14 +184,16 @@ export class CollectionFreeFormView extends CollectionSubView { // if (modes[e.deltaMode] === 'pixels') coefficient = 50; // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height?? let deltaScale = (1 - (e.deltaY / coefficient)); + if (deltaScale < 0) deltaScale = -deltaScale; if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling(); } let [x, y] = this.getTransform().transformPoint(e.clientX, e.clientY); let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); - this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); - this.setPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale); + let safeScale = Math.abs(localTransform.Scale); + this.props.Document.SetNumber(KeyStore.Scale, Math.abs(safeScale)); + this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); e.stopPropagation(); } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 8cf7a0dd2..97d53a47e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -66,22 +66,22 @@ export class CollectionFreeFormDocumentView extends React.Component 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; - // let fadeUp = .75 * 1800; - // let fadeDown = .075 * 1800; - // zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; + //var zoom = doc.GetNumber(KeyStore.Zoom, 1); + let transform = this.getTransform().scale(this.contentScaling()).inverse(); + var [sptX, sptY] = transform.transformPoint(0, 0); + let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); + let w = bptX - sptX; + //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; + let fadeUp = .75 * 1800; + let fadeDown = .075 * 1800; + zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; return (
Date: Thu, 18 Apr 2019 13:51:25 -0400 Subject: fixed workspace switching exception. started to refresh minimize functionality. --- src/client/util/DragManager.ts | 2 +- .../views/collections/CollectionDockingView.tsx | 11 +++++---- .../views/collections/CollectionTreeView.tsx | 9 +++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 10 +++++---- src/client/views/globalCssVariables.scss | 2 ++ src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +++++++++---- src/client/views/nodes/DocumentView.scss | 13 +++++------ src/client/views/nodes/DocumentView.tsx | 26 +++++++++++++++++----- src/fields/KeyStore.ts | 4 +++- 11 files changed, 76 insertions(+), 41 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 64ea4342e..426c9fc3d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -250,7 +250,7 @@ export namespace DragManager { dragData.aliasOnDrop = e.ctrlKey || e.altKey; } if (e.shiftKey) { - abortDrag(); + AbortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 39e27b601..e4c647635 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -19,7 +19,7 @@ import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { TextField } from "../../../fields/TextField"; import { ListField } from "../../../fields/ListField"; -import { thisExpression } from "babel-types"; +import { Transform } from '../../util/Transform' @observer export class CollectionDockingView extends React.Component { @@ -336,9 +336,12 @@ export class DockedFrameRenderer extends React.Component { } ScreenToLocalTransform = () => { - let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!.children[0].firstChild as HTMLElement); - scale = Utils.GetScreenTransform(this._mainCont.current!).scale; - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling()); + if (this._mainCont.current && this._mainCont.current.children) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!.children[0].firstChild as HTMLElement); + scale = Utils.GetScreenTransform(this._mainCont.current!).scale; + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling()); + } + return Transform.Identity(); } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 51a02fc25..e0387f4b4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,20 +1,17 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, trace } from "mobx"; +import { action, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { SetupDrag, DragManager } from "../../util/DragManager"; +import { DragManager, SetupDrag } from "../../util/DragManager"; import { EditableView } from "../EditableView"; -import "./CollectionTreeView.scss"; -import { CollectionView } from "./CollectionView"; -import * as globalCssVariables from "../../views/globalCssVariables.scss"; import { CollectionSubView } from "./CollectionSubView"; +import "./CollectionTreeView.scss"; import React = require("react"); -import { props } from 'bluebird'; export interface TreeViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 159db6279..af6819cd4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -71,20 +71,25 @@ export class CollectionFreeFormView extends CollectionSubView { @action drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { + console.log("DROP Aat " + de.x + " off " + de.data.xOffset); const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { - let dropX = de.data.droppedDocuments[0].GetNumber(KeyStore.X, 0); - let dropY = de.data.droppedDocuments[0].GetNumber(KeyStore.Y, 0); + let dragDoc = de.data.droppedDocuments[0]; + let dropX = dragDoc.GetNumber(KeyStore.X, 0); + let dropY = dragDoc.GetNumber(KeyStore.Y, 0); de.data.droppedDocuments.map(d => { + let minimized = d.GetBoolean(KeyStore.Minimized, false); d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX)); d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY)); - if (!d.GetNumber(KeyStore.Width, 0)) { - d.SetNumber(KeyStore.Width, 300); - } - if (!d.GetNumber(KeyStore.Height, 0)) { - let nw = d.GetNumber(KeyStore.NativeWidth, 0); - let nh = d.GetNumber(KeyStore.NativeHeight, 0); - d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + if (!minimized) { + if (!d.GetNumber(KeyStore.Width, 0)) { + d.SetNumber(KeyStore.Width, 300); + } + if (!d.GetNumber(KeyStore.Height, 0)) { + let nw = d.GetNumber(KeyStore.NativeWidth, 0); + let nh = d.GetNumber(KeyStore.NativeHeight, 0); + d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + } } this.bringToFront(d); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 65f461b27..8b94374fa 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -11,6 +11,7 @@ import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; +import { MINIMIZED_ICON_SIZE } from '../../../views/globalCssVariables.scss' import "./MarqueeView.scss"; import React = require("react"); @@ -207,11 +208,12 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { + let minimized = doc.GetBoolean(KeyStore.Minimized, false); var z = doc.GetNumber(KeyStore.Zoom, 1); - var x = doc.GetNumber(KeyStore.X, 0); - var y = doc.GetNumber(KeyStore.Y, 0); - var w = doc.Width() / z; - var h = doc.Height() / z; + var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0); + var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0); + var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z; + var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 5c8e9c8fc..f154f8158 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -23,7 +23,9 @@ $mainTextInput-zindex: 999; // then text input overlay so that it's context menu $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; +$MINIMIZED_ICON_SIZE:25; :export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; + MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index ed8573f41..cc77d987a 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -2,6 +2,7 @@ interface IGlobalScss { contextMenuZindex: string; // context menu shows up over everything COLLECTION_BORDER_WIDTH: string; + MINIMIZED_ICON_SIZE: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 97d53a47e..a3689414d 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,7 +17,7 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() - .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)) + .translate(-this.X, -this.Y) .scale(1 / this.contentScaling()).scale(1 / this.zoom) contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); - panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); + panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth(); + panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight(); @computed get docView() { @@ -64,6 +70,8 @@ export class CollectionFreeFormDocumentView extends React.Component; } + get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); } + render() { let zoomFade = 1; //var zoom = doc.GetNumber(KeyStore.Zoom, 1); diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 690ee50e8..85c305b5a 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -13,7 +13,6 @@ } .top { - background: #232323; height: 20px; cursor: pointer; } @@ -32,13 +31,13 @@ .documentView-node-topmost { background: white; } - .minimized-box { - height: 10px; - width: 10px; - border-radius: 2px; - background: $dark-color; - transform-origin: left top; + position: absolute; + left:0; + top:0; + width:$MINIMIZED_ICON_SIZE; + height:$MINIMIZED_ICON_SIZE; + transform-origin: left top; } .minimized-box:hover { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d74f9fc57..af52e44e1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,12 +1,13 @@ +import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faObjectGroup, faStickyNote, faFilePdf, faFilm, faImage } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { BooleanField } from "../../../fields/BooleanField"; import { Document } from "../../../fields/Document"; -import { Field, FieldWaiting, Opt } from "../../../fields/Field"; +import { Field, Opt } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { TextField } from "../../../fields/TextField"; import { ServerUtils } from "../../../server/ServerUtil"; import { emptyFunction, Utils } from "../../../Utils"; import { Documents } from "../../documents/Documents"; @@ -19,12 +20,19 @@ import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; +import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Document; @@ -216,6 +224,8 @@ export class DocumentView extends React.Component { @action public minimize = (): void => { this.props.Document.SetBoolean(KeyStore.Minimized, true); + this.props.Document.SetNumber(KeyStore.MinimizedX, 0); + this.props.Document.SetNumber(KeyStore.MinimizedY, 0); SelectionManager.DeselectAll(); } @@ -314,8 +324,14 @@ export class DocumentView extends React.Component { var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%"; if (this.isMinimized()) { - return
; + let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf : + this.layout.indexOf("ImageBox") !== -1 ? faImage : + this.layout.indexOf("Formatted") !== -1 ? faStickyNote : + this.layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return
+ +
} return (
Date: Thu, 18 Apr 2019 16:29:21 -0400 Subject: Update SelectionManager.ts --- src/client/util/SelectionManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 20319dff9..92d78696e 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -37,7 +37,7 @@ export namespace SelectionManager { } @action ReselectAll2(sdocs: DocumentView[]) { - sdocs.map(s => SelectionManager.SelectDoc(s, false)); + sdocs.map(s => SelectionManager.SelectDoc(s, true)); } } -- cgit v1.2.3-70-g09d2 From 64b062eab72e78776a78b9983c7ddcd7afde66b0 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Apr 2019 16:38:33 -0400 Subject: avoid exception --- src/client/util/DragManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 426c9fc3d..46658867b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -272,7 +272,7 @@ export namespace DragManager { AbortDrag = () => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + dragElements.map(dragElement => { if (dragElement.parentNode == dragDiv) dragDiv.removeChild(dragElement); }); eles.map(ele => (ele.hidden = false)); }; const upHandler = (e: PointerEvent) => { -- cgit v1.2.3-70-g09d2 From 374ab8b762b5286e91a6ca8a8516f21fd465db64 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 20 Apr 2019 03:55:11 -0400 Subject: some tweaks to iconifying. --- src/client/util/DocumentManager.ts | 14 +++++-- src/client/views/DocumentDecorations.tsx | 66 ++++++++++++++++++-------------- src/client/views/nodes/DocumentView.tsx | 66 ++++++++++++++++++++------------ 3 files changed, 89 insertions(+), 57 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 3b5a5b470..56669fb79 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -38,11 +38,17 @@ export class DocumentManager { toReturn = view; return; } - let docSrc = doc.GetT(KeyStore.Prototype, Document); - if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { - toReturn = view; - } }); + if (!toReturn) { + DocumentManager.Instance.DocumentViews.map(view => { + let doc = view.props.Document; + + let docSrc = doc.GetT(KeyStore.Prototype, Document); + if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { + toReturn = view; + } + }); + } return toReturn; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e68c4fe0f..32cf985ce 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from "mobx"; +import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Key } from "../../fields/Key"; import { KeyStore } from "../../fields/KeyStore"; @@ -17,6 +17,7 @@ import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); import { CompileScript } from "../util/Scripting"; import { IconBox } from "./nodes/IconBox"; +import { FieldValue, Field } from "../../fields/Field"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -33,6 +34,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _titleHeight = 20; private _linkButton = React.createRef(); private _linkerButton = React.createRef(); + private _downX = 0; + private _downY = 0; + @observable private _minimizedX = 0; + @observable private _minimizedY = 0; //@observable private _title: string = this._documents[0].props.Document.Title; @observable private _title: string = this._documents.length > 0 ? this._documents[0].props.Document.Title : ""; @observable private _fieldKey: Key = KeyStore.Title; @@ -179,13 +184,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.removeEventListener("pointerup", this.onCloseUp); } } - _downX = 0; - _downY = 0; + @action onMinimizeDown = (e: React.PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { this._downX = e.pageX; this._downY = e.pageY; + let selDoc = SelectionManager.SelectedDocuments()[0]; + let selDocPos = selDoc.props.ScreenToLocalTransform().scale(selDoc.props.ContentScaling()).inverse().transformPoint(0, 0); + this._minimizedX = selDocPos[0] + 12; + this._minimizedY = selDocPos[1] + 12; document.removeEventListener("pointermove", this.onMinimizeMove); document.addEventListener("pointermove", this.onMinimizeMove); document.removeEventListener("pointerup", this.onMinimizeUp); @@ -193,40 +201,49 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } - @observable _minimizedX = 0; - @observable _minimizedY = 0; @action onMinimizeMove = (e: PointerEvent): void => { e.stopPropagation(); let moved = Math.abs(e.pageX - this._downX) > 4 || Math.abs(e.pageY - this._downY) > 4; if (moved) { - this._iconifying = true; let selDoc = SelectionManager.SelectedDocuments()[0]; - let xf = selDoc.props.ScreenToLocalTransform().scale(selDoc.props.ContentScaling()).inverse().transformPoint(0, 0); - let snapped = Math.abs(e.pageX - xf[0]) < 20 && Math.abs(e.pageY - xf[1]) < 20; - this._minimizedX = snapped ? xf[0] + 12 : e.clientX; - this._minimizedY = snapped ? xf[1] + 12 : e.clientY; - this.moveMinDocs(); + let selDocPos = selDoc.props.ScreenToLocalTransform().scale(selDoc.props.ContentScaling()).inverse().transformPoint(0, 0); + let snapped = Math.abs(e.pageX - selDocPos[0]) < 20 && Math.abs(e.pageY - selDocPos[1]) < 20; + this._minimizedX = snapped ? selDocPos[0] + 4 : e.clientX; + this._minimizedY = snapped ? selDocPos[1] - 18 : e.clientY; + let selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd); + Promise.all(selectedDocs.map(async selDoc => await selDoc.getIconDoc())).then(minDocSet => + this.moveIconDocs(SelectionManager.SelectedDocuments()) + ); + this._iconifying = snapped; } } @action onMinimizeUp = (e: PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { - let dx = e.clientX - this._downX; - let dy = e.clientY - this._downY; - let tapped = Math.abs(dx) < 4 && Math.abs(dy) < 4 && !this._iconifying; document.removeEventListener("pointermove", this.onMinimizeMove); document.removeEventListener("pointerup", this.onMinimizeUp); - Promise.all(SelectionManager.SelectedDocuments().map(async selDoc => await selDoc.minimize())).then(() => { - !tapped && this.moveMinDocs(); - this._minimizedX = this._minimizedY = 0; + let selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd); + Promise.all(selectedDocs.map(async selDoc => await selDoc.getIconDoc())).then(minDocSet => { + let minDocs = minDocSet.filter(minDoc => minDoc instanceof Document).map(minDoc => minDoc as Document); + minDocs.map(minDoc => { + minDoc.SetNumber(KeyStore.X, minDocs[0].GetNumber(KeyStore.X, 0)); + minDoc.SetNumber(KeyStore.Y, minDocs[0].GetNumber(KeyStore.Y, 0)); + minDoc.SetData(KeyStore.LinkTags, minDocs, ListField); + if (this._iconifying && selectedDocs[0].props.removeDocument) { + selectedDocs[0].props.removeDocument(minDoc); + (minDoc.Get(KeyStore.MaximizedDoc, false) as Document)!.Set(KeyStore.MinimizedDoc, undefined); + } + }); + runInAction(() => this._minimizedX = this._minimizedY = 0); + if (!this._iconifying) selectedDocs[0].toggleIcon(); + this._iconifying = false; }); - this._iconifying = false; } } - moveMinDocs() { - SelectionManager.SelectedDocuments().map(selDoc => { + moveIconDocs(selViews: DocumentView[], minDocSet?: FieldValue[]) { + selViews.map(selDoc => { let minDoc = selDoc.props.Document.Get(KeyStore.MinimizedDoc); if (minDoc instanceof Document) { let zoom = selDoc.props.Document.GetNumber(KeyStore.Zoom, 1); @@ -416,17 +433,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (bounds.x === Number.MAX_VALUE || !seldoc) { return (null); } - let selpos = this._minimizedX !== 0 || this._minimizedY !== 0 ? - [this._minimizedX - 12 + (!this._iconifying ? 8 : 0), this._minimizedY - 12 + (!this._iconifying ? 28 : 0)] : - [0, this._iconifying ? -18 : 0]; let minimizeIcon = ( -
+
{SelectionManager.SelectedDocuments().length == 1 ? IconBox.DocumentIcon(SelectionManager.SelectedDocuments()[0].props.Document.GetText(KeyStore.Layout, "...")) : "..."}
); - if (this._iconifying) { - return (
{minimizeIcon}
); - } if (this.Hidden) { return (null); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 44c71c24a..c47a56168 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -22,6 +22,8 @@ import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); import { TextField } from "../../../fields/TextField"; +import { string } from "prop-types"; +import { NumberField } from "../../../fields/NumberField"; export interface DocumentViewProps { ContainingCollectionView: Opt; @@ -81,6 +83,7 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { @observer export class DocumentView extends React.Component { + static _incompleteAnimations: Map = new Map(); private _downX: number = 0; private _downY: number = 0; private _mainCont = React.createRef(); @@ -184,7 +187,7 @@ export class DocumentView extends React.Component { this.props.Document.GetTAsync(KeyStore.MaximizedDoc, Document).then(maxdoc => { if (maxdoc instanceof Document) { this.props.addDocument && this.props.addDocument(maxdoc, false); - this.toggleMinimize(maxdoc, this.props.Document); + this.toggleIcon(); } else SelectionManager.SelectDoc(this, e.ctrlKey); }); @@ -219,9 +222,12 @@ export class DocumentView extends React.Component { @action createIcon = (layoutString: string): Document => { let iconDoc = Documents.IconDocument(layoutString); + iconDoc.SetText(KeyStore.Title, "ICON" + this.props.Document.Title) iconDoc.SetBoolean(KeyStore.IsMinimized, false); iconDoc.SetNumber(KeyStore.NativeWidth, 0); iconDoc.SetNumber(KeyStore.NativeHeight, 0); + iconDoc.SetNumber(KeyStore.X, this.props.Document.GetNumber(KeyStore.X, 0)); + iconDoc.SetNumber(KeyStore.Y, this.props.Document.GetNumber(KeyStore.Y, 0) - 24); iconDoc.Set(KeyStore.Prototype, this.props.Document); iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document); this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc); @@ -229,7 +235,7 @@ export class DocumentView extends React.Component { return iconDoc; } - animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) { + animateBetweenIcon(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) { setTimeout(() => { let now = Date.now(); let progress = Math.min(1, (now - stime) / 200); @@ -241,7 +247,7 @@ export class DocumentView extends React.Component { target.SetNumber(KeyStore.X, pval[0]); target.SetNumber(KeyStore.Y, pval[1]); if (now < stime + 200) { - this.animateTransition(icon, targ, width, height, stime, target, maximizing); + this.animateBetweenIcon(icon, targ, width, height, stime, target, maximizing); } else { if (!maximizing) { @@ -251,43 +257,53 @@ export class DocumentView extends React.Component { target.SetNumber(KeyStore.Width, width); target.SetNumber(KeyStore.Height, height); } - this._completed = true; + DocumentView._incompleteAnimations.set(target.Id, false); } }, 2); } - _completed = true; - @action - public toggleMinimize = (maximized: Document, minim: Document): void => { + public toggleIcon = async (): Promise => { SelectionManager.DeselectAll(); - if (maximized instanceof Document && this._completed) { - this._completed = false; - let minimized = maximized.GetBoolean(KeyStore.IsMinimized, false); - maximized.SetBoolean(KeyStore.IsMinimized, false); - this.animateTransition( - [minim.GetNumber(KeyStore.X, 0), minim.GetNumber(KeyStore.Y, 0)], - [maximized.GetNumber(KeyStore.X, 0), maximized.GetNumber(KeyStore.Y, 0)], - maximized.GetNumber(KeyStore.Width, 0), maximized.GetNumber(KeyStore.Height, 0), - Date.now(), maximized, minimized); - } + let isMinimized: boolean | undefined; + let minDoc = await this.props.Document.GetTAsync(KeyStore.MinimizedDoc, Document); + if (!minDoc) return; + let minimizedDocSet = await minDoc.GetTAsync(KeyStore.LinkTags, ListField); + if (!minimizedDocSet) return; + minimizedDocSet.Data.map(async minimizedDoc => { + if (minimizedDoc instanceof Document) { + this.props.addDocument && this.props.addDocument(minimizedDoc, false); + let maximizedDoc = await minimizedDoc.GetTAsync(KeyStore.MaximizedDoc, Document); + if (maximizedDoc instanceof Document && !DocumentView._incompleteAnimations.get(maximizedDoc.Id)) { + DocumentView._incompleteAnimations.set(maximizedDoc.Id, true); + isMinimized = isMinimized === undefined ? maximizedDoc.GetBoolean(KeyStore.IsMinimized, false) : isMinimized; + maximizedDoc.SetBoolean(KeyStore.IsMinimized, false); + let minx = await minimizedDoc.GetTAsync(KeyStore.X, NumberField); + let miny = await minimizedDoc.GetTAsync(KeyStore.Y, NumberField); + let maxx = await maximizedDoc.GetTAsync(KeyStore.X, NumberField); + let maxy = await maximizedDoc.GetTAsync(KeyStore.Y, NumberField); + let maxw = await maximizedDoc.GetTAsync(KeyStore.Width, NumberField); + let maxh = await maximizedDoc.GetTAsync(KeyStore.Height, NumberField); + if (minx !== undefined && miny !== undefined && maxx !== undefined && maxy !== undefined && + maxw !== undefined && maxh !== undefined) + this.animateBetweenIcon( + [minx.Data, miny.Data], [maxx.Data, maxy.Data], maxw.Data, maxh.Data, + Date.now(), maximizedDoc, isMinimized); + } + + } + }) } @action - public minimize = async (): Promise => { - let mindoc = await this.props.Document.GetTAsync(KeyStore.MinimizedDoc, Document).then(async mindoc => + public getIconDoc = async (): Promise => { + return await this.props.Document.GetTAsync(KeyStore.MinimizedDoc, Document).then(async mindoc => mindoc ? mindoc : await this.props.Document.GetTAsync(KeyStore.BackgroundLayout, TextField).then(async field => (field instanceof TextField) ? this.createIcon(field.Data) : await this.props.Document.GetTAsync(KeyStore.Layout, TextField).then(field => (field instanceof TextField) ? this.createIcon(field.Data) : undefined))); - - if (mindoc instanceof Document) { - this.props.addDocument && this.props.addDocument(mindoc, false); - this.toggleMinimize(this.props.Document, mindoc); - } - return mindoc; } @undoBatch -- cgit v1.2.3-70-g09d2