From c31bb0d5d8c4d42fb5cd97b1582de0cae1b16ca0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 12 May 2022 12:17:12 -0400 Subject: fixed perfromance (flickering, speed) issues with having pointerEvents prop invalidate documents - switched to using a function to avoid flickering on PDFs of annotations in particular. --- src/client/views/nodes/FieldView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/FieldView.tsx') diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ae9acfe3f..686b4308b 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; import { DateField } from "../../../fields/DateField"; -import { Doc, Field, FieldResult } from "../../../fields/Doc"; +import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { WebField } from "../../../fields/URLField"; import { DocumentViewSharedProps } from "./DocumentView"; @@ -25,7 +25,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { setHeight?: (height: number) => void; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) - pointerEvents?: string; + pointerEvents?: () => Opt; fontSize?: number; height?: number; width?: number; -- cgit v1.2.3-70-g09d2 From d2075d39b0ec5e8fd6e5752c6d777b6f3f2d5138 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 17 May 2022 13:18:35 -0400 Subject: improved browse mode by not needing to click on background to zoom out. cleaned up api to use a browseClick prop. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 ++++++++++++++++------ src/client/views/nodes/DocumentView.tsx | 4 ++- src/client/views/nodes/FieldView.tsx | 2 ++ 3 files changed, 28 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/FieldView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 68a51ef69..5c727a7f0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -155,7 +155,8 @@ export class CollectionFreeFormView extends CollectionSubView this._keyframeEditing = set; getKeyFrameEditing = () => this._keyframeEditing; - onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick, ScriptCast(this.layoutDoc.onBrowseClick)); + onBrowseClickHandler = () => this.props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick); + onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; shrinkWrap = () => { @@ -622,9 +623,14 @@ export class CollectionFreeFormView extends CollectionSubView { - - if (this.layoutDoc.onBrowseClick) { - this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1); + if (this.onBrowseClickHandler()) { + // if (this.Document[this.scaleFieldKey] !== 0.5) { + // this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 0.5); + // } + // else + if (this.props.DocumentView?.()) { + this.onBrowseClickHandler().script.run({ documentView: this.props.DocumentView(), clientX: e.clientX, clientY: e.clientY }); + } e.stopPropagation(); e.preventDefault(); } @@ -1082,7 +1088,7 @@ export class CollectionFreeFormView extends CollectionSubView this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView)", { documentView: "any" }), icon: "compress-arrows-alt" }); + viewCtrlItems.push({ description: (this.layoutDoc.onChildClick ? "Leave" : "Enter") + " Browse Mode", event: () => this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", { documentView: "any", clientX: "number", clientY: "number" }), icon: "compress-arrows-alt" }); !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); @@ -1982,8 +1989,16 @@ class CollectionFreeFormBackgroundGrid extends React.Component { + const ffview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView ?? dv.ComponentView; // first try to zoom out using the docView's container if it's container is a freeformview. Otherwise, use the doc view's freeform view if the document itself is a freeformview. + if (!didMove && ffview instanceof CollectionFreeFormView) { + ffview.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5); + } + return ViewAdjustment.doNothing; + } + }); Doc.linkFollowHighlight(dv?.props.Document, false); } ScriptingGlobals.add(CollectionBrowseClick); \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 628a12945..1d4805fff 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -177,6 +177,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onDoubleClick?: () => ScriptField; onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; + onBrowseClick?: () => ScriptField; } // these props are only available in DocumentViewIntenral @@ -232,7 +233,7 @@ export class DocumentViewInternal extends DocComponent 0))) { if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && + !this.props.onBrowseClick && !this.Document.ignoreClick && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 686b4308b..33ed8cd89 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -6,6 +6,7 @@ import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { WebField } from "../../../fields/URLField"; import { DocumentViewSharedProps } from "./DocumentView"; +import { ScriptField } from "../../../fields/ScriptField"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. @@ -23,6 +24,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { isSelected: (outsideReaction?: boolean) => boolean; scaling?: () => number; setHeight?: (height: number) => void; + onBrowseClick?: () => ScriptField; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: () => Opt; -- cgit v1.2.3-70-g09d2 From 51199aae80013073d4f1a0749a36051dcee591c1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 20 May 2022 10:48:04 -0400 Subject: moved explore mode to topBar. fixed highlighting of overlay toggle. fixed pointerEvents on lockedPosition collectoins that are not children of a free form view. --- src/client/util/CurrentUserUtils.ts | 10 ++++---- src/client/views/MainView.tsx | 15 ++++++------ src/client/views/StyleProvider.tsx | 20 +++++++--------- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 4 +++- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +----- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/button/ButtonScripts.ts | 4 +++- src/client/views/topbar/TopBar.tsx | 28 +++++++++++++++------- 10 files changed, 50 insertions(+), 44 deletions(-) (limited to 'src/client/views/nodes/FieldView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 78bf531c6..8fed6e940 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1009,7 +1009,7 @@ export class CurrentUserUtils { title: "Header Color", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()', }, // Only when a document is selected - { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay(_readOnly_)', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform + { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", backgroundColor: 'toggleOverlay(true)', click: 'toggleOverlay()', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected { title: "Text", type: "textTools", subMenu: true, expanded: 'selectedDocumentType("rtf")' }, // Always available { title: "Ink", type: "inkTools", subMenu: true, expanded: 'selectedDocumentType("ink")' }, // Always available @@ -1023,7 +1023,7 @@ export class CurrentUserUtils { if (doc.contextMenuBtns === undefined) { const docList: Doc[] = []; - (await CurrentUserUtils.contextMenuTools(doc)).map(({ title, width, list, toolTip, ignoreClick, icon, type, btnType, click, script, subMenu, hidden, expanded }) => { + (await CurrentUserUtils.contextMenuTools(doc)).map(({ title, width, list, toolTip, backgroundColor, ignoreClick, icon, type, btnType, click, script, subMenu, hidden, expanded }) => { const menuDocList: Doc[] = []; if (subMenu) { // default is textTools @@ -1046,7 +1046,7 @@ export class CurrentUserUtils { break; } tools.map(({ title, toolTip, icon, btnType, numBtnType, numBtnMax, numBtnMin, click, script, width, list, ignoreClick, switchToggle }) => { - const computed = click ? ComputedField.MakeFunction(click) as any : "transparent"; + const backgroundColor = click ? ComputedField.MakeFunction(click) as any : "transparent"; menuDocList.push(Docs.Create.FontIconDocument({ _nativeWidth: width ? width : 25, _nativeHeight: 25, @@ -1069,7 +1069,7 @@ export class CurrentUserUtils { title, switchToggle, color: Colors.WHITE, - backgroundColor: computed, + backgroundColor, _dropAction: "alias", _removeDropProperties: new List(["dropAction", "_stayInCollection"]), onClick: click ? ScriptField.MakeScript(click) : undefined @@ -1105,7 +1105,7 @@ export class CurrentUserUtils { dontUndo: true, title, color: Colors.WHITE, - // backgroundColor: checkResult ? ComputedField.MakeFunction(checkResult, {}, {_readOnly_:true}) as any : "transparent", + backgroundColor: backgroundColor ? ComputedField.MakeFunction(backgroundColor) as any : "transparent", _dropAction: "alias", hidden: hidden ? ComputedField.MakeFunction(hidden) as any : undefined, _removeDropProperties: new List(["dropAction", "_stayInCollection"]), diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2e1d10955..9be00fa9e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -273,6 +273,12 @@ export class MainView extends React.Component { Doc.AddDocToList(this.userDoc.myFilesystem as Doc, "data", folder); } + @observable _exploreMode = false; + @computed get exploreMode() { + return () => this._exploreMode ? ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", + { documentView: "any", clientX: "number", clientY: "number" })! : undefined; + } + @computed get mainDocView() { return ; } - @computed get topbar() { - TraceMobx(); - return
- -
; - } - @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts return !DocumentLinksButton.invisibleWebDoc ? null :
@@ -625,7 +624,7 @@ export class MainView extends React.Component { - {this.topbar} + {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? DocumentLinksButton.LinkEditorDocView = undefined)} docView={DocumentLinksButton.LinkEditorDocView} /> : (null)} {LinkDocPreview.LinkInfo ? : (null)} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 93da2fa19..7ac40fc8e 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -156,15 +156,14 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? - Doc.UserDoc().activeCollectionNestedBackground : - Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ? - Colors.BLACK : - "linear-gradient(#065fff, #85c1f9)")) - )); + doc.annotationOn ? "#00000015" : // faint interior for collections on PDFs, images, etc + (doc?._isGroup ? undefined : + StrCast((props?.renderDepth || 0) > 0 ? + Doc.UserDoc().activeCollectionNestedBackground : + Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ? + Colors.BLACK : + "linear-gradient(#065fff, #85c1f9)")) + )); break; //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break; @@ -203,7 +202,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 && + return doc && (isBackground() || selected) && !Doc.IsSystem(doc) && (props?.renderDepth || 0) > 0 && ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
toggleLockedPosition(doc)}> @@ -236,7 +235,6 @@ export function DashboardStyleProvider(doc: Opt, props: Opt; } return DefaultStyleProvider(doc, props, property); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 7c5f49b42..19485a0eb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -261,7 +261,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent + style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? "none" : undefined }}> {this.showIsTagged()} {this.renderSubView(this.collectionViewType, props)}
); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index cebc3f779..43f31813c 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -9,6 +9,7 @@ import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; import { FieldId } from "../../../fields/RefField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils"; @@ -24,6 +25,7 @@ import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { Colors, Shadows } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; +import { MainView } from '../MainView'; import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; @@ -33,7 +35,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionView, CollectionViewType } from './CollectionView'; import "./TabDocView.scss"; import React = require("react"); -import { List } from '../../../fields/List'; const _global = (window /* browser */ || global /* node */) as any; interface TabDocViewProps { @@ -354,6 +355,7 @@ export class TabDocView extends React.Component { DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} + onBrowseClick={MainView.Instance.exploreMode} isContentActive={returnTrue} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 916cc9c05..df09569ef 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -624,10 +624,6 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.onBrowseClickHandler()) { - // if (this.Document[this.scaleFieldKey] !== 0.5) { - // this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 0.5); - // } - // else if (this.props.DocumentView?.()) { this.onBrowseClickHandler().script.run({ documentView: this.props.DocumentView(), clientX: e.clientX, clientY: e.clientY }); } @@ -961,7 +957,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._lockedTransform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1564,7 +1560,6 @@ export class CollectionFreeFormView extends CollectionSubView this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", { documentView: "any", clientX: "number", clientY: "number" }), icon: "compress-arrows-alt" }); !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1a74a4500..f5ad47ca7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -177,7 +177,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onDoubleClick?: () => ScriptField; onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; - onBrowseClick?: () => ScriptField; + onBrowseClick?: () => (ScriptField | undefined); } // these props are only available in DocumentViewIntenral diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 33ed8cd89..94937430e 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -24,7 +24,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { isSelected: (outsideReaction?: boolean) => boolean; scaling?: () => number; setHeight?: (height: number) => void; - onBrowseClick?: () => ScriptField; + onBrowseClick?: () => (ScriptField | undefined); // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: () => Opt; diff --git a/src/client/views/nodes/button/ButtonScripts.ts b/src/client/views/nodes/button/ButtonScripts.ts index f3731b8f9..b4a382faf 100644 --- a/src/client/views/nodes/button/ButtonScripts.ts +++ b/src/client/views/nodes/button/ButtonScripts.ts @@ -1,5 +1,6 @@ import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; import { SelectionManager } from "../../../util/SelectionManager"; +import { Colors } from "../../global/globalEnums"; // toggle: Set overlay status of selected document ScriptingGlobals.add(function changeView(view: string) { @@ -8,7 +9,8 @@ ScriptingGlobals.add(function changeView(view: string) { }); // toggle: Set overlay status of selected document -ScriptingGlobals.add(function toggleOverlay() { +ScriptingGlobals.add(function toggleOverlay(readOnly?: boolean) { const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; + if (readOnly) return selected?.Document.z ? Colors.MEDIUM_BLUE : "transparent"; selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("failed"); }); \ No newline at end of file diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0af7de6af..be248ab92 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -1,4 +1,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from "@material-ui/core"; +import { action } from "mobx"; import { observer } from "mobx-react"; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; @@ -9,6 +11,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SettingsManager } from "../../util/SettingsManager"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { Borders, Colors } from "../global/globalEnums"; +import { MainView } from "../MainView"; import "./TopBar.scss"; /** @@ -40,20 +43,28 @@ export class TopBar extends React.Component {
-
{ + Create a new dashboard
} placement="bottom">
{ const batch = UndoManager.StartBatch("new dash"); await CurrentUserUtils.createNewDashboard(Doc.UserDoc()); batch.end(); }}> {"New"}
- {
{ - const batch = UndoManager.StartBatch("snapshot"); - await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); - batch.end(); - }}> - {"Snapshot"} -
} + + Work on a copy of the dashboard layout
} placement="bottom"> +
{ + const batch = UndoManager.StartBatch("snapshot"); + await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); + batch.end(); + }}> + {"Snapshot"} +
+ + Browsing mode for directly navigating to documents} placement="bottom"> +
MainView.Instance._exploreMode = !MainView.Instance._exploreMode)}> + {"Explore"} +
+
@@ -64,7 +75,6 @@ export class TopBar extends React.Component {
SettingsManager.Instance.open()}> {"Settings"}
-
-- cgit v1.2.3-70-g09d2 From 3fe0e0e02a6c9bd717b3df9b000c13d1131f6eb4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 23 May 2022 12:28:31 -0400 Subject: cleaning up singleLine text box api and TreeView types --- src/client/util/CurrentUserUtils.ts | 7 +-- src/client/views/MainView.tsx | 5 +- .../views/collections/CollectionTreeView.tsx | 29 ++++++---- src/client/views/collections/TreeView.tsx | 35 ++++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 34 ++++++++++-- .../collections/collectionFreeForm/MarqueeView.tsx | 13 +++-- src/client/views/nodes/DocumentView.tsx | 2 + src/client/views/nodes/FieldView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 7 +-- .../formattedText/ProsemirrorExampleTransfer.ts | 62 ++++++---------------- 10 files changed, 101 insertions(+), 96 deletions(-) (limited to 'src/client/views/nodes/FieldView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 85769d915..1ebb5365a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -16,6 +16,7 @@ import { Docs, DocumentOptions, DocUtils } from "../documents/Documents"; import { DocumentType } from "../documents/DocumentTypes"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { CollectionFreeFormView } from "../views/collections/collectionFreeForm"; +import { TreeViewType } from "../views/collections/CollectionTreeView"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { TreeView } from "../views/collections/TreeView"; import { Colors } from "../views/global/globalEnums"; @@ -215,7 +216,7 @@ export class CurrentUserUtils { if (doc.emptySlide === undefined) { doc.emptySlide = Docs.Create.TreeDocument([], { ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined, - allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" + allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" }); } if (doc.emptyHeader === undefined) { @@ -563,7 +564,7 @@ export class CurrentUserUtils { title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true, + _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." })); const toggleDarkTheme = ScriptField.MakeScript(`this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`); @@ -616,7 +617,7 @@ export class CurrentUserUtils { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." })); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 6a2df3b51..09a57843c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -8,11 +8,9 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; import { PromiseValue, StrCast } from '../../fields/Types'; -import { TraceMobx } from '../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; @@ -34,6 +32,7 @@ import { CollectionDockingView } from './collections/CollectionDockingView'; import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; +import { TreeViewType } from './collections/CollectionTreeView'; import { CollectionViewType } from './collections/CollectionView'; import "./collections/TreeView.scss"; import { ComponentDecorations } from './ComponentDecorations'; @@ -263,7 +262,7 @@ export class MainView extends React.Component { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." })); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5e89016db..99ffb9bb0 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -27,6 +27,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { TreeView } from "./TreeView"; import React = require("react"); +import { FieldViewProps } from "../nodes/FieldView"; const _global = (window /* browser */ || global /* node */) as any; export type collectionTreeViewProps = { @@ -39,6 +40,12 @@ export type collectionTreeViewProps = { onChildClick?: () => ScriptField; }; +export enum TreeViewType { + outline = "outline", + fileSystem = "fileSystem", + default = "default" +} + @observer export class CollectionTreeView extends CollectionSubView>() { private _treedropDisposer?: DragManager.DragDropDisposer; @@ -54,8 +61,8 @@ export class CollectionTreeView extends CollectionSubView StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === "outline") this.makeTextCollection(this.treeChildren); + if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} />; } + onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { + if (this.outlineMode && e.key === "Enter") { + e.stopPropagation(); + this.makeTextCollection(this.treeChildren); + return true; + } + } get documentTitle() { return this._titleRef = r} - onKeyDown={e => { - if (this.outlineMode) { - e.stopPropagation(); - e.key === "Enter" && this.makeTextCollection(this.treeChildren); - } - }}> + ref={r => this._titleRef = r}> {this.outlineMode ? this.documentTitle : this.editableTitle} ; } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 65f8fe248..70ad23f41 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -26,11 +26,12 @@ import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFun import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { StyleProp } from '../StyleProvider'; -import { CollectionTreeView } from './CollectionTreeView'; +import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView, CollectionViewType } from './CollectionView'; import "./TreeView.scss"; import React = require("react"); import { KeyValueBox } from '../nodes/KeyValueBox'; +import { FieldViewProps } from '../nodes/FieldView'; export interface TreeViewProps { treeView: CollectionTreeView; @@ -241,7 +242,7 @@ export class TreeView extends React.Component { layout: CollectionView.LayoutString("data"), title: "-title-", treeViewExpandedViewLock: true, treeViewExpandedView: "data", - _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: "outline", + _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _width: 1000, _height: 10 }); Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text'); @@ -604,24 +605,29 @@ export class TreeView extends React.Component { if (property.startsWith(StyleProp.Decorations)) return (null); return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView } - onKeyDown = (e: React.KeyboardEvent) => { + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { switch (e.key) { case "Tab": - e.stopPropagation(); - e.preventDefault(); + e.stopPropagation?.(); + e.preventDefault?.(); setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150); - return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab"); + UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab"); + return true; case "Backspace": - e.stopPropagation(); - e.preventDefault(); - return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc); + if (!(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc)) { + e.stopPropagation?.(); + e.preventDefault?.(); + return true; + } + break; case "Enter": - e.stopPropagation(); - e.preventDefault(); + e.stopPropagation?.(); + e.preventDefault?.(); return UndoManager.RunInBatch(this.makeTextCollection, "bullet"); } } + return false; } titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - 2 * treeBulletWidth())); @@ -758,6 +764,7 @@ export class TreeView extends React.Component { hideResizeHandles={this.props.treeView.outlineMode} focus={this.refocus} ContentScaling={returnOne} + onKey={this.onKeyDown} hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} ScreenToLocalTransform={this.docTransform} @@ -800,7 +807,7 @@ export class TreeView extends React.Component { @computed get renderBorder() { const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } }; - return
+ return
{!this.treeViewOpen ? (null) : this.renderContent}
; } @@ -821,9 +828,7 @@ export class TreeView extends React.Component { return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document - onKeyDown={this.onKeyDown}> + onDrop={this.onTreeDrop}>
  • {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader" this.renderEmbeddedDocument(false, returnFalse) : diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index df09569ef..3b32cf57d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,18 +1,18 @@ import { Bezier } from "bezier-js"; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { DateField } from "../../../../fields/DateField"; -import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; +import { DataSym, Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; -import { ImageField } from "../../../../fields/URLField"; import { createSchema, listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; +import { ImageField } from "../../../../fields/URLField"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils"; @@ -26,6 +26,7 @@ import { DragManager, dropActionType } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; import { InteractionUtils } from "../../../util/InteractionUtils"; import { LinkManager } from "../../../util/LinkManager"; +import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; import { SearchUtil } from "../../../util/SearchUtil"; import { SelectionManager } from "../../../util/SelectionManager"; import { ColorScheme } from "../../../util/SettingsManager"; @@ -47,13 +48,14 @@ import { CreateImage } from "../../nodes/WebBoxRenderer"; import { StyleProp } from "../../StyleProvider"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; +import { TreeViewType } from "../CollectionTreeView"; import { CollectionViewType } from "../CollectionView"; import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; +import { FieldView, FieldViewProps } from "../../nodes/FieldView"; export const panZoomSchema = createSchema({ _panX: "number", @@ -957,7 +959,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1160,6 +1162,27 @@ export class CollectionFreeFormView extends CollectionSubView this.props.isSelected() || this.props.isContentActive(); + @undoBatch + @action + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { + const docView = fieldProps.DocumentView?.(); + if (docView && docView.rootDoc._singleLine && ["Tab", "Enter"].includes(e.key)) { + e.stopPropagation?.(); + const below = !e.altKey && e.key !== "Tab"; + const layoutKey = StrCast(docView.LayoutFieldKey); + const newDoc = Doc.MakeCopy(docView.rootDoc, true); + const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; + newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; + if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10; + else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10; + if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = docView.rootDoc[layoutKey]; + } + Doc.GetProto(newDoc).text = undefined; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + return this.addDocument?.(newDoc); + } + } pointerEvents = () => { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = this.props.isContentActive() === false ? "none" : @@ -1185,6 +1208,7 @@ export class CollectionFreeFormView extends CollectionSubView Transform; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f5ad47ca7..f7312e59c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -50,6 +50,7 @@ import { ScriptingBox } from "./ScriptingBox"; import { PresBox } from './trails/PresBox'; import React = require("react"); import { DocServer } from "../../DocServer"; +import { FieldViewProps } from "./FieldView"; const { Howl } = require('howler'); interface Window { @@ -178,6 +179,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; onBrowseClick?: () => (ScriptField | undefined); + onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined); } // these props are only available in DocumentViewIntenral diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 94937430e..79c1f1c40 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -5,7 +5,7 @@ import { DateField } from "../../../fields/DateField"; import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { WebField } from "../../../fields/URLField"; -import { DocumentViewSharedProps } from "./DocumentView"; +import { DocumentView, DocumentViewSharedProps } from "./DocumentView"; import { ScriptField } from "../../../fields/ScriptField"; // @@ -25,6 +25,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { scaling?: () => number; setHeight?: (height: number) => void; onBrowseClick?: () => (ScriptField | undefined); + onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined); // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: () => Opt; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 164bcb9b0..0e29461a6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -17,6 +17,7 @@ import { InkTool } from '../../../../fields/InkField'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from "../../../../fields/RichTextField"; import { RichTextUtils } from '../../../../fields/RichTextUtils'; +import { ComputedField } from '../../../../fields/ScriptField'; import { Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; @@ -62,7 +63,6 @@ import { schema } from "./schema_rts"; import { SummaryView } from "./SummaryView"; import applyDevTools = require("prosemirror-dev-tools"); import React = require("react"); -import { ComputedField } from '../../../../fields/ScriptField'; const translateGoogleApi = require("translate-google-api"); export interface FormattedTextBoxProps { @@ -1471,11 +1471,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, "titler"); } } + 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; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index c76eda859..0dd0a8411 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -1,20 +1,15 @@ -import { chainCommands, exitCode, joinDown, joinUp, lift, deleteSelection, joinBackward, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn, newlineInCode } from "prosemirror-commands"; -import { liftTarget } from "prosemirror-transform"; +import { chainCommands, deleteSelection, exitCode, joinBackward, joinDown, joinUp, lift, newlineInCode, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn } from "prosemirror-commands"; import { redo, undo } from "prosemirror-history"; import { Schema } from "prosemirror-model"; -import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; -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, DocListCast, AclAugment, AclSelfEdit } 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"; +import { splitListItem, wrapInList } from "prosemirror-schema-list"; +import { EditorState, TextSelection, Transaction } from "prosemirror-state"; +import { liftTarget } from "prosemirror-transform"; +import { AclAugment, AclSelfEdit, Doc } from "../../../../fields/Doc"; import { GetEffectiveAcl } from "../../../../fields/util"; +import { Utils } from "../../../../Utils"; +import { Docs } from "../../../documents/Documents"; +import { SelectionManager } from "../../../util/SelectionManager"; +import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; @@ -48,29 +43,6 @@ export function buildKeymap>(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.Document.treeViewType === "outline") return true; // bcz: Arghh .. need to determine if this is an treeViewOutlineBox in which case Enter's are ignored.. - 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([]) : 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; - }; - const canEdit = (state: any) => { switch (GetEffectiveAcl(props.Document)) { case AclAugment: return false; @@ -109,11 +81,7 @@ export function buildKeymap>(schema: S, props: any, mapKey bind("Ctrl-i", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state as any, dispatch as any)); bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => 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; - } + if (props.onKey?.({ key: "Tab" }, props)) return true; if (!canEdit(state)) return true; const ref = state.selection; const range = ref.$from.blockRange(ref.$to); @@ -138,8 +106,7 @@ export function buildKeymap>(schema: S, props: any, mapKey }); bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - /// bcz; Argh!! replace with a onShiftTab prop conditionally handles Tab); - if (props.Document._singleLine) return true; + if (props.onKey?.({ key: "Tab", shiftKey: true })) return true; // single line docs don't process tabs so that their containers can decide what to do. This should be a prop if (!canEdit(state)) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); @@ -188,13 +155,14 @@ export function buildKeymap>(schema: S, props: any, mapKey }; //Command to create a text document to the right of the selected textbox - bind("Alt-Enter", () => addTextBox(false, true)); + bind("Alt-Enter", () => true); //Command to create a text document to the bottom of the selected textbox - bind("Ctrl-Enter", () => addTextBox(true, true)); + bind("Ctrl-Enter", () => true); // backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward); bind("Backspace", (state: EditorState, dispatch: (tx: Transaction>) => void) => { + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; if (!deleteSelection(state, (tx: Transaction) => { @@ -216,8 +184,8 @@ export function buildKeymap>(schema: S, props: any, mapKey //newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock //command to break line bind("Enter", (state: EditorState, dispatch: (tx: Transaction>) => void) => { - if (addTextBox(true, false)) return true; + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; const trange = state.selection.$from.blockRange(state.selection.$to); -- cgit v1.2.3-70-g09d2