diff options
-rw-r--r-- | src/client/util/ProsemirrorKeymap.ts | 4 | ||||
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 103 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.scss | 76 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 89 | ||||
-rw-r--r-- | src/client/views/InkingControl.scss | 4 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 27 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 16 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 32 |
8 files changed, 236 insertions, 115 deletions
diff --git a/src/client/util/ProsemirrorKeymap.ts b/src/client/util/ProsemirrorKeymap.ts index 00d086b97..cf656dc17 100644 --- a/src/client/util/ProsemirrorKeymap.ts +++ b/src/client/util/ProsemirrorKeymap.ts @@ -1,4 +1,4 @@ -import { Schema } from "prosemirror-model"; +import { Schema, NodeType } from "prosemirror-model"; import { wrapIn, setBlockType, chainCommands, toggleMark, exitCode, joinUp, joinDown, lift, selectParentNode @@ -50,7 +50,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?: } if (type = schema.nodes.bullet_list) { - bind("Ctrl-b", wrapInList(type)); + bind("Ctrl-.", wrapInList(type)); } if (type = schema.nodes.ordered_list) { bind("Ctrl-n", wrapInList(type)); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3e3e98206..61ca4af5e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; -import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands'; +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType, Slice } from "prosemirror-model"; +import { joinUp, lift, setBlockType, toggleMark, wrapIn, selectNodeForward, deleteSelection } from 'prosemirror-commands'; import { redo, undo } from 'prosemirror-history'; import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list'; -import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; +import { EditorState, Transaction, NodeSelection, TextSelection, Selection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], @@ -26,6 +26,14 @@ export const nodes: { [index: string]: NodeSpec } = { toDOM() { return pDOM; } }, + // starmine: { + // inline: true, + // attrs: { oldtext: { default: "" } }, + // group: "inline", + // toDOM() { return ["star", "㊉"]; }, + // parseDOM: [{ tag: "star" }] + // }, + // :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks. blockquote: { content: "block+", @@ -77,6 +85,30 @@ export const nodes: { [index: string]: NodeSpec } = { group: "inline" }, + star: { + inline: true, + attrs: { + visibility: { default: false }, + oldtext: { default: undefined }, + oldtextslice: { default: undefined }, + oldtextlen: { default: 0 } + + }, + group: "inline", + toDOM(node) { + const attrs = { style: `width: 40px` }; + return ["span", { ...node.attrs, ...attrs }]; + }, + // parseDOM: [{ + // tag: "star", getAttrs(dom: any) { + // return { + // visibility: dom.getAttribute("visibility"), + // oldtext: dom.getAttribute("oldtext"), + // oldtextlen: dom.getAttribute("oldtextlen"), + // } + // } + // }] + }, // :: NodeSpec An inline image (`<img>`) node. Supports `src`, // `alt`, and `href` attributes. The latter two default to the empty // string. @@ -222,6 +254,15 @@ export const marks: { [index: string]: MarkSpec } = { toDOM: () => ['sup'] }, + collapse: { + parseDOM: [{ style: 'color: blue' }], + toDOM() { + return ['span', { + style: 'color: blue' + }] + } + }, + // :: MarkSpec Code font mark. Represented as a `<code>` element. code: { @@ -280,6 +321,7 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + /** FONT SIZES */ p10: { @@ -407,6 +449,49 @@ export class ImageResizeView { this._handle.style.display = "none"; } } + +export class SummarizedView { + // TODO: highlight text that is summarized. to find end of region, walk along mark + _collapsed: HTMLElement; + constructor(node: any, view: any, getPos: any) { + this._collapsed = document.createElement("span"); + this._collapsed.textContent = "㊉"; + this._collapsed.style.opacity = "0.5"; + // this._collapsed.style.background = "yellow"; + this._collapsed.style.position = "relative"; + this._collapsed.style.width = "40px"; + this._collapsed.style.height = "20px"; + this._collapsed.onpointerdown = function (e: any) { + console.log("star pressed!"); + if (node.attrs.visibility) { + node.attrs.visibility = !node.attrs.visibility; + console.log("content is visible"); + let y = getPos(); + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1 + node.attrs.oldtextlen))); + view.dispatch(view.state.tr.deleteSelection(view.state, () => { })); + //this._collapsed.textContent = "㊀"; + } else { + node.attrs.visibility = !node.attrs.visibility; + console.log("content is invisible"); + let y = getPos(); + let mark = view.state.schema.mark(view.state.schema.marks.underline); + console.log("PASTING " + node.attrs.oldtext.toString()); + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1))); + view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext).addMark(view.state.selection.from, view.state.selection.from + node.attrs.oldtextlen, mark)); + //this._collapsed.textContent = "㊉"; + } + e.preventDefault(); + e.stopPropagation(); + }; + (this as any).dom = this._collapsed; + + } + selectNode() { + } + + deselectNode() { + } +} // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, @@ -415,4 +500,14 @@ export class ImageResizeView { // // To reuse elements from this schema, extend or read from its // `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). -export const schema = new Schema({ nodes, marks });
\ No newline at end of file +export const schema = new Schema({ nodes, marks }); + +const fromJson = schema.nodeFromJSON; + +schema.nodeFromJSON = (json: any) => { + let node = fromJson(json); + if (json.type === "star") { + node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice); + } + return node; +}
\ No newline at end of file diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index 437da0d63..4d4eb386d 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -36,7 +36,7 @@ position: relative; padding-right: 15px; margin: 3px; - background: #333333; + background: white; border-radius: 3px; text-align: center; } @@ -69,6 +69,7 @@ .ProseMirror-menu-dropdown-menu { z-index: 15; min-width: 6em; + background: white; } .linking { @@ -82,7 +83,7 @@ } .ProseMirror-menu-dropdown-item:hover { - background: #2e2b2b; + background: white; } .ProseMirror-menu-submenu-wrap { @@ -132,7 +133,7 @@ position: relative; min-height: 1em; color: white; - padding: 1px 6px; + padding: 10px 10px; top: 0; left: 0; right: 0; border-bottom: 1px solid silver; background:$dark-color; @@ -155,7 +156,7 @@ } .ProseMirror-icon svg { - fill: currentColor; + fill:white; height: 1em; } @@ -184,7 +185,7 @@ position: fixed; border-radius: 3px; z-index: 11; - box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2); + box-shadow: -.5px 2px 5px white(255, 255, 255, 0.2); } .ProseMirror-prompt h5 { @@ -196,7 +197,7 @@ .ProseMirror-prompt input[type="text"], .ProseMirror-prompt textarea { - background: #eee; + background: white; border: none; outline: none; } @@ -233,15 +234,18 @@ .tooltipMenu { position: absolute; - z-index: 200; - background: $dark-color; + z-index: 50; + background: whitesmoke; border: 1px solid silver; - border-radius: 4px; + border-radius: 15px; padding: 2px 10px; - margin-bottom: 7px; - -webkit-transform: translateX(-50%); - transform: translateX(-50%); + //margin-bottom: 100px; + //-webkit-transform: translateX(-50%); + //transform: translateX(-50%); + transform: translateY(-50%); pointer-events: all; + height: auto; + width:inherit; .ProseMirror-example-setup-style hr { padding: 2px 10px; border: none; @@ -257,34 +261,34 @@ } } -.tooltipMenu:before { - content: ""; - height: 0; width: 0; - position: absolute; - left: 50%; - margin-left: -5px; - bottom: -6px; - border: 5px solid transparent; - border-bottom-width: 0; - border-top-color: silver; - } - .tooltipMenu:after { - content: ""; - height: 0; width: 0; - position: absolute; - left: 50%; - margin-left: -5px; - bottom: -4.5px; - border: 5px solid transparent; - border-bottom-width: 0; - border-top-color: $dark-color; - } +// .tooltipMenu:before { +// content: ""; +// height: 0; width: 0; +// position: absolute; +// left: 50%; +// margin-left: -5px; +// bottom: -6px; +// border: 5px solid transparent; +// border-bottom-width: 0; +// border-top-color: silver; +// } +// .tooltipMenu:after { +// content: ""; +// height: 0; width: 0; +// position: absolute; +// left: 50%; +// margin-left: -5px; +// bottom: -4.5px; +// border: 5px solid transparent; +// border-bottom-width: 0; +// border-top-color: $dark-color; +// } .menuicon { display: inline-block; - border-right: 1px solid rgba(0, 0, 0, 0.2); + border-right: 1px solid white(0, 0, 0, 0.2); //color: rgb(19, 18, 18); - color: white; + color: rgb(226, 21, 21); line-height: 1; padding: 0px 2px; margin: 1px; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index f517f757a..e12d4ed3c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,6 +1,6 @@ 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 { baseKeymap, lift, deleteSelection } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state"; @@ -22,12 +22,13 @@ import { throwStatement } from "babel-types"; import { View } from "@react-pdf/renderer"; import { DragManager } from "./DragManager"; import { Doc, Opt, Field } from "../../new_fields/Doc"; -import { Utils } from "../northstar/utils/Utils"; import { DocServer } from "../DocServer"; import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { DocumentManager } from "./DocumentManager"; import { Id } from "../../new_fields/FieldSymbols"; +import { Utils } from "../../Utils"; +// import { wrap } from "module"; const SVG = "http://www.w3.org/2000/svg"; @@ -68,12 +69,13 @@ export class TooltipTextMenu { library.add(faListUl); //add the buttons to the tooltip let items = [ - { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") }, - { command: toggleMark(schema.marks.em), dom: this.icon("i", "em") }, - { command: toggleMark(schema.marks.underline), dom: this.icon("U", "underline") }, - { 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") }, + { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong", "Bold") }, + { command: toggleMark(schema.marks.em), dom: this.icon("i", "em", "Italic") }, + { command: toggleMark(schema.marks.underline), dom: this.icon("U", "underline", "Underline") }, + { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough", "Strikethrough") }, + { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript", "Superscript") }, + { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript", "Subscript") }, + { command: deleteSelection, dom: this.icon("C", 'collapse', 'Collapse') } // { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, // { command: wrapInList(schema.nodes.ordered_list), dom: this.icon("1)", "bullets") }, // { command: lift, dom: this.icon("<", "lift") }, @@ -86,7 +88,10 @@ export class TooltipTextMenu { dom.addEventListener("pointerdown", e => { e.preventDefault(); view.focus(); - command(view.state, view.dispatch, view); + if (dom.contains(e.target as Node)) { + e.stopPropagation(); + command(view.state, view.dispatch, view); + } }); }); @@ -131,13 +136,13 @@ export class TooltipTextMenu { //font SIZES let fontSizeBtns: MenuItem[] = []; this.fontSizeToNum.forEach((number, mark) => { - fontSizeBtns.push(this.dropdownMarkBtn(String(number), "width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); + fontSizeBtns.push(this.dropdownMarkBtn(String(number), "color: black; width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); }); 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;" + css: "color:black; min-width: 60px; padding-left: 5px; margin-right: 0;" }) as MenuItem).render(this.view).dom; this.tooltip.appendChild(this.fontSizeDom); } @@ -150,13 +155,13 @@ export class TooltipTextMenu { //font STYLES let fontBtns: MenuItem[] = []; this.fontStylesToName.forEach((name, mark) => { - fontBtns.push(this.dropdownMarkBtn(name, "font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); + fontBtns.push(this.dropdownMarkBtn(name, "color: black; 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;" + css: "color:black; width: 125px; margin-left: -3px; padding-left: 2px;" }) as MenuItem).render(this.view).dom; this.tooltip.appendChild(this.fontStyleDom); @@ -165,7 +170,7 @@ export class TooltipTextMenu { updateLinkMenu() { if (!this.linkEditor || !this.linkText) { this.linkEditor = document.createElement("div"); - this.linkEditor.style.color = "white"; + this.linkEditor.style.color = "black"; this.linkText = document.createElement("div"); this.linkText.style.cssFloat = "left"; this.linkText.style.marginRight = "5px"; @@ -174,13 +179,13 @@ export class TooltipTextMenu { this.linkText.style.whiteSpace = "nowrap"; this.linkText.style.width = "150px"; this.linkText.style.overflow = "hidden"; - this.linkText.style.color = "white"; + this.linkText.style.color = "black"; this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); }; let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; - linkBtn.style.width = "20px"; - linkBtn.style.height = "20px"; - linkBtn.style.color = "white"; + linkBtn.style.width = "10px"; + linkBtn.style.height = "10px"; + linkBtn.style.color = "black"; linkBtn.style.cssFloat = "left"; linkBtn.onpointerdown = (e: PointerEvent) => { let node = this.view.state.selection.$from.nodeAfter; @@ -207,7 +212,7 @@ export class TooltipTextMenu { this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; this.linkDrag.style.width = "20px"; this.linkDrag.style.height = "20px"; - this.linkDrag.style.color = "white"; + this.linkDrag.style.color = "black"; this.linkDrag.style.background = "black"; this.linkDrag.style.cssFloat = "left"; this.linkDrag.onpointerdown = (e: PointerEvent) => { @@ -228,6 +233,22 @@ export class TooltipTextMenu { this.linkEditor.appendChild(this.linkText); this.linkEditor.appendChild(linkBtn); this.tooltip.appendChild(this.linkEditor); + + let starButton = document.createElement("span"); + // starButton.style.width = '10px'; + // starButton.style.height = '10px'; + starButton.style.marginLeft = '10px'; + starButton.textContent = "Summarize"; + starButton.style.color = 'black'; + starButton.style.height = '20px'; + starButton.style.backgroundColor = 'white'; + starButton.style.textAlign = 'center'; + starButton.onclick = () => { + let state = this.view.state; + this.insertStar(state, this.view.dispatch); + } + + this.tooltip.appendChild(starButton); } let node = this.view.state.selection.$from.nodeAfter; @@ -253,6 +274,16 @@ export class TooltipTextMenu { link = node && node.marks.find(m => m.type.name === "link"); } + insertStar(state: EditorState<any>, dispatch: any) { + console.log("creating star..."); + let newNode = schema.nodes.star.create({ visibility: false, oldtext: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from }); + if (dispatch) { + console.log(newNode.attrs.oldtext.toString()); + dispatch(state.tr.replaceSelectionWith(newNode)); + } + return true; + } + //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown updateListItemDropdown(label: string, listTypeBtn: Node) { //remove old btn @@ -261,14 +292,14 @@ export class TooltipTextMenu { //Make a dropdown of all list types let toAdd: MenuItem[] = []; this.listTypeToIcon.forEach((icon, type) => { - toAdd.push(this.dropdownNodeBtn(icon, "width: 40px;", type, this.view, this.listTypes, this.changeToNodeType)); + toAdd.push(this.dropdownNodeBtn(icon, "color: black; width: 40px;", type, this.view, this.listTypes, this.changeToNodeType)); }); //option to remove the list formatting - toAdd.push(this.dropdownNodeBtn("X", "width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType)); + toAdd.push(this.dropdownNodeBtn("X", "color: black; width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType)); listTypeBtn = (new Dropdown(toAdd, { label: label, - css: "color:white; width: 40px;" + css: "color:black; width: 40px;" }) as MenuItem).render(this.view).dom; //add this new button and return it @@ -349,12 +380,12 @@ export class TooltipTextMenu { } // Helper function to create menu icons - icon(text: string, name: string) { + icon(text: string, name: string, title: string = name) { let span = document.createElement("span"); span.className = name + " menuicon"; - span.title = name; + span.title = title; span.textContent = text; - span.style.color = "white"; + span.style.color = "black"; return span; } @@ -421,8 +452,14 @@ 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 = 225 + "px"; + //this.tooltip.style.width = 225 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + this.tooltip.style.top = "-100px"; + //this.tooltip.style.height = "100px"; + + // let transform = this.editorProps.ScreenToLocalTransform(); + // this.tooltip.style.width = `${225 / transform.Scale}px`; + // Utils //UPDATE LIST ITEM DROPDOWN this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!); diff --git a/src/client/views/InkingControl.scss b/src/client/views/InkingControl.scss index ba4ec41af..2c53dc031 100644 --- a/src/client/views/InkingControl.scss +++ b/src/client/views/InkingControl.scss @@ -1,8 +1,8 @@ @import "globalCssVariables"; .inking-control { position: absolute; - left: 70px; - bottom: 70px; + right: 0px; + bottom: 20px; margin: 0; padding: 0; display: flex; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 42d5929bf..4b328f286 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -221,33 +221,15 @@ export class MainView extends React.Component { nodesMenu() { let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; - let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c27211_sample_explain.pdf"; - let weburl = "https://cs.brown.edu/courses/cs166/"; - let audiourl = "http://techslides.com/demos/samples/sample.mp3"; - let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); let addColNode = action(() => Docs.FreeformDocument([], { width: this.pwidth * .7, height: this.pheight, title: "a freeform collection" })); - let addSchemaNode = action(() => Docs.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); let addTreeNode = action(() => CurrentUserUtils.UserDocument); - //let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); - // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); - let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); - let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [ - [React.createRef<HTMLDivElement>(), "font", "Add Textbox", addTextNode], [React.createRef<HTMLDivElement>(), "image", "Add Image", addImageNode], - [React.createRef<HTMLDivElement>(), "file-pdf", "Add PDF", addPDFNode], - [React.createRef<HTMLDivElement>(), "film", "Add Video", addVideoNode], - [React.createRef<HTMLDivElement>(), "music", "Add Audio", addAudioNode], - [React.createRef<HTMLDivElement>(), "globe-asia", "Add Web Clipping", addWebNode], [React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode], [React.createRef<HTMLDivElement>(), "tree", "Add Tree", addTreeNode], - [React.createRef<HTMLDivElement>(), "table", "Add Schema", addSchemaNode], ]; return < div id="add-nodes-menu" > @@ -256,12 +238,16 @@ export class MainView extends React.Component { <div id="add-options-content"> <ul id="add-options-list"> + <li key="search"><button className="add-button round-button" title="Search" onClick={this.toggleSearch}><FontAwesomeIcon icon="search" size="sm" /></button></li> + <li key="undo"><button className="add-button round-button" title="Undo" onClick={() => UndoManager.Undo()}><FontAwesomeIcon icon="undo-alt" size="sm" /></button></li> + <li key="redo"><button className="add-button round-button" title="Redo" onClick={() => UndoManager.Redo()}><FontAwesomeIcon icon="redo-alt" size="sm" /></button></li> {btns.map(btn => <li key={btn[1]} ><div ref={btn[0]}> <button className="round-button add-button" title={btn[2]} onPointerDown={SetupDrag(btn[0], btn[3])}> <FontAwesomeIcon icon={btn[1]} size="sm" /> </button> </div></li>)} + <li key="ink"><button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /></button></li> </ul> </div> </div >; @@ -276,7 +262,6 @@ export class MainView extends React.Component { let logoutRef = React.createRef<HTMLDivElement>(); return [ - <button className="clear-db-button" key="clear-db" onClick={e => e.shiftKey && e.altKey && DocServer.DeleteDatabase()}>Clear Database</button>, <div id="toolbar" key="toolbar"> <div ref={notifsRef}> <button className="toolbar-button round-button" title="Notifs" @@ -287,10 +272,6 @@ export class MainView extends React.Component { {length} </div> </div> - <button className="toolbar-button round-button" title="Search" onClick={this.toggleSearch}><FontAwesomeIcon icon="search" size="sm" /></button> - <button className="toolbar-button round-button" title="Undo" onClick={() => UndoManager.Undo()}><FontAwesomeIcon icon="undo-alt" size="sm" /></button> - <button className="toolbar-button round-button" title="Redo" onClick={() => UndoManager.Redo()}><FontAwesomeIcon icon="redo-alt" size="sm" /></button> - <button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /></button> </div >, this.isSearchVisible ? <div className="main-searchDiv" key="search" style={{ top: '34px', right: '1px', position: 'absolute' }} > <SearchBox /> </div> : null, <div className="main-buttonDiv" key="logout" style={{ bottom: '0px', right: '1px', position: 'absolute' }} ref={logoutRef}> diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 01bbbba4c..5f2a732b9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -45,12 +45,14 @@ export class MarqueeView extends React.Component<MarqueeViewProps> _commandExecuted = false; @action - cleanupInteractions = (all: boolean = false) => { + cleanupInteractions = (all: boolean = false, rem_keydown: boolean = true) => { if (all) { document.removeEventListener("pointerup", this.onPointerUp, true); document.removeEventListener("pointermove", this.onPointerMove, true); } - document.removeEventListener("keydown", this.marqueeCommand, true); + if (rem_keydown) { + document.removeEventListener("keydown", this.marqueeCommand, true); + } this._visible = false; } @@ -146,6 +148,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this._downY = this._lastY = e.pageY; this._commandExecuted = false; PreviewCursor.Visible = false; + this.cleanupInteractions(true); if (e.button === 2 || (e.button === 0 && e.altKey)) { if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]); document.addEventListener("pointermove", this.onPointerMove, true); @@ -181,14 +184,21 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @action onPointerUp = (e: PointerEvent): void => { + console.log("pointer up!"); if (this._visible) { + console.log("visible"); let mselect = this.marqueeSelect(); if (!e.shiftKey) { SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); + mselect.length ? this.cleanupInteractions(true, false) : this.cleanupInteractions(true); } - this.cleanupInteractions(true); + else { + console.log("invisible"); + this.cleanupInteractions(true); + } + if (e.altKey) { e.preventDefault(); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 6a51db4ac..6a490109f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -7,7 +7,7 @@ import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import { Doc, Opt } from "../../../new_fields/Doc"; +import { Doc, Field, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { Id } from '../../../new_fields/FieldSymbols'; import { RichTextField } from "../../../new_fields/RichTextField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; @@ -18,18 +18,21 @@ import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { ImageResizeView, schema } from "../../util/RichTextSchema"; +import { SummarizedView, ImageResizeView, schema } from "../../util/RichTextSchema"; import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; -import { UndoManager } from "../../util/UndoManager"; -import { ContextMenu } from '../ContextMenu'; -import { ContextMenuProps } from '../ContextMenuItem'; +import { undoBatch, UndoManager } from "../../util/UndoManager"; +import { ContextMenu } from "../../views/ContextMenu"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); +import { DocUtils } from '../../documents/Documents'; +import { start } from 'repl'; +import { ContextMenuProps } from '../ContextMenuItem'; library.add(faEdit); library.add(faSmile); @@ -174,7 +177,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, nodeViews: { - image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } + image(node, view, getPos) { return new ImageResizeView(node, view, getPos); }, + star(node, view, getPos) { return new SummarizedView(node, view, getPos); } } }); if (startup) { @@ -208,7 +212,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._toolTipTextMenu.tooltip.style.opacity = "0"; } } - this._linkClicked = ""; + let ctrlKey = e.ctrlKey; if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) { let href = (e.target as any).href; for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) { @@ -225,6 +229,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe e.stopPropagation(); e.preventDefault(); } + } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { e.preventDefault(); @@ -234,14 +239,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "1"; } - let ctrlKey = e.ctrlKey; - if (this._linkClicked) { - DocServer.GetRefField(this._linkClicked).then(f => { - (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")); - }); - e.stopPropagation(); - e.preventDefault(); - } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } @@ -265,10 +262,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onClick = (e: React.MouseEvent): void => { this._proseRef.current!.focus(); - if (this._linkClicked) { - e.preventDefault(); - e.stopPropagation(); - } } onMouseDown = (e: React.MouseEvent): void => { if (!this.props.isSelected()) { // preventing default allows the onClick to be generated instead of being swallowed by the text box itself @@ -368,6 +361,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseDown={this.onMouseDown} + // tfs: do we need this event handler onWheel={this.onPointerWheel} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} |