diff options
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r-- | src/client/views/nodes/ColorBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 20 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.scss | 4 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.tsx | 42 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 15 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx | 59 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts | 76 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.tsx | 36 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextRules.ts | 2 |
10 files changed, 126 insertions, 136 deletions
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 090cf015a..0aa0c33fb 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -55,7 +55,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument render() { const selDoc = SelectionManager.SelectedDocuments()?.[0]?.rootDoc; return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`} - onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} + onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} onClick={e => { (e.nativeEvent as any).stuff = true; e.stopPropagation(); }} style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > <SketchPicker onChange={ColorBox.switchColor} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 89ce32e78..4b740d3de 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -40,6 +40,7 @@ import { RadialMenu } from './RadialMenu'; import { TaskCompletionBox } from './TaskCompletedBox'; import React = require("react"); import { CurrentUserUtils } from '../../util/CurrentUserUtils'; +import { RichTextField } from '../../../fields/RichTextField'; export type DocFocusFunc = () => boolean; @@ -269,6 +270,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } onKeyDown = (e: React.KeyboardEvent) => { + if (this.rootDoc._singleLine && ((e.key === "Backspace" && this.dataDoc.text && !(this.dataDoc.text as RichTextField)?.Text) || ["Tab", "Enter"].includes(e.key))) { + return; + } if (e.altKey && !(e.nativeEvent as any).StopPropagationForReal) { (e.nativeEvent as any).StopPropagationForReal = true; // e.stopPropagation() doesn't seem to work... e.stopPropagation(); @@ -299,7 +303,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { let stopPropagate = true; let preventDefault = true; - !this.props.Document._isBackground && this.props.bringToFront(this.props.Document); + !this.props.Document._isBackground && !this.props.Document["_isBackground-canClick"] && this.props.bringToFront(this.props.Document); if (this._doubleTap && ((this.props.renderDepth && this.props.Document.type !== DocumentType.FONTICON) || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (this._timeout) { clearTimeout(this._timeout); @@ -593,9 +597,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu if (CurrentUserUtils.ActiveDashboard === this.props.Document) { alert("Can't delete the active dashboard"); } else { - const selected = SelectionManager.SelectedDocuments().slice(); - SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); this.props.removeDocument?.(this.props.Document); } } @@ -627,6 +628,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { + if (this.props.LayoutTemplateString) return; if (this.props.Document === CurrentUserUtils.ActiveDashboard) { if ((e.target as any)?.closest?.("*.lm_content")) { alert("You can't perform this move most likely because you don't have permission to modify the destination."); @@ -762,6 +764,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; optionItems.push({ description: "Bring to Front", event: () => this.props.bringToFront(this.rootDoc, false), icon: "expand-arrows-alt" }); optionItems.push({ description: "Send to Back", event: () => this.props.bringToFront(this.rootDoc, true), icon: "expand-arrows-alt" }); + optionItems.push({ description: "Lock in Back", event: () => this.rootDoc["_isBackground-canClick"] = !this.rootDoc["_isBackground-canClick"], icon: "expand-arrows-alt" }); !this.props.treeViewDoc && this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" }); @@ -903,7 +906,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} {/* {this.allAnchors} */} - {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton || this.props.dontRegisterView ? (null) : + {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.isLinkButton || (!this.isSelected() && this.layoutDoc.hideLinkButton) || this.props.dontRegisterView ? (null) : <DocumentLinksButton View={this} links={this.allLinks} Offset={this.linkOffset} />} </div> ); @@ -1007,6 +1010,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } @computed get ignorePointerEvents() { return this.props.pointerEvents === false || + (SnappingManager.GetIsDragging() && this.Document["_isBackground-canClick"]) || (this.Document._isBackground && !this.isSelected() && !SnappingManager.GetIsDragging()) || (this.Document.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None); } @@ -1046,7 +1050,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; - const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); + const fullDegree = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString const borderRounding = this.layoutDoc.borderRounding; const localScale = fullDegree; const highlightColors = CurrentUserUtils.ActiveDashboard?.darkScheme ? @@ -1060,8 +1064,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu id={this.props.Document[Id]} ref={this._mainCont} onKeyDown={this.onKeyDown} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - onPointerEnter={action(() => { Doc.BrushDoc(this.props.Document); })} - onPointerLeave={action((e: React.PointerEvent<HTMLDivElement>) => { + onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} + onPointerLeave={action(e => { let entered = false; const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); for (let child: any = target; child; child = child?.parentElement) { diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 174bf8eff..2d88246c2 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -187,8 +187,8 @@ color: lightgray; margin-top: auto; margin-bottom: auto; - transform-origin: 50% 50%; - width: 100%; + transform-origin: 40% 40%; + width: 125%; transform: rotate(40deg) scale(0.8); font-size: 80; padding: 5%; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 99fb5d2ce..b23dffe80 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -1129,13 +1129,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20; } let doc = undefined; - const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24pt", }); - const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16pt" }); - const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20pt" }); - const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24pt" }); - const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14pt" }); - const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14pt" }); - const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" }); + const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24px", }); + const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16px" }); + const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20px" }); + const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24px" }); + const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14px" }); + const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14px" }); + const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14px" }); switch (layout) { case 'blank': doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y }); @@ -1227,8 +1227,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; let type: string = ''; + const effectiveType = targetDoc.treeViewOutlineMode ? DocumentType.COL : targetDoc.type;// bcz: Argh .. .need a better way to identify a slide doc if (activeItem) { - switch (targetDoc.type) { + switch (effectiveType) { case DocumentType.PDF: type = "PDF"; break; case DocumentType.RTF: type = "Text node"; break; case DocumentType.COL: type = "Collection"; break; @@ -1248,8 +1249,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> @computed get progressivizeDropdown() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; + const activeItem = this.activeItem; + const targetDoc = this.targetDoc; + const effectiveType = targetDoc.treeViewOutlineMode ? DocumentType.COL : targetDoc.type; if (activeItem && targetDoc) { const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black"; const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black"; @@ -1258,7 +1260,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> <div className="ribbon-box"> {this.stringType} selected - <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}> + <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: effectiveType === DocumentType.COL ? "inline-flex" : "none" }}> <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div> <div className="ribbon-button" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div> </div> @@ -1274,11 +1276,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> </div> {this.viewedColorPicker} - {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}> + {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (effectiveType === DocumentType.COL && targetDoc._viewType === 'freeform') || effectiveType === DocumentType.IMG ? "inline-flex" : "none" }}> <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Zoom</div> <div className="ribbon-button" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Edit</div> </div> */} - <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}> + <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || effectiveType === DocumentType.PDF || effectiveType === DocumentType.WEB || effectiveType === DocumentType.RTF ? "inline-flex" : "none" }}> <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll</div> <div className="ribbon-button" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div> </div> @@ -1435,18 +1437,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } @action - progressivizeChild = (e: React.MouseEvent) => { - e.stopPropagation(); + progressivizeChild = (e?: React.MouseEvent) => { + e?.stopPropagation(); const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); if (!activeItem.presProgressivize) { targetDoc.editing = false; activeItem.presProgressivize = true; targetDoc.presProgressivize = true; targetDoc._currentFrame = 0; - docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true)); - targetDoc.lastFrame = docs.length - 1; + let count = 0; + const setupProgressivize = (doc: Doc) => { + CollectionFreeFormDocumentView.setupKeyframes([doc], count++, true); + targetDoc.treeViewOutlineMode && DocListCast(doc[Doc.LayoutFieldKey(doc)]).forEach(d => setupProgressivize(d)); + } + setupProgressivize(targetDoc); + targetDoc.lastFrame = count; } else { targetDoc.editProgressivize = false; activeItem.presProgressivize = false; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 9620e241c..e93411c0f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -396,6 +396,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum view = <span className="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />; } else if (field instanceof WebField) { const url = this.layoutDoc.useCors ? Utils.CorsProxy(field.url.href) : field.url.href; + // view = <iframe className="webBox-iframe" src={url} onLoad={e => { e.currentTarget.before((e.currentTarget.contentDocument?.body || e.currentTarget.contentDocument)?.children[0]!); e.currentTarget.remove(); }} + view = <iframe className="webBox-iframe" enable-annotation={"true"} ref={this._iframeRef} src={url} onLoad={this.iframeLoaded} // the 'allow-top-navigation' and 'allow-top-navigation-by-user-activation' attributes are left out to prevent iframes from redirecting the top-level Dash page sandbox={"allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts"} />; @@ -479,7 +481,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum highlight = (color: string) => { // creates annotation documents for current highlights const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); - const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) ? this.makeAnnotationDocument(color) : undefined; + const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) ? this.makeAnnotationDocument(color.replace(/[0-9.]*\)/, "0.3)")) : undefined; annotationDoc && this.addDocument?.(annotationDoc); return annotationDoc ?? undefined; } @@ -501,7 +503,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum Doc.GetProto(targetDoc).data = new List<Doc>([clipDoc]); clipDoc.rootDocument = targetDoc; targetDoc.layoutKey = "layout"; - const annotationDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color + const annotationDoc = this.highlight("rgba(173, 216, 230, 0.35)"); // hyperlink color if (annotationDoc) { DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, { dragComplete: e => { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 97d023673..3be02aa92 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -988,7 +988,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (documentId) { exportState = await RichTextUtils.GoogleDocs.Import(documentId, dataDoc); } - UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls); + exportState && UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls); } updateState = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => { @@ -1171,6 +1171,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } componentWillUnmount() { + this.endUndoTypingBatch(); Object.values(this._disposers).forEach(disposer => disposer?.()); this._editorView?.destroy(); } @@ -1417,7 +1418,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } _lastTimedMark: Mark | undefined = undefined; - onKeyPress = (e: React.KeyboardEvent) => { + onKeyDown = (e: React.KeyboardEvent) => { + // single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container) + if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) { + return; + } if (e.altKey) { e.preventDefault(); return; @@ -1502,8 +1507,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (!this.props.isSelected() && FormattedTextBoxComment.textBox === this) { setTimeout(() => FormattedTextBoxComment.Hide(), 0); } - const selPad = this.props.isSelected() ? -10 : 0; - const selclass = this.props.isSelected() ? "-selected" : ""; + const selPad = this.props.isSelected() && !this.layoutDoc._singleLine ? -10 : 0; + const selclass = this.props.isSelected() && !this.layoutDoc._singleLine ? "-selected" : ""; return ( <div className={"formattedTextBox-cont"} style={{ @@ -1526,7 +1531,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"), }} onContextMenu={this.specificContextMenu} - onKeyDown={this.onKeyPress} + onKeyDown={this.onKeyDown} onFocus={this.onFocused} onClick={this.onClick} onPointerMove={e => this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, true)} diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 6c71f08e7..1982cabab 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -1,28 +1,28 @@ +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from "@material-ui/core"; +import { action } from "mobx"; import { Mark, ResolvedPos } from "prosemirror-model"; import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; +import wiki from "wikijs"; import { Doc, DocCastAsync, Opt } from "../../../../fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter, returnEmptyDoclist } from "../../../../Utils"; +import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { schema } from "./schema_rts"; +import { Docs } from "../../../documents/Documents"; +import { DocumentType } from "../../../documents/DocumentTypes"; +import { LinkManager } from "../../../util/LinkManager"; import { Transform } from "../../../util/Transform"; +import { undoBatch } from "../../../util/UndoManager"; +import { LinkMenuItem } from "../../linking/LinkMenuItem"; import { ContentFittingDocumentView } from "../ContentFittingDocumentView"; +import { DocumentLinksButton } from "../DocumentLinksButton"; +import { LinkDocPreview } from "../LinkDocPreview"; import { FormattedTextBox } from "./FormattedTextBox"; import './FormattedTextBoxComment.scss'; +import { schema } from "./schema_rts"; import React = require("react"); -import { Docs } from "../../../documents/Documents"; -import wiki from "wikijs"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action } from "mobx"; -import { LinkManager } from "../../../util/LinkManager"; -import { LinkDocPreview } from "../LinkDocPreview"; -import { DocumentLinksButton } from "../DocumentLinksButton"; -import { Tooltip } from "@material-ui/core"; -import { undoBatch } from "../../../util/UndoManager"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -98,40 +98,18 @@ export class FormattedTextBoxComment { const textBox = FormattedTextBoxComment.textBox; const linkDoc = FormattedTextBoxComment.linkDoc; if (linkDoc && !keep && textBox) { - FormattedTextBoxComment.linkDoc = undefined; if (linkDoc.author) { if (FormattedTextBoxComment._deleteRef?.contains(e.target as any)) { this.deleteLink(); - } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) { - if (linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right"); - } else { - const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? - Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) - || linkDoc); - const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; - - if (linkDoc.follow) { - if (linkDoc.follow === "default") { - DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); - } else if (linkDoc.follow === "Always open in right tab") { - if (target) { textBox.props.addDocTab(target, "add:right"); } - } else if (linkDoc.follow === "Always open in new tab") { - if (target) { textBox.props.addDocTab(target, "add"); } - } - } else { - DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); - } - } } else { + FormattedTextBoxComment.linkDoc = undefined; if (linkDoc.type !== DocumentType.LINK) { textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right"); } else { - DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, - (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation)); + const target = LinkManager.getOppositeAnchor(linkDoc, textBox.dataDoc); + target && LinkMenuItem.followDefault(linkDoc, textBox.dataDoc, target, textBox.props.addDocTab); } } - } } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, useCors: true }), "add:right"); @@ -146,14 +124,13 @@ export class FormattedTextBoxComment { } @undoBatch - @action - deleteLink = () => { + deleteLink = action(() => { FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null; LinkDocPreview.LinkInfo = undefined; DocumentLinksButton.EditLink = undefined; //FormattedTextBoxComment.tooltipText = undefined; FormattedTextBoxComment.Hide(); - } + }); public static Hide() { FormattedTextBoxComment.textBox = undefined; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index c6bacc1a8..674b63e77 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -7,11 +7,13 @@ import { splitListItem, wrapInList, } from "prosemirror-schema-list"; import { EditorState, Transaction, TextSelection } from "prosemirror-state"; import { SelectionManager } from "../../../util/SelectionManager"; import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types"; -import { Doc, DataSym } from "../../../../fields/Doc"; +import { Doc, DataSym, DocListCast } from "../../../../fields/Doc"; import { FormattedTextBox } from "./FormattedTextBox"; import { Id } from "../../../../fields/FieldSymbols"; import { Docs } from "../../../documents/Documents"; import { Utils } from "../../../../Utils"; +import { listSpec } from "../../../../fields/Schema"; +import { List } from "../../../../fields/List"; const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; @@ -45,6 +47,29 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey keys[key] = cmd; } + /// bcz; Argh!! replace with an onEnter func that conditionally handles Enter + const addTextBox = (below: boolean, force?: boolean) => { + if (props.LayoutTemplateString) return true; + const layoutDoc = props.Document; + const originalDoc = layoutDoc.rootDocument || layoutDoc; + if (force || props.Document._singleLine) { + const layoutKey = StrCast(originalDoc.layoutKey); + const newDoc = Doc.MakeCopy(originalDoc, true); + const dataField = originalDoc[Doc.LayoutFieldKey(newDoc)]; + newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined; + if (below) newDoc.y = NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10; + else newDoc.x = NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10; + if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = originalDoc[layoutKey]; + } + Doc.GetProto(newDoc).text = undefined; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + props.addDocument(newDoc); + return true; + } + return false; + } + //History commands bind("Mod-z", undo); bind("Shift-Mod-z", redo); @@ -66,6 +91,11 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey bind("Ctrl-i", wrapInList(schema.nodes.ordered_list)); bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { + /// bcz; Argh!! replace layotuTEmpalteString with a onTab prop conditionally handles Tab); + if (props.Document._singleLine) { + if (!props.LayoutTemplateString) return addTextBox(false, true); + return true; + } const ref = state.selection; const range = ref.$from.blockRange(ref.$to); const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); @@ -89,6 +119,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey }); bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { + /// bcz; Argh!! replace with a onShiftTab prop conditionally handles Tab); + if (props.Document._singleLine) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); if (!liftListItem(schema.nodes.list_item)(state.tr, (tx2: Transaction) => { @@ -136,47 +168,11 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey return tx; }; - const addTextOnRight = (force: boolean) => { - const layoutDoc = props.Document; - const originalDoc = layoutDoc.rootDocument || layoutDoc; - if (force || props.Document._singleLine) { - const layoutKey = StrCast(originalDoc.layoutKey); - const newDoc = Doc.MakeCopy(originalDoc, true); - newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = undefined; - newDoc.x = NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10; - if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { - newDoc[layoutKey] = originalDoc[layoutKey]; - } - Doc.GetProto(newDoc).text = undefined; - FormattedTextBox.SelectOnLoad = newDoc[Id]; - props.addDocument(newDoc); - return true; - } - return false; - }; - //Command to create a text document to the right of the selected textbox - bind("Alt-Enter", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => { - return addTextOnRight(true); - }); + bind("Alt-Enter", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => addTextBox(false, true)); //Command to create a text document to the bottom of the selected textbox - bind("Ctrl-Enter", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { - const layoutDoc = props.Document; - const originalDoc = layoutDoc.rootDocument || layoutDoc; - if (originalDoc instanceof Doc) { - const layoutKey = StrCast(originalDoc.layoutKey); - const newDoc = Doc.MakeCopy(originalDoc, true); - newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = undefined; - newDoc.y = NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10; - if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { - newDoc[layoutKey] = originalDoc[layoutKey]; - } - Doc.GetProto(newDoc).text = undefined; - FormattedTextBox.SelectOnLoad = newDoc[Id]; - props.addDocument(newDoc); - } - }); + bind("Ctrl-Enter", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => addTextBox(true, true)); // backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward); bind("Backspace", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => { @@ -199,7 +195,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey //newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock //command to break line bind("Enter", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => { - if (addTextOnRight(false)) return true; + if (addTextBox(true, false)) return true; const trange = state.selection.$from.blockRange(state.selection.$to); const path = (state.selection.$from as any).path; const depth = trange ? liftTarget(trange) : undefined; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 307238ea1..da515aa5a 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -78,21 +78,21 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { runInAction(() => this.Pinned = true); this.fontSizeOptions = [ - { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 8 }), title: "Set font size", label: "8pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 9 }), title: "Set font size", label: "9pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 10 }), title: "Set font size", label: "10pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 12 }), title: "Set font size", label: "12pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 14 }), title: "Set font size", label: "14pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 16 }), title: "Set font size", label: "16pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 18 }), title: "Set font size", label: "18pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 20 }), title: "Set font size", label: "20pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 24 }), title: "Set font size", label: "24pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 32 }), title: "Set font size", label: "32pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 48 }), title: "Set font size", label: "48pt", command: this.changeFontSize }, - { mark: schema.marks.pFontSize.create({ fontSize: 72 }), title: "Set font size", label: "72pt", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 8 }), title: "Set font size", label: "8px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 9 }), title: "Set font size", label: "9px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 10 }), title: "Set font size", label: "10px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 12 }), title: "Set font size", label: "12px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 14 }), title: "Set font size", label: "14px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 16 }), title: "Set font size", label: "16px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 18 }), title: "Set font size", label: "18px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 20 }), title: "Set font size", label: "20px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 24 }), title: "Set font size", label: "24px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 32 }), title: "Set font size", label: "32px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 48 }), title: "Set font size", label: "48px", command: this.changeFontSize }, + { mark: schema.marks.pFontSize.create({ fontSize: 72 }), title: "Set font size", label: "72px", command: this.changeFontSize }, { mark: null, title: "", label: "...", command: unimplementedFunction, hidden: true }, - { mark: null, title: "", label: "13pt", command: unimplementedFunction, hidden: true }, // this is here because the default size is 13, but there is no actual 13pt option + { mark: null, title: "", label: "13px", command: unimplementedFunction, hidden: true }, // this is here because the default size is 13, but there is no actual 13pt option ]; this.fontFamilyOptions = [ @@ -177,7 +177,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { this.activeListType = this.getActiveListStyle(); this.activeAlignment = this.getActiveAlignment(); this.activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; - this.activeFontSize = !activeSizes.length ? "13pt" : activeSizes.length === 1 ? String(activeSizes[0]) : "..."; + this.activeFontSize = !activeSizes.length ? "13px" : activeSizes.length === 1 ? String(activeSizes[0]) : "..."; this.activeFontColor = !activeColors.length ? "black" : activeColors.length === 1 ? String(activeColors[0]) : "..."; this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length === 1 ? String(activeHighlights[0]) : "..."; @@ -255,7 +255,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { marks.forEach(m => { m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family); m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color); - m.type === state.schema.marks.pFontSize && activeSizes.push(String(m.attrs.fontSize) + "pt"); + m.type === state.schema.marks.pFontSize && activeSizes.push(String(m.attrs.fontSize) + "px"); m.type === state.schema.marks.marker && activeHighlights.push(String(m.attrs.highlight)); }); } @@ -384,7 +384,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { if (!self.TextView.props.isSelected(true)) { switch (mark.type) { case schema.marks.pFontFamily: setter(Doc.UserDoc().fontFamily = mark.attrs.family); break; - case schema.marks.pFontSize: setter(Doc.UserDoc().fontSize = mark.attrs.fontSize.toString() + "pt"); break; + case schema.marks.pFontSize: setter(Doc.UserDoc().fontSize = mark.attrs.fontSize.toString() + "px"); break; } } else UndoManager.RunInBatch(() => self.view && mark && command(mark, self.view), "text mark dropdown"); @@ -425,7 +425,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { changeFontSize = (mark: Mark, view: EditorView) => { if ((this.view?.state.selection.$from.pos || 0) < 2) { - this.TextView.layoutDoc._fontSize = mark.attrs.fontSize; + this.TextView.layoutDoc._fontSize = mark.attrs.fontSize === Number(mark.attrs.fontSize) ? `${mark.attrs.fontSize}pt` : mark.attrs.fontSize; } const fmark = view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }); this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true); diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 5c0505909..02f9c6268 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -90,7 +90,7 @@ export class RichTextRules { textDoc.inlineTextCount = numInlines + 1; const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to const inlineLayoutKey = "layout_" + inlineFieldKey; // the field holding the layout string that will render the inline annotation - const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, _fontSize: "9pt", title: "inline comment" }); + const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, _fontSize: "9px", title: "inline comment" }); textDocInline.title = inlineFieldKey; // give the annotation its own title textDocInline["title-custom"] = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point |