From dd9eda99662d1bfb921a8f1589c5f77ac9321172 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 21 Jun 2020 03:00:43 -0400 Subject: cleaned up lists in prosemirror. everything's an ordered_list now (even unordred lists). things are read back from the dom correctly to allow copy & paste. added prosemirror's dev tools. --- .../views/nodes/formattedText/FormattedTextBox.tsx | 52 +++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c23ecb8ac..82334688b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -15,6 +15,7 @@ import { EditorView } from "prosemirror-view"; import { DateField } from '../../../../fields/DateField'; import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclSym } from "../../../../fields/Doc"; import { documentSchema } from '../../../../fields/documentSchemas'; +import applyDevTools = require("prosemirror-dev-tools"); import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { PrefetchProxy } from '../../../../fields/Proxy'; @@ -57,6 +58,7 @@ import { FieldView, FieldViewProps } from "../FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); +import requestPromise = require('request-promise'); library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -488,6 +490,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }); !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); + this._downX = this._downY = Number.NaN; } recordDictation = () => { @@ -920,6 +923,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp clipboardTextSerializer: this.clipboardTextSerializer, handlePaste: this.handlePaste, }); + // applyDevTools.applyDevTools(this._editorView); const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field); if (startupText) { const { state: { tr }, dispatch } = this._editorView; @@ -1008,7 +1012,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) { e.stopPropagation(); } - this._downX = this._downY = Number.NaN; } @action @@ -1073,38 +1076,35 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. - hitBulletTargets(x: number, y: number, select: boolean, highlightOnly: boolean) { + hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean) { clearStyleSheetRules(FormattedTextBox._bulletStyleSheet); - const pos = this._editorView!.posAtCoords({ left: x, top: y }); - if (pos && this.props.isSelected(true)) { - // let beforeEle = document.querySelector("." + hit.className) as Element; // const before = hit ? window.getComputedStyle(hit, ':before') : undefined; - //const node = this._editorView!.state.doc.nodeAt(pos.pos); - const $pos = this._editorView!.state.doc.resolve(pos.pos); - let list_node = $pos.node().type === schema.nodes.list_item ? $pos.node() : undefined; - if ($pos.node().type === schema.nodes.ordered_list) { - for (let off = 1; off < 100; off++) { - const pos = this._editorView!.posAtCoords({ left: x + off, top: y }); - const node = pos && this._editorView!.state.doc.nodeAt(pos.pos); - if (node?.type === schema.nodes.list_item) { - list_node = node; - break; - } + const clickPos = this._editorView!.posAtCoords({ left: x, top: y }); + let olistPos = clickPos?.pos; + if (clickPos && olistPos && this.props.isSelected(true)) { + const clickNode = this._editorView?.state.doc.nodeAt(olistPos); + let nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1)); + olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos; + let $olistPos = this._editorView?.state.doc.resolve(olistPos); + let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef; + if (olistNode?.type === this._editorView?.state.schema.nodes.list_item) { + if ($olistPos && ($olistPos as any).path.length > 3) { + olistNode = $olistPos.parent; + $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]); } } - if (list_node && pos.inside >= 0 && this._editorView!.state.doc.nodeAt(pos.inside)!.attrs.bulletStyle === list_node.attrs.bulletStyle) { - if (select) { - const $olist_pos = this._editorView!.state.doc.resolve($pos.pos - $pos.parentOffset - 1); + const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos!); + if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list) { + if (!collapse) { if (!highlightOnly) { - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olist_pos))); + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olistPos!))); } - addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); - } else if (Math.abs(pos.pos - pos.inside) < 2) { + addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); + } else if (listNode && listNode.type === this._editorView.state.schema.nodes.list_item) { if (!highlightOnly) { - const offset = this._editorView!.state.doc.nodeAt(pos.inside)?.type === schema.nodes.ordered_list ? 1 : 0; - this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(pos.inside + offset, list_node.type, { ...list_node.attrs, visibility: !list_node.attrs.visibility })); - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pos.inside + offset))); + this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(clickPos.pos!, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility })); + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, clickPos.pos!))); } - addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); + addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } } } -- cgit v1.2.3-70-g09d2 From e81ad333750a86e4dae51907adc489a73d08437a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 11:19:00 -0400 Subject: cleaned up errors. added ctrl-a to select documents within a freeform collection. fixed ctrl-x to remove documents properly. fixed paste documents to clone only if copied. --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 14 ++++++----- src/client/views/PreviewCursor.tsx | 24 ++++++++++--------- .../CollectionFreeFormLinkView.tsx | 8 +++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 27 +++++++++++++++------- src/client/views/nodes/ImageBox.tsx | 8 +++---- src/client/views/nodes/KeyValueBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +++++----- src/client/views/nodes/formattedText/nodes_rts.ts | 2 +- 10 files changed, 58 insertions(+), 43 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d92fe5203..beb6155ca 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -175,7 +175,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } @undoBatch @action - onCloseClick = async (e: React.MouseEvent) => { + onCloseClick = async (e: React.MouseEvent | undefined) => { if (!e?.button) { const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc; const selected = SelectionManager.SelectedDocuments().slice(); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c696625db..27755737e 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -253,8 +253,8 @@ export default class KeyManager { case "x": if (SelectionManager.SelectedDocuments().length) { const bds = DocumentDecorations.Instance.Bounds; - const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2]; - const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); + const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); + const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); DocumentDecorations.Instance.onCloseClick(undefined); stopPropagation = false; @@ -265,7 +265,7 @@ export default class KeyManager { if (DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) { const bds = DocumentDecorations.Instance.Bounds; const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); - const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); + const text = `__DashCloneId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); stopPropagation = false; } @@ -280,10 +280,12 @@ export default class KeyManager { }); public paste(e: ClipboardEvent) { - if (e.clipboardData?.getData("text/plain") !== "" && e.clipboardData?.getData("text/plain").startsWith("__DashDocId(")) { + const plain = e.clipboardData?.getData("text/plain"); + const clone = plain?.startsWith("__DashCloneId("); + if (plain && (plain.startsWith("__DashDocId(") || clone)) { const first = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined; if (first?.props.Document.type === DocumentType.COL) { - const docids = e.clipboardData.getData("text/plain").split(":"); + const docids = plain.split(":"); let count = 1; const list: Doc[] = []; const targetDataDoc = Doc.GetProto(first.props.Document); @@ -295,7 +297,7 @@ export default class KeyManager { list.push(doc); } if (count === docids.length) { - const added = list.filter(d => !docList.includes(d)); + const added = list.filter(d => !docList.includes(d)).map(d => clone ? Doc.MakeClone(d) : d); if (added.length) { added.map(doc => doc.context = targetDataDoc); undoBatch(() => { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index dd65681d4..e27f6b95a 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -32,10 +32,11 @@ export class PreviewCursor extends React.Component<{}> { // tests for URL and makes web document const re: any = /^https?:\/\//g; - if (e.clipboardData.getData("text/plain") !== "") { + const plain = e.clipboardData.getData("text/plain"); + if (plain) { // tests for youtube and makes video document - if (e.clipboardData.getData("text/plain").indexOf("www.youtube.com/watch") !== -1) { - const url = e.clipboardData.getData("text/plain").replace("youtube.com/watch?v=", "youtube.com/embed/"); + if (plain.indexOf("www.youtube.com/watch") !== -1) { + const url = plain.replace("youtube.com/watch?v=", "youtube.com/embed/"); undoBatch(() => PreviewCursor._addDocument(Docs.Create.VideoDocument(url, { title: url, _width: 400, _height: 315, _nativeWidth: 600, _nativeHeight: 472.5, @@ -43,8 +44,8 @@ export class PreviewCursor extends React.Component<{}> { })))(); } - else if (re.test(e.clipboardData.getData("text/plain"))) { - const url = e.clipboardData.getData("text/plain"); + else if (re.test(plain)) { + const url = plain; undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, { title: url, _width: 500, _height: 300, UseCors: true, // nativeWidth: 300, nativeHeight: 472.5, @@ -52,10 +53,11 @@ export class PreviewCursor extends React.Component<{}> { })))(); } - else if (e.clipboardData.getData("text/plain").startsWith("__DashDocId(")) { - const docids = e.clipboardData.getData("text/plain").split(":"); + else if (plain.startsWith("__DashDocId(") || plain.startsWith("__DashCloneId(")) { + const clone = plain.startsWith("__DashCloneId("); + const docids = plain.split(":"); const strs = docids[0].split(","); - const ptx = Number(strs[0].substring("__DashDocId(".length)); + const ptx = Number(strs[0].substring((clone ? "__DashCloneId(" : "__DashDocId(").length)); const pty = Number(strs[1].substring(0, strs[1].length - 1)); let count = 1; const list: Doc[] = []; @@ -65,7 +67,7 @@ export class PreviewCursor extends React.Component<{}> { count++; if (doc instanceof Doc) { i === 1 && (first = doc); - const alias = Doc.MakeClone(doc); + const alias = clone ? Doc.MakeClone(doc) : doc; const deltaX = NumCast(doc.x) - NumCast(first!.x) - ptx; const deltaY = NumCast(doc.y) - NumCast(first!.y) - pty; alias.x = newPoint[0] + deltaX; @@ -115,9 +117,9 @@ export class PreviewCursor extends React.Component<{}> { (e.keyCode < 112 || e.keyCode > 123) && // F1 thru F12 keys !e.key.startsWith("Arrow") && !e.defaultPrevented) { - if ((!e.ctrlKey || (e.keyCode >= 48 && e.keyCode <= 57)) && !e.metaKey) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) { + if ((!e.metaKey && !e.ctrlKey) || (e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 65 && e.keyCode <= 90)) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) { PreviewCursor.Visible && PreviewCursor._onKeyPress?.(e); - PreviewCursor.Visible = false; + ((!e.ctrlKey && !e.metaKey) || e.key !== "v") && (PreviewCursor.Visible = false); } } else if (PreviewCursor.Visible) { if (e.key === "ArrowRight") { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 859bbc8f8..a24693c30 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -63,8 +63,8 @@ export class CollectionFreeFormLinkView extends React.Component Transform; getTransform: () => Transform; activeDocuments: () => Doc[]; - selectDocuments: (docs: Doc[], ink: { Document: Doc, Ink: Map }[]) => void; + selectDocuments: (docs: Doc[]) => void; addLiveTextDocument: (doc: Doc) => void; isSelected: () => boolean; nudge: (x: number, y: number) => boolean; @@ -80,11 +82,17 @@ export class MarqueeView extends React.Component { @@ -108,6 +116,7 @@ export class MarqueeView extends React.Component { @@ -118,7 +127,8 @@ export class MarqueeView extends React.Component { this.hideMarquee(); @@ -354,7 +364,7 @@ export class MarqueeView extends React.Component this.props.removeDocument(d)); const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2); this.props.addDocument(newCollection!); - this.props.selectDocuments([newCollection!], []); + this.props.selectDocuments([newCollection!]); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); } @@ -379,7 +389,7 @@ export class MarqueeView extends React.Component this.props.selectDocuments([newCollection], []), 0); + setTimeout(() => this.props.selectDocuments([newCollection]), 0); } @undoBatch @@ -731,6 +741,7 @@ export class MarqueeView extends React.Component e.preventDefault()} + onPaste={this.paste} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index f0818c7b4..c1c6f6baf 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -397,15 +397,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 4442ee2eb..d375466c9 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -147,7 +147,7 @@ export class KeyValueBox extends React.Component { { this._valInput.current!.select(); e.stopPropagation(); }} style={{ width: `${this.splitPercentage}%` }}> - + ; } @action diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 82334688b..f45a86b56 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1082,7 +1082,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp let olistPos = clickPos?.pos; if (clickPos && olistPos && this.props.isSelected(true)) { const clickNode = this._editorView?.state.doc.nodeAt(olistPos); - let nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1)); + const nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1)); olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos; let $olistPos = this._editorView?.state.doc.resolve(olistPos); let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef; @@ -1092,17 +1092,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]); } } - const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos!); + const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos); if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list) { if (!collapse) { if (!highlightOnly) { - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olistPos!))); + this._editorView.dispatch(this._editorView.state.tr.setSelection(new NodeSelection($olistPos!))); } addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } else if (listNode && listNode.type === this._editorView.state.schema.nodes.list_item) { if (!highlightOnly) { - this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(clickPos.pos!, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility })); - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, clickPos.pos!))); + this._editorView.dispatch(this._editorView.state.tr.setNodeMarkup(clickPos.pos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility })); + this._editorView.dispatch(this._editorView.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, clickPos.pos))); } addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } @@ -1232,7 +1232,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp setTimeout(() => FormattedTextBoxComment.Hide(), 0); } const selPad = this.props.isSelected() ? -10 : 0; - const selclass = this.props.isSelected() ? "-selected" : "" + const selclass = this.props.isSelected() ? "-selected" : ""; return (
Date: Mon, 22 Jun 2020 11:37:47 -0400 Subject: fixed onClick events for text. --- src/client/views/nodes/DocumentView.tsx | 8 -------- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 5 +---- 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9c8c05176..71cb18e08 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -323,20 +323,12 @@ export class DocumentView extends DocComponent(Docu const alias = Doc.MakeAlias(this.props.Document); DocUtils.makeCustomViewClicked(alias, undefined, "onClick"); this.props.addDocTab(alias, "onRight"); - // UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); - //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { - // if (this.props.Document.type === DocumentType.RTF) { - // DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; - // DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; - - // this.props.focus(this.props.Document, false); - // } SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey); } preventDefault = false; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f45a86b56..86757296e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1066,12 +1066,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; } (e.nativeEvent as any).formattedHandled = true; - if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientX - this._downX) < 4) { - this.props.select(e.ctrlKey); - this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); - } if (this.props.isSelected(true)) { // if text box is selected, then it consumes all click events e.stopPropagation(); + this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); } } -- cgit v1.2.3-70-g09d2 From 3a8f534a9bea20cedbb194d3cc9dceff6afcef37 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 12:19:21 -0400 Subject: added a way to broadcast a message to all users (e.g., for restarting server) --- src/client/views/MainView.tsx | 5 +++++ src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fcaa349cd..d6c46e3b0 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -80,6 +80,11 @@ export class MainView extends React.Component { componentDidMount() { const tag = document.createElement('script'); + const proto = DocServer.GetRefField("rtfProto").then(proto => { + (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), + msg => msg && alert(msg)); + }); + tag.src = "https://www.youtube.com/iframe_api"; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 747eb36a1..d3d1c8929 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -732,7 +732,7 @@ export class CollectionTreeView extends CollectionSubView this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); } - ContextMenu.Instance.addItem({ + !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { const { ImageDocument, PdfDocument } = Docs.Create; const { Document } = this.props; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 86757296e..134fe6e62 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -58,7 +58,6 @@ import { FieldView, FieldViewProps } from "../FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); -import requestPromise = require('request-promise'); library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -456,6 +455,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp uicontrols.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); uicontrols.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); uicontrols.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); + !Doc.UserDoc().noviceMode && uicontrols.push({ + description: "Broadcast Message", event: () => DocServer.GetRefField("rtfProto").then(proto => + proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt" + }); funcs.push({ description: "UI Controls...", subitems: uicontrols, icon: "asterisk" }); -- cgit v1.2.3-70-g09d2 From aba93a47815d424c9fcfc044259281f8facfe6b5 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 14:13:20 -0400 Subject: fixed tree view to allow textdocument to be typed while title is changing. fixed tryUpdateHeight so that text boxes don't get a scroll bar if they're autoHeight --- .../views/collections/CollectionTreeView.tsx | 7 +++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 34 +++++++++++----------- 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d3d1c8929..68dc0ced2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -312,8 +312,8 @@ class TreeView extends React.Component { @computed get renderContent() { TraceMobx(); - const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; - if (expandKey !== undefined) { + const expandKey = this.treeViewExpandedView; + if (["links", this.fieldKey].includes(expandKey)) { const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey); const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true); @@ -338,7 +338,7 @@ class TreeView extends React.Component { const layoutDoc = Doc.Layout(this.props.document); const panelHeight = layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight; const panelWidth = layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth; - return
+ return
this.addDoc(doc, relativeTo, before); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 134fe6e62..29018edda 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1201,18 +1201,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.dataDoc._nativeHeight, 0); const dh = NumCast(this.rootDoc._height, 0); const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); - if (Math.abs(newHeight - dh) > 1) { // bcz: Argh! without this, we get into a React crash if the same document is opened in a freeform view and in the treeview. no idea why, but after dragging the freeform document, selecting it, and selecting text, it will compute to 1 pixel higher than the treeview which causes a cycle - if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) { - // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... - console.log("Delayed height adjustment..."); - setTimeout(() => { - this.rootDoc._height = newHeight; - this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; - }, 10); - } else { + if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) { + // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... + console.log("Delayed height adjustment..."); + setTimeout(() => { this.rootDoc._height = newHeight; this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; - } + }, 10); + } else { + this.rootDoc._height = newHeight; + this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; } } } @@ -1234,15 +1232,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selPad = this.props.isSelected() ? -10 : 0; const selclass = this.props.isSelected() ? "-selected" : ""; return ( -
+
Date: Mon, 22 Jun 2020 16:15:37 -0400 Subject: cleaned up menus for formatted text & tempaltes. fixed pdf menu behavior (not fading until unselected); --- .../collectionFreeForm/CollectionFreeFormView.tsx | 24 +++--- src/client/views/nodes/PDFBox.scss | 41 +++++----- src/client/views/nodes/PDFBox.tsx | 14 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 93 ++++++++++++---------- src/client/views/pdf/PDFMenu.tsx | 1 + src/client/views/pdf/PDFViewer.tsx | 14 +++- 6 files changed, 104 insertions(+), 83 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index bf425f654..960b6efef 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1203,20 +1203,22 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); + appearanceItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + appearanceItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); + appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)!._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); + !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" }); - optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); + const options = ContextMenu.Instance.findByDescription("Options..."); + const optionItems = options && "subitems" in options ? options.subitems : []; optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }); - optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); - optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); - optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); - optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); + !Doc.UserDoc().noviceMode && optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); - // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - optionItems.push({ + !Doc.UserDoc().noviceMode && optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); input.type = "file"; @@ -1243,8 +1245,8 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); + !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); } @observable _timelineVisible = false; diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 6f18b1321..3e09fe519 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -15,6 +15,27 @@ z-index: 1; pointer-events: none; + .pdfBox-pageNums { + display: flex; + flex-direction: row; + height: 25px; + position: absolute; + left: 5px; + top: 5px; + .pdfBox-overlayButton-fwd, + .pdfBox-overlayButton-back { + background: #121721; + height: 25px; + width: 25px; + display: flex; + position: relative; + align-items: center; + justify-content: center; + border-radius: 3px; + pointer-events: all; + } + } + .pdfBox-overlayButton { border-bottom-left-radius: 50%; display: flex; @@ -47,26 +68,6 @@ pointer-events: all; } } - .pdfBox-overlayButton-fwd, - .pdfBox-overlayButton-back { - background: #121721; - height: 25px; - width: 25px; - display: flex; - position: relative; - align-items: center; - justify-content: center; - border-radius: 3px; - pointer-events: all; - position: absolute; - top: 5; - } - .pdfBox-overlayButton-fwd { - left: 45; - } - .pdfBox-overlayButton-back { - left: 25; - } .pdfBox-nextIcon, .pdfBox-prevIcon { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 985fb4363..6b1c9fcde 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -147,6 +147,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent ; const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; + const curPage = this.Document.curPage || 1; return !this.active() ? (null) : (
e.keyCode === KeyCodes.BACKSPACE || e.keyCode === KeyCodes.DELETE ? e.stopPropagation() : true} onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}> @@ -170,11 +171,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent e.stopPropagation()}>
- this.gotoPage(Number(e.currentTarget.value))} - style={{ left: 5, top: 5, height: "20px", width: "3ch", position: "absolute", pointerEvents: "all" }} - onClick={action(() => this._pageControls = !this._pageControls)} /> - {this._pageControls ? pageBtns : (null)} + +
+ this.gotoPage(Number(e.currentTarget.value))} + style={{ width: `${curPage > 99 ? 4 : 3}ch`, pointerEvents: "all" }} + onClick={action(() => this._pageControls = !this._pageControls)} /> + {this._pageControls ? pageBtns : (null)} +
e.stopPropagation()}> , ...this.shapeButtons, this.bezierButton, this.widthPicker, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 348ed4ba5..ccdf41233 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -251,22 +251,23 @@ footnote::after { .prosemirror-links { display: none; position: absolute; - background-color: gray; - padding-bottom: 10px; - margin-top: 1em; + background-color: dimgray; + margin-top: 1.5em; z-index: 1; + padding: 5; + border-radius: 2px; } .prosemirror-hrefoptions{ width:0px; border:unset; padding:0px; - } .prosemirror-links a { float: left; color: white; text-decoration: none; + border-radius: 3px; } .prosemirror-links a:hover { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2a019ada7..3ee5603e5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -599,10 +599,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }; } - makeLinkToSelection(linkId: string, title: string, location: string, targetId: string) { + makeLinkToSelection(linkId: string, title: string, location: string, targetId: string, targetHref?: string) { const state = this._editorView?.state; if (state) { - const href = Utils.prepend("/doc/" + linkId); + const href = targetHref ?? Utils.prepend("/doc/" + linkId); const sel = state.selection; const splitter = state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); let tr = state.tr.addMark(sel.from, sel.to, splitter); @@ -610,7 +610,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { const allHrefs = [{ href, title, targetId, linkId }]; allHrefs.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); - const link = state.schema.marks.link.create({ href, allHrefs, title, location, linkId, targetId }); + const link = state.schema.marks.link.create({ allHrefs, title, location, linkId }); tr = tr.addMark(pos, pos + node.nodeSize, link); } }); @@ -937,6 +937,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const { state: { tr }, dispatch } = this._editorView; dispatch(tr.insertText(startupText)); } + (this._editorView as any).TextView = this; } const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad; @@ -1040,6 +1041,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (bounds && this.layoutDoc._chromeStatus !== "disabled") { const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width); let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height); + console.log("y = " + y + " hgt = " + RichTextMenu.Instance.height + " cords = " + coords.top); if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) { y = Math.min(bounds.bottom, window.innerHeight - RichTextMenu.Instance.height); } diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 1e14b8237..fecf2de85 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -12,7 +12,7 @@ import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscr import { updateBullets } from "./ProsemirrorExampleTransfer"; import { FieldViewProps } from "../FieldView"; import { Cast, StrCast } from "../../../../fields/Types"; -import { FormattedTextBoxProps } from "./FormattedTextBox"; +import { FormattedTextBoxProps, FormattedTextBox } from "./FormattedTextBox"; import { unimplementedFunction, Utils } from "../../../../Utils"; import { wrapInList } from "prosemirror-schema-list"; import { PastelSchemaPalette, DarkPastelSchemaPalette } from '../../../../fields/SchemaHeaderField'; @@ -307,7 +307,7 @@ export default class RichTextMenu extends AntimodeMenu { function onClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + //self.view?.focus(); self.view && command && command(self.view.state, self.view.dispatch, self.view); self.view && onclick && onclick(self.view.state, self.view.dispatch, self.view); self.setActiveMarkButtons(self.getActiveMarksOnSelection()); @@ -427,7 +427,7 @@ export default class RichTextMenu extends AntimodeMenu { function onBrushClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + // self.view?.focus(); self.view && self.fillBrush(self.view.state, self.view.dispatch); } @@ -501,13 +501,13 @@ export default class RichTextMenu extends AntimodeMenu { function onColorClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + // self.view?.focus(); self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); } function changeColor(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + //self.view?.focus(); self.setActiveColor(color); self.view && self.insertColor(self.activeFontColor, self.view.state, self.view.dispatch); } @@ -554,13 +554,13 @@ export default class RichTextMenu extends AntimodeMenu { function onHighlightClick(e: React.PointerEvent) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + // self.view?.focus(); self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); } function changeHighlight(e: React.PointerEvent, color: string) { e.preventDefault(); e.stopPropagation(); - self.view && self.view.focus(); + // self.view?.focus(); self.setActiveHighlight(color); self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch); } @@ -659,15 +659,8 @@ export default class RichTextMenu extends AntimodeMenu { } // TODO: should check for valid URL - makeLinkToURL = (target: String, lcoation: string) => { - if (!this.view) return; - - let node = this.view.state.selection.$from.nodeAfter; - let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location }); - this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link)); - this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link)); - node = this.view.state.selection.$from.nodeAfter; - link = node && node.marks.find(m => m.type.name === "link"); + makeLinkToURL = (target: string, lcoation: string) => { + ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRight", "", target); } deleteLink = () => { @@ -760,13 +753,14 @@ export default class RichTextMenu extends AntimodeMenu { this.collapsed = !this.collapsed; setTimeout(() => { const x = Math.min(this._left, window.innerWidth - RichTextMenu.Instance.width); - RichTextMenu.Instance.jumpTo(x, this._top); + RichTextMenu.Instance.jumpTo(x, this._top, true); }, 0); } render() { const row1 =
{[ + !this.collapsed ? this.getDragger() : (null), this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)), this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)), this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)), @@ -781,6 +775,7 @@ export default class RichTextMenu extends AntimodeMenu { ]}
; const row2 =
+ {this.collapsed ? this.getDragger() : (null)}
{[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size"), this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family"), @@ -795,7 +790,6 @@ export default class RichTextMenu extends AntimodeMenu { - {this.getDragger()}
; @@ -840,7 +834,7 @@ class ButtonDropdown extends React.Component { onDropdownClick = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - this.props.view && this.props.view.focus(); + //this.props.view?.focus(); this.toggleDropdown(); } -- cgit v1.2.3-70-g09d2 From 71ba25ed627be46d02878e58bd791bf817d552ad Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jun 2020 01:53:31 -0400 Subject: changed titles to just look at first node of text box. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3ee5603e5..e01144f82 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -230,7 +230,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp updateTitle = () => { if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) { - const str = this._editorView.state.doc.textContent; + let node = this._editorView.state.doc; + while (node.firstChild) node = node.firstChild; + const str = node.textContent; const titlestr = str.substr(0, Math.min(40, str.length)); this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : ""); } -- cgit v1.2.3-70-g09d2 From ae6315813d718f8e4913ed98f5aec33464eb8164 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jun 2020 11:45:22 -0400 Subject: fixed warnings. fixed blockquote menu function. --- src/client/util/DragManager.ts | 2 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 5 +-- .../views/nodes/formattedText/ParagraphNodeSpec.ts | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 50 +++++++++++++--------- src/client/views/nodes/formattedText/nodes_rts.ts | 20 ++++++++- .../nodes/formattedText/prosemirrorPatches.js | 4 +- 7 files changed, 56 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 533bc8485..91bc51101 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -218,7 +218,7 @@ export namespace DragManager { docDragData.dropAction !== "same" && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => { const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []); const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps)); - remProps.map(prop => drop[prop] = undefined) + remProps.map(prop => drop[prop] = undefined); }); batch.end(); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index ee987abdb..79c577b6d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -527,7 +527,8 @@ export class CollectionDockingView extends React.Component dispatch(tx)); + toggleMark(mark.type, mark.attrs)(state, dispatch); } } } @@ -411,8 +415,12 @@ export default class RichTextMenu extends AntimodeMenu { } insertBlockquote(state: EditorState, dispatch: any) { - if (state.selection.empty) return false; - setBlockType(state.schema.nodes.blockquote)(state, (tx: any) => dispatch(tx)); + const path = (state.selection.$from as any).path; + if (path.length > 6 && path[path.length - 6].type === schema.nodes.blockquote) { + lift(state, dispatch); + } else { + wrapIn(schema.nodes.blockquote)(state, dispatch); + } return true; } @@ -758,7 +766,7 @@ export default class RichTextMenu extends AntimodeMenu { } render() { - + TraceMobx(); const row1 =
{[ !this.collapsed ? this.getDragger() : (null), this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)), diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index 1a292d9af..0a867912f 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -1,7 +1,7 @@ import React = require("react"); import { DOMOutputSpecArray, Fragment, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model"; import { bulletList, listItem, orderedList } from 'prosemirror-schema-list'; -import ParagraphNodeSpec from "./ParagraphNodeSpec"; +import { ParagraphNodeSpec, toParagraphDOM, getParagraphNodeAttrs } from "./ParagraphNodeSpec"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -32,13 +32,29 @@ export const nodes: { [index: string]: NodeSpec } = { // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. blockquote: { - content: "block+", + content: "block*", group: "block", defining: true, parseDOM: [{ tag: "blockquote" }], toDOM() { return blockquoteDOM; } }, + + // blockquote: { + // ...ParagraphNodeSpec, + // defining: true, + // parseDOM: [{ + // tag: "blockquote", getAttrs(dom: any) { + // return getParagraphNodeAttrs(dom); + // } + // }], + // toDOM(node: any) { + // const dom = toParagraphDOM(node); + // (dom as any)[0] = 'blockquote'; + // return dom; + // }, + // }, + // :: NodeSpec A horizontal rule (`
`). horizontal_rule: { group: "block", diff --git a/src/client/views/nodes/formattedText/prosemirrorPatches.js b/src/client/views/nodes/formattedText/prosemirrorPatches.js index 269423482..763961958 100644 --- a/src/client/views/nodes/formattedText/prosemirrorPatches.js +++ b/src/client/views/nodes/formattedText/prosemirrorPatches.js @@ -136,4 +136,6 @@ function wrappingInputRule(regexp, nodeType, getAttrs, joinPredicate, customWith (!joinPredicate || joinPredicate(match, before))) { tr.join(start - 1); } return tr }) -} \ No newline at end of file +} + + -- cgit v1.2.3-70-g09d2