From 72dad52c4fea5a2fccabacbb6a49ca1494093954 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Jun 2023 10:14:26 -0400 Subject: cleaned up dragging - abort presItem drags properly, fix naming for drag/dropAction, small fix undo of drag removeproperties, dragging in/out of headerBar, fixed isContentActive to avoid SnappingManager.GetIsDragging. fixed resizing videos. --- src/client/views/nodes/ComparisonBox.scss | 2 +- src/client/views/nodes/ComparisonBox.tsx | 80 ++++++++++++++-------- src/client/views/nodes/DocumentView.tsx | 52 +++++++++----- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 4 +- src/client/views/nodes/KeyValueBox.tsx | 8 +-- src/client/views/nodes/KeyValuePair.tsx | 1 - src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 5 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 - src/client/views/nodes/WebBox.tsx | 14 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 21 +++--- src/client/views/nodes/trails/PresBox.tsx | 4 +- src/client/views/nodes/trails/PresElementBox.tsx | 13 ++-- 15 files changed, 126 insertions(+), 86 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 660045a6f..a12f1c12b 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -93,4 +93,4 @@ display: flex; } } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index e6a4635c0..d747c4527 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -2,11 +2,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { DocCast, NumCast, StrCast } from '../../../fields/Types'; import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; +import { Docs, DocUtils } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; -import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; @@ -32,15 +31,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { this._disposers[disposerId]?.(); if (ele) { - // create disposers identified by disposerId to remove drag & drop listeners this._disposers[disposerId] = DragManager.MakeDropTarget(ele, (e, dropEvent) => this.internalDrop(e, dropEvent, fieldKey), this.layoutDoc); } }; @@ -50,29 +46,40 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey)); + res && (droppedDocs.lastElement().embedContainer = this.dataDoc); + return res; } }; private registerSliding = (e: React.PointerEvent, targetWidth: number) => { - e.button !== 2 && + if (e.button !== 2) { setupMoveUpEvents( this, e, this.onPointerMove, emptyFunction, + action((e, doubleTap) => { + if (doubleTap) { + this._isAnyChildContentActive = true; + if (!this.dataDoc[this.fieldKey + '_1']) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); + if (!this.dataDoc[this.fieldKey + '_2']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); + } + }), + false, + undefined, action(() => { - // on click, animate slider movement to the targetWidth + if (this._isAnyChildContentActive) return; this._animating = 'all 200ms'; + // on click, animate slider movement to the targetWidth this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this.props.PanelWidth(); setTimeout( action(() => (this._animating = '')), 200 ); - }), - false + }) ); + } }; @action @@ -86,7 +93,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { const anchor = Docs.Create.ConfigDocument({ - title: 'ImgAnchor:' + this.rootDoc.title, + title: 'CompareAnchor:' + this.rootDoc.title, // set presentation timing properties for restoring view presTransition: 1000, annotationOn: this.rootDoc, @@ -105,12 +112,29 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent boolean, which: string) => this.remDoc(doc, which) && addDocument(doc); + addDoc = (doc: Doc, which: string) => { + this.dataDoc[which] = doc; + return true; + }; + remDoc = (doc: Doc, which: string) => { + if (this.dataDoc[which] === doc) { + this.dataDoc[which] = undefined; + return true; + } + return false; + }; + + whenChildContentsActiveChanged = action((isActive: boolean) => (this._isAnyChildContentActive = isActive)); docStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; return this.props.styleProvider?.(doc, props, property); }; - + moveDoc1 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); + moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); + remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); + remDoc2 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_2'), true); render() { const clearButton = (which: string) => { return ( @@ -118,33 +142,35 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent e.stopPropagation()} // prevent triggering slider movement in registerSliding onClick={e => this.clearDoc(e, which)}> - + ); }; const displayDoc = (which: string) => { - const whichDoc = Cast(this.dataDoc[which], Doc, null); - // if (whichDoc?.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null); - const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc; - return whichDoc ? ( + const whichDoc = DocCast(this.dataDoc[which]); + const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc); + return targetDoc ? ( <> {clearButton(which)} // placeholder image if doc is missing ) : (
- +
); }; @@ -157,7 +183,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent +
{displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)}
{displayBox(`${this.fieldKey}_1`, 0, 0)} @@ -169,7 +195,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined, }} - onPointerDown={e => this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ + onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ >
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 23148ed34..5470a72f5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -14,7 +14,7 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, return18, returnEmptyString, returnFalse, returnTrue, returnVal, returnZero, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../../DocServer'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -47,6 +47,7 @@ import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; import { FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; +import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; @@ -163,6 +164,7 @@ export interface DocumentViewSharedProps { docViewPath: () => DocumentView[]; childHideDecorationTitle?: () => boolean; childHideResizeHandles?: () => boolean; + childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt styleProvider: Opt; setTitleFocus?: () => void; @@ -182,7 +184,7 @@ export interface DocumentViewSharedProps { pinToPres: (document: Doc, pinProps: PinProps) => void; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; - canEmbedOnDrag?: boolean; + dragAction?: dropActionType; treeViewDoc?: Doc; xPadding?: number; yPadding?: number; @@ -194,7 +196,6 @@ export interface DocumentViewSharedProps { forceAutoHeight?: boolean; disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected - enableDragWhenActive?: boolean; waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; defaultDoubleClick?: () => 'default' | 'ignore' | undefined; pointerEvents?: () => Opt; @@ -314,7 +315,7 @@ export class DocumentViewInternal extends DocComponent { + if (de.complete.docDragData && this.isContentActive()) { + targetAction && (de.complete.docDragData.dropAction = targetAction); + e.stopPropagation(); + } + }; setupHandlers() { this.cleanupHandlers(false); if (this._mainCont.current) { - this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document); + this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document, this.preDropFunc); this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)); this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)); } @@ -387,7 +393,7 @@ export class DocumentViewInternal extends DocComponent (ffview.ChildDrag = this.props.DocumentView())); DragManager.StartDocumentDrag( @@ -478,7 +484,7 @@ export class DocumentViewInternal extends DocComponent (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title)); + clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title); } else { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { @@ -506,7 +512,7 @@ export class DocumentViewInternal extends DocComponent { this._longPressSelector = setTimeout(() => { if (DocumentView.LongPress) { - if (this.rootDoc.dontUndo) { + if (this.rootDoc.undoIgnoreFields) { runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); } else { this.props.select(false); @@ -535,7 +541,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return; + if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; if (this.props.Document === Doc.ActiveDashboard) { + e.stopPropagation(); alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.'); - return; + e.preventDefault(); + return true; } const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData; if (linkdrag) { @@ -625,8 +633,10 @@ export class DocumentViewInternal extends DocComponent (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); isContentActive = (outsideReaction?: boolean): boolean | undefined => { - return this.props.isContentActive() === false + // true - if the document has been activated directly or indirectly (by having its children selected) + // false - if its pointer events are explicitly turned off or if it's container tells it that it's inactive + // undefined - it is not active, but it should be responsive to actions that might active it or its contents (eg clicking) + return this.props.isContentActive() === false || this.props.pointerEvents?.() === 'none' || (this.rootDoc.pointerEvents === 'none' && !StrCast(this.props.LayoutTemplateString).includes(KeyValueBox.name)) ? false : Doc.ActiveTool !== InkTool.None || SnappingManager.GetIsDragging() || @@ -871,17 +884,18 @@ export class DocumentViewInternal extends DocComponent Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc)); const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc)); return !this.props.LayoutTemplateString && - !this.props.isSelected() && + !this.isContentActive() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb && !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) && - ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking) && - !this._componentView?.isAnyChildContentActive?.() + ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking) ? true : false; }; childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; - contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents); + + /// disable pointer events on content when there's an enabled onClick script, or if contents are marked inactive + contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler) || this.isContentActive() === false ? 'none' : this.pointerEvents); @computed get contents() { TraceMobx(); const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString; @@ -889,7 +903,7 @@ export class DocumentViewInternal extends DocComponent {!this._retryThumb || !this.thumbShown() ? null : ( diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 85dd779fc..4ebf22ddf 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -45,7 +45,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { @observer export class FieldView extends React.Component { public static LayoutString(fieldType: { name: string }, fieldStr: string) { - return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" + return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" } @computed diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9acbee1e7..64d6814df 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -387,7 +387,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))} style={{ - display: (SnappingManager.GetIsDragging() && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none', + display: (this.props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none', width: 'min(10%, 25px)', height: 'min(10%, 25px)', background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray', @@ -505,7 +505,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { document.addEventListener('pointerup', this.onDividerUp); }; - getFieldView = async () => { + getFieldView = () => { const rows = this.rows.filter(row => row.isChecked); if (rows.length > 1) { - const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true }); + const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document).title}`, _chromeHidden: true }); for (const row of rows) { - const field = this.createFieldView(DocCast(this.props.Document.data), row); + const field = this.createFieldView(DocCast(this.props.Document), row); field && Doc.AddDocToList(parent, 'data', field); row.uncheck(); } return parent; } - return rows.length ? this.createFieldView(DocCast(this.props.Document.data), rows.lastElement()) : undefined; + return rows.length ? this.createFieldView(DocCast(this.props.Document), rows.lastElement()) : undefined; }; createFieldView = (templateDoc: Doc, row: KeyValuePair) => { diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index d0db60b37..01acdccb7 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -67,7 +67,6 @@ export class KeyValuePair extends React.Component { isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, - dropAction: 'embed', bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index e86b881a8..9bcd04cf5 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -47,7 +47,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { if (separation > 100) { const dragData = new DragManager.DocumentDragData([this.rootDoc]); dragData.dropAction = 'embed'; - dragData.removeDropProperties = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick']; + dragData.dropPropertiesToRemove = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick']; DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]); return true; } else { diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 93e54ffb7..de0b57fd7 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -512,9 +512,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { - return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'; - }; + pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); + @computed get annotationLayer() { return (
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 72f37b62c..a9154c5bb 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -510,7 +510,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { - return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'; + return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'; }; @computed get annotationLayer() { return ( diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 6d040ca1a..fd4c6366b 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -559,7 +559,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent ); } - isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath())); @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; @@ -592,7 +591,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance?.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'); - annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None ? 'all' : 'none'); + pointerEvents = () => + !this._draggingSidebar && this.props.isContentActive() && !MarqueeOptionsMenu.Instance?.isShown() + ? 'all' // + : 'none'; + annotationPointerEvents = () => (this.props.isContentActive() && (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none'); render() { const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any); @@ -1013,7 +1015,11 @@ export class WebBox extends ViewBoxAnnotatableComponent + style={{ + pointerEvents: this.pointerEvents(), // + position: SnappingManager.GetIsDragging() ? 'absolute' : undefined, + display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined, + }}>
{ - if (this._editorView) { + if (this._editorView && (this._editorView as any).docView) { const state = this._editorView.state.apply(tx); this._editorView.updateState(state); @@ -2020,17 +2020,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent= 10 ? '-selected' : ''; + const selPad = (active && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0; + const selPaddingClass = active && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : ''; const styleFromLayoutString = Doc.styleFromLayoutString(this.rootDoc, this.layoutDoc, this.props, scale); // this converts any expressions in the format string to style props. e.g., return styleFromLayoutString?.height === '0px' ? null : (
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 4f7d2e1c1..ef1c3911c 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1029,9 +1029,6 @@ export class PresBox extends ViewBoxBaseComponent() { removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => this.props.isContentActive(outsideReaction); - //.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false; - /** * For sorting the array so that the order is maintained when it is dropped. */ @@ -2462,6 +2459,7 @@ export class PresBox extends ViewBoxBaseComponent() { childIgnoreNativeSize={true} moveDocument={returnFalse} ignoreUnrendered={true} + childDragAction="move" //childLayoutFitWidth={returnTrue} childOpacity={returnOne} childClickScript={PresBox.navigateToDocScript} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 34e069046..f31cf6147 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -192,13 +192,14 @@ export class PresElementBox extends ViewBoxBaseComponent() { const dragArray = this.presBoxView?._dragArray ?? []; const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); - dragData.dropAction = 'move'; dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; dragData.moveDocument = this.props.moveDocument; const dragItem: HTMLElement[] = []; + const classesToRestore = new Map(); if (dragArray.length === 1) { const doc = this._itemRef.current || dragArray[0]; if (doc) { + classesToRestore.set(doc, doc.className); doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide'; dragItem.push(doc); } @@ -212,16 +213,19 @@ export class PresElementBox extends ViewBoxBaseComponent() { dragItem.push(doc); } - // const dropEvent = () => runInAction(() => this._dragging = false); if (activeItem) { + runInAction(() => (this._dragging = true)); DragManager.StartDocumentDrag( dragItem.map(ele => ele), dragData, e.clientX, e.clientY, - undefined + undefined, + action(() => { + Array.from(classesToRestore).forEach(pair => (pair[0].className = pair[1])); + this._dragging = false; + }) ); - // runInAction(() => this._dragging = true); return true; } return false; @@ -536,7 +540,6 @@ export class PresElementBox extends ViewBoxBaseComponent() {
{ e.stopPropagation(); if (this._itemRef.current && this._dragRef.current) { -- cgit v1.2.3-70-g09d2 From 5c32758dbc26a0c0e034d878e9dff633061dc2c6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Jun 2023 10:32:04 -0400 Subject: fix so that text boxes don't sometimes collapse when being dragged. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2cd3c6cd6..2e8f6c696 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1837,7 +1837,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0); const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined; - if (children) { + if (children && !SnappingManager.GetIsDragging()) { const toNum = (val: string) => Number(val.replace('px', '').replace('auto', '0')); const toHgt = (node: Element) => { const { height, marginTop, marginBottom } = getComputedStyle(node); @@ -1848,6 +1848,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight); + if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) { setScrollHeight(); } else { -- cgit v1.2.3-70-g09d2 From b599b69dd0892de1b98807a7f8b4a8badcd8abe0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Jun 2023 21:15:24 -0400 Subject: fixed placement of link preview in sidebar to be on screen. got rid of transition for display doc border on hover. fixed showing link targets in menu when source is an annotation. fixed crashes when their is no context path for a showDocument --- src/client/util/DocumentManager.ts | 29 ++++++++++++++++------------- src/client/util/LinkManager.ts | 6 ++---- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/DocumentView.scss | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 612f16ce9..7e3302067 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -246,16 +246,18 @@ export class DocumentManager { ) => { const docContextPath = DocumentManager.GetContextPath(targetDoc, true); if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false; - let rootContextView = await new Promise(res => { - const viewIndex = docContextPath.findIndex(doc => this.getDocumentView(doc)); - if (viewIndex !== -1) { - viewIndex && docContextPath.splice(0, viewIndex); - return res(this.getDocumentView(docContextPath[0])!); - } - options.didMove = true; - docContextPath.some(doc => TabDocView.Activate(doc)) || DocumentViewInternal.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight); - this.AddViewRenderedCb(docContextPath[0], dv => res(dv)); - }); + let rootContextView = + docContextPath.length && + (await new Promise(res => { + const viewIndex = docContextPath.findIndex(doc => this.getDocumentView(doc)); + if (viewIndex !== -1) { + viewIndex && docContextPath.splice(0, viewIndex); + return res(this.getDocumentView(docContextPath[0])!); + } + options.didMove = true; + docContextPath.some(doc => TabDocView.Activate(doc)) || DocumentViewInternal.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight); + this.AddViewRenderedCb(docContextPath[0], dv => res(dv)); + })); if (options.openLocation === OpenWhere.lightbox) { // even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox) const target = DocCast(targetDoc.annotationOn, targetDoc); @@ -269,9 +271,10 @@ export class DocumentManager { const innerDoc = docContextPath.shift(); return { viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined }; }; - const target = await this.focusViewsInPath(rootContextView, options, childViewIterator); - this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc); - + if (rootContextView) { + const target = await this.focusViewsInPath(rootContextView, options, childViewIterator); + this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc); + } finished?.(); }; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 3aa72f501..ce422f849 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -194,10 +194,8 @@ export class LinkManager { public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { const a1 = Cast(linkDoc.link_anchor_1, Doc, null); const a2 = Cast(linkDoc.link_anchor_2, Doc, null); - if (Doc.AreProtosEqual(anchor, a1)) return a2; - if (Doc.AreProtosEqual(anchor, a2)) return a1; - if (Doc.AreProtosEqual(anchor, a1.annotationOn as Doc)) return a2; - if (Doc.AreProtosEqual(anchor, a2.annotationOn as Doc)) return a1; + if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1.annotationOn, a1))) return a2; + if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2.annotationOn, a2))) return a1; if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; } } diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 9ceac3b8c..737d675aa 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -170,7 +170,7 @@ export class LinkMenuItem extends React.Component { linkSrc: this.props.sourceDoc, linkDoc: this.props.linkDoc, showHeader: false, - location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY], + location: [(this._drag.current?.getBoundingClientRect().left ?? 100) + 40, (this._drag.current?.getBoundingClientRect().top ?? e.clientY) + 25], noPreview: false, }) }> diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 1265651ad..f1627e1e1 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -24,7 +24,7 @@ width: 100%; height: 100%; border-radius: inherit; - transition: outline 0.3s linear; + // transition: outline 0.3s linear; // background: $white; //overflow: hidden; transform-origin: center; -- cgit v1.2.3-70-g09d2 From 51d57ce0a1f618737a51370c09e5fb3f4139f1f9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Jun 2023 22:49:47 -0400 Subject: fixed text transcriptions. --- src/client/views/InkTranscription.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index e38474ea0..c39fa79da 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -124,9 +124,9 @@ export class InkTranscription extends React.Component { const strokes: InkData[] = []; const times: number[] = []; validInks - .filter(i => Cast(i.data, InkField)) + .filter(i => Cast(i[Doc.LayoutFieldKey(i)], InkField)) .forEach(i => { - const d = Cast(i.data, InkField, null); + const d = Cast(i[Doc.LayoutFieldKey(i)], InkField, null); const inkStroke = DocumentManager.Instance.getDocumentView(i)?.ComponentView as InkingStroke; strokes.push(d.inkData.map(pd => inkStroke.ptToScreen({ X: pd.X, Y: pd.Y }))); times.push(DateCast(i.author_date).getDate().getTime()); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5470a72f5..fbc84389d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1099,7 +1099,7 @@ export class DocumentViewInternal extends DocComponent users.user.email === this.dataDoc.author)?.sharingDoc.userColor, + SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.userColor, Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)' ); const layout_sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); -- cgit v1.2.3-70-g09d2 From 1429ab79eac9aa316082f52c14c576f6b3a97111 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 23 Jun 2023 13:14:18 -0400 Subject: cleaned up more issues with pointer events/contents active. fixed dragging from piles. --- src/client/documents/Documents.ts | 7 ++- src/client/util/UndoManager.ts | 3 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 1 + .../collections/CollectionMasonryViewFieldRow.tsx | 9 +-- src/client/views/collections/CollectionMenu.tsx | 3 +- .../views/collections/CollectionNoteTakingView.tsx | 13 +++-- .../collections/CollectionNoteTakingViewColumn.tsx | 1 + .../views/collections/CollectionPileView.tsx | 8 +-- .../collections/CollectionStackedTimeline.tsx | 30 +++++----- .../views/collections/CollectionStackingView.tsx | 10 +++- .../CollectionStackingViewFieldColumn.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 18 +++--- .../views/collections/CollectionTreeView.tsx | 15 +++-- src/client/views/collections/TreeView.tsx | 23 ++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 +++--- .../collections/collectionFreeForm/MarqueeView.tsx | 1 + .../CollectionMulticolumnView.tsx | 1 + .../CollectionMultirowView.tsx | 1 + .../collectionSchema/CollectionSchemaView.tsx | 3 +- src/client/views/nodes/ComparisonBox.tsx | 11 ++-- src/client/views/nodes/DocumentView.tsx | 22 +++++--- src/client/views/nodes/FunctionPlotBox.tsx | 5 +- src/client/views/nodes/ImageBox.tsx | 17 +++--- src/client/views/nodes/LabelBox.tsx | 2 + src/client/views/nodes/ScriptingBox.tsx | 8 ++- .../views/nodes/formattedText/FormattedTextBox.tsx | 64 +++++++++++++--------- src/fields/Proxy.ts | 4 +- src/fields/util.ts | 3 +- 29 files changed, 184 insertions(+), 119 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a61ef1da3..acd323eca 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -361,12 +361,13 @@ export class DocumentOptions { _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)'); _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere'); _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.'); - childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged fromt he collection'); + childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged from the collection'); dropConverter?: ScriptField; // script to run when documents are dropped on this Document. dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else"); _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else"); _dropPropertiesToRemove?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document cloneFieldFilter?: List; // fields not to copy when the document is clonedclipboard?: Doc; + dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group'); dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)'); dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true); dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script @@ -667,7 +668,7 @@ export namespace Docs { { data: new List(), layout: { view: EmptyBox, dataField: defaultDataKey }, - options: { childDragAction: 'embed', title: 'Global Group Database' }, + options: { title: 'Global Group Database' }, }, ], [ @@ -1663,7 +1664,7 @@ export namespace DocUtils { }); }); if (create) { - const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2 }); + const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, dragWhenActive: true }); newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size; newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size; newCollection._width = newCollection._height = size * 2; diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 2379cb2ab..b59af6656 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -1,4 +1,5 @@ import { observable, action, runInAction } from 'mobx'; +import { Field } from '../../fields/Doc'; import { Without } from '../../Utils'; function getBatchName(target: any, key: string | symbol): string { @@ -95,7 +96,7 @@ export namespace UndoManager { export function AddEvent(event: UndoEvent, value?: any): void { if (currentBatch && batchCounter.get() && !undoing) { - console.log(' '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + value); + console.log(' '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + (value instanceof Array ? value.map(val => Field.toScriptString(val)).join(',') : Field.toScriptString(value))); currentBatch.push(event); tempEvents?.push(event); } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 0709d6cb9..3de40a640 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -220,7 +220,7 @@ export function ViewBoxAnnotatableComponent

() Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc); }); const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List; - if (annoDocs instanceof List) annoDocs.push(...added); + if (annoDocs instanceof List) annoDocs.push(...added.filter(add => !annoDocs.includes(add))); else targetDataDoc[annotationKey ?? this.annotationKey] = new List(added); targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now())); } diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 11b89fd69..74dd1c2f7 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -209,6 +209,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { (dv, doc) => { doc.isGroup = !doc.isGroup; doc.forceActive = doc.isGroup; + doc.dragWhenActive = doc.isGroup; } ); } diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 64f9c6a87..6f88f6727 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -98,14 +98,15 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createEmbeddingSelected = false; if (de.complete.docDragData) { - this.props.parent.Document.dropConverter instanceof ScriptField && this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData }); const key = this.props.pivotField; const castedValue = this.getValue(this.heading); const onLayoutDoc = this.onLayoutDoc(key); - de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc)); - this.props.parent.onInternalDrop(e, de); - e.stopPropagation(); + if (this.props.parent.onInternalDrop(e, de)) { + de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc)); + } + return true; } + return false; }); getValue = (value: string): any => { diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index fc3f713ce..7d71bce13 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -427,8 +427,9 @@ export class CollectionViewBaseChrome extends React.Component c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || [])); e.stopPropagation(); + return true; } - return true; + return false; } dragViewDown = (e: React.PointerEvent) => { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 9a3ab8074..f1c4c2cdf 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -441,23 +441,24 @@ export class CollectionNoteTakingView extends CollectionSubView() { docs.splice(previousDocIndex + 1, 0, ...newDocs); } } + return true; } } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); - this.props.addDocument?.(source); + if (!this.props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed e.stopPropagation(); - } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); + return true; + } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) { + return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); + } return false; }; @undoBatch internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) { const dropCreator = annoDragData.dropDocCreator; - annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => { - const dropDoc = dropCreator(annotationOn); - return dropDoc || this.rootDoc; - }; + annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => dropCreator(annotationOn) || this.rootDoc; return true; } diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 2f28ecd00..3286d60bd 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -92,6 +92,7 @@ export class CollectionNoteTakingViewColumn extends React.Component { const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false)); + return true; }); getValue = (value: string): any => { diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 15570b195..91be31289 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -63,12 +63,14 @@ export class CollectionPileView extends CollectionSubView() {

); @@ -106,7 +108,6 @@ export class CollectionPileView extends CollectionSubView() { _undoBatch: UndoManager.Batch | undefined; pointerDown = (e: React.PointerEvent) => { let dist = 0; - SnappingManager.SetIsDragging(true); setupMoveUpEvents( this, e, @@ -129,7 +130,6 @@ export class CollectionPileView extends CollectionSubView() { () => { this._undoBatch?.end(); this._undoBatch = undefined; - SnappingManager.SetIsDragging(false); }, emptyFunction, e.shiftKey && this.layoutEngine() === computePassLayout.name, diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index e835fa659..ad84d859d 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -369,22 +369,22 @@ export class CollectionStackedTimeline extends CollectionSubView { - const anchorEnd = this.anchorEnd(drop); - if (anchorEnd !== undefined) { - Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false); - } - Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false); - }); + if (super.onInternalDrop(e, de)) { + // determine x coordinate of drop and assign it to the documents being dragged --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view + const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + const x = localPt[0] - docDragData.offset[0]; + const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth); + docDragData.droppedDocuments.forEach(drop => { + const anchorEnd = this.anchorEnd(drop); + if (anchorEnd !== undefined) { + Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false); + } + Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false); + }); - return true; + return true; + } + return false; } onInternalDrop = (e: Event, de: DragManager.DropEvent) => { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 8eed4f716..4756b4cd3 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -459,18 +459,24 @@ export class CollectionStackingView extends CollectionSubView docs.indexOf(newdoc) !== -1 && docs.splice(docs.indexOf(newdoc), 1)); const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter; const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0); newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1)); docs.splice(insertInd - offset, 0, ...newDocs); } + return true; } } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); - this.props.addDocument?.(source); + if (!this.props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed e.stopPropagation(); - } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); + return true; + } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) { + return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); + } + e.preventDefault(); return false; }; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 6be9cb72d..ebb4ba5a1 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -94,6 +94,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false)); + return true; }); getValue = (value: string): any => { const parsed = parseInt(value); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 539dde7e0..39fb2db1e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -185,12 +185,14 @@ export function CollectionSubView(moreProps?: X) { @undoBatch protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {} - protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) { + protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) { if (de.complete.docDragData) { - // if dropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction. - // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys) - if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) { - de.complete.docDragData.dropAction = targetAction; + // override the dropEvent's dropAction + const dropAction = this.layoutDoc.dropAction as dropActionType; + // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding. + // so we check if our collection has a dropAction set on it and if so, we use that instead. + if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) { + de.complete.docDragData.dropAction = dropAction; } e.stopPropagation(); } @@ -218,16 +220,16 @@ export function CollectionSubView(moreProps?: X) { ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); added = addedDocs.length ? this.addDocument(addedDocs) : true; } - added && e.stopPropagation(); - return added; } else { ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); added = this.addDocument(docDragData.droppedDocuments); + !added && alert('You cannot perform this move'); } - !added && alert('You cannot perform this move'); + !added && e.preventDefault(); e.stopPropagation(); return added; } else if (de.complete.annoDragData) { + e.stopPropagation(); const dropCreator = de.complete.annoDragData.dropDocCreator; de.complete.annoDragData.dropDocCreator = () => { const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7598bb753..4cd3885f5 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -140,11 +140,16 @@ export class CollectionTreeView extends CollectionSubView { + protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => { + const dropAction = this.layoutDoc.dropAction as dropActionType; const dragData = de.complete.docDragData; if (dragData) { - const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); - dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction; + const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.rootDoc) ? true : false; + const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); + if (isAlreadyInTree() !== sameTree) { + console.log('WHAAAT'); + } + dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction; } }; @@ -394,6 +399,7 @@ export class CollectionTreeView extends CollectionSubView !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), overflow: 'auto', @@ -417,8 +423,7 @@ export class CollectionTreeView extends CollectionSubView e.stopPropagation()} - onDrop={this.onTreeDrop} - ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}> + onDrop={this.onTreeDrop}>
    {this.treeViewElements}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 91ae2b3cc..8d8d895c6 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -347,7 +347,7 @@ export class TreeView extends React.Component { }; deleteItem = () => this.props.removeDoc?.(this.doc); - preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { + preTreeDrop = (e: Event, de: DragManager.DropEvent) => { const dragData = de.complete.docDragData; dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction); }; @@ -355,7 +355,7 @@ export class TreeView extends React.Component { @undoBatch treeDrop = (e: Event, de: DragManager.DropEvent) => { const pt = [de.x, de.y]; - if (!this._header.current) return; + if (!this._header.current) return false; const rect = this._header.current.getBoundingClientRect(); const before = pt[1] < rect.top + rect.height / 2; const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocs?.length ? true : false); @@ -364,14 +364,25 @@ export class TreeView extends React.Component { const destDoc = this.doc; DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' }); e.stopPropagation(); + return true; } const docDragData = de.complete.docDragData; if (docDragData && pt[0] < rect.left + rect.width) { if (docDragData.draggedDocuments[0] === this.doc) return true; - if (this.dropDocuments(docDragData.droppedDocuments, before, inside, docDragData.dropAction, docDragData.removeDocument, docDragData.moveDocument, docDragData.treeViewDoc === this.props.treeView.props.Document)) { - e.stopPropagation(); - } + const added = this.dropDocuments( + docDragData.droppedDocuments, // + before, + inside, + docDragData.dropAction, + docDragData.removeDocument, + docDragData.moveDocument, + docDragData.treeViewDoc === this.props.treeView.props.Document + ); + e.stopPropagation(); + !added && e.preventDefault(); + return added; } + return false; }; dropping: boolean = false; @@ -924,7 +935,7 @@ export class TreeView extends React.Component { PanelHeight={return18} contextMenuItems={this.contextMenuItems} renderDepth={1} - isContentActive={this.props.isContentActive} + isContentActive={emptyFunction} //this.props.isContentActive} isDocumentActive={this.props.isContentActive} focus={this.refocus} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d7e073c5f..e6f8f3071 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -418,15 +418,16 @@ export class CollectionFreeFormView extends CollectionSubView { if (de.complete.columnDragData) { - e.stopPropagation(); const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]; const index = this.findDropIndex(mouseX); this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex); @@ -448,6 +447,7 @@ export class CollectionSchemaView extends CollectionSubView() { }); }); + e.stopPropagation(); return true; } const draggedDocs = de.complete.docDragData?.draggedDocuments; @@ -462,7 +462,6 @@ export class CollectionSchemaView extends CollectionSubView() { if (draggedView) DocumentManager.Instance.RemoveView(draggedView); DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true)); }); - e.stopPropagation(); return true; } return false; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index d747c4527..2290e0711 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -42,13 +42,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { + private internalDrop = (e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { if (dropEvent.complete.docDragData) { - event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; - const res = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey)); - res && (droppedDocs.lastElement().embedContainer = this.dataDoc); - return res; + const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey)); + droppedDocs.lastElement().embedContainer = this.dataDoc; + !added && e.preventDefault(); + e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place + return added; } }; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fbc84389d..b6f1626f8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -356,9 +356,10 @@ export class DocumentViewInternal extends DocComponent { - if (de.complete.docDragData && this.isContentActive()) { - targetAction && (de.complete.docDragData.dropAction = targetAction); + preDropFunc = (e: Event, de: DragManager.DropEvent) => { + const dropAction = this.layoutDoc.dropAction as dropActionType; + if (de.complete.docDragData && this.isContentActive() && !this.props.treeViewDoc) { + dropAction && (de.complete.docDragData.dropAction = dropAction); e.stopPropagation(); } }; @@ -492,8 +493,13 @@ export class DocumentViewInternal extends DocComponent this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey)); + const sendToBack = e.altKey; + this._singleClickFunc = + clickFunc ?? + (() => + sendToBack + ? this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.bringToFront(this.rootDoc, true) + : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey)); const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') { this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout); @@ -541,7 +547,7 @@ export class DocumentViewInternal extends DocComponent @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData?.droppedDocuments.length) { + const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => res && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc), true); + !added && e.preventDefault(); e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place - de.complete.docDragData.droppedDocuments.map(doc => Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc)); - return false; + return added; } return false; }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 64d6814df..f67930a3f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -135,19 +135,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent { if (de.complete.docDragData) { + let added = true; const targetIsBullseye = (ele: HTMLElement): boolean => { if (!ele) return false; if (ele === this._overlayIconRef.current) return true; return targetIsBullseye(ele.parentElement as HTMLElement); }; if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) { - de.complete.docDragData.droppedDocuments.forEach( - action((drop: Doc) => { - Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop); - this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover'; - e.stopPropagation(); - }) - ); + added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => { + this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover'; + return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop); + }, true); } else if (de.altKey || !this.dataDoc[this.fieldKey]) { const layoutDoc = de.complete.docDragData?.draggedDocuments[0]; const targetField = Doc.LayoutFieldKey(layoutDoc); @@ -156,10 +154,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d))); e.stopPropagation(); + return true; } + return false; }; @observable _mouseOver = false; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 37fda14fc..3ad3c911d 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -270,8 +270,12 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { - Doc.SetInPlace(this.rootDoc, fieldKey, de.complete.docDragData?.droppedDocuments[0], true); - e.stopPropagation(); + if (de.complete.docDragData) { + de.complete.docDragData.droppedDocuments.forEach(doc => Doc.SetInPlace(this.rootDoc, fieldKey, doc, true)); + e.stopPropagation(); + return true; + } + return false; }; // deletes a param from all areas in which it is stored diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2e8f6c696..da0fc9ffb 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -531,36 +531,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true); + if (de.complete.annoDragData) { + de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true); + e.stopPropagation(); + return true; + } const dragData = de.complete.docDragData; if (dragData) { - const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0]; - // replace text contents whend dragging with Alt - if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) { - if (draggedDoc.data instanceof RichTextField) { - Doc.GetProto(this.dataDoc)[this.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text); - e.stopPropagation(); - } - // embed document when dragg marked as embed - } else if (de.embedKey) { - const target = dragData.droppedDocuments[0]; - const node = schema.nodes.dashDoc.create({ - width: target[Width](), - height: target[Height](), - title: 'dashDoc', - docId: target[Id], - float: 'unset', - }); - if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) { - dragData.removeDocument?.(dragData.draggedDocuments[0]); + const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc; + const effectiveAcl = GetEffectiveAcl(dataDoc); + let added = [AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl); + const draggedDoc = dragData.draggedDocuments.lastElement(); + if (added) { + // replace text contents when dragging with Alt + if (de.altKey) { + const fieldKey = Doc.LayoutFieldKey(draggedDoc); + if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) { + Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]); + } + + // embed document when drag marked as embed + } else if (de.embedKey) { + const node = schema.nodes.dashDoc.create({ + width: draggedDoc[Width](), + height: draggedDoc[Height](), + title: 'dashDoc', + docId: draggedDoc[Id], + float: 'unset', + }); + if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) { + added = dragData.removeDocument?.(draggedDoc) ? true : false; + } + if (added) { + draggedDoc._freeform_fitContentsToBox = true; + draggedDoc.embedContainer = this.rootDoc; + const view = this._editorView!; + view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node)); + } } - target._freeform_fitContentsToBox = true; - target.embedContainer = this.rootDoc; - const view = this._editorView!; - view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node)); - e.stopPropagation(); } // otherwise, fall through to outer collection to handle drop + !added && e.preventDefault(); + e.stopPropagation(); + return added; } + return false; }; getNodeEndpoints(context: Node, node: Node): { from: number; to: number } | null { diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index 55d1d9ea4..c076f5fe1 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -1,5 +1,5 @@ import { Deserializable } from '../client/util/SerializationHelper'; -import { FieldWaiting, Opt } from './Doc'; +import { Field, FieldWaiting, Opt } from './Doc'; import { primitive, serializable } from 'serializr'; import { observable, action, runInAction, computed } from 'mobx'; import { DocServer } from '../client/DocServer'; @@ -39,7 +39,7 @@ export class ProxyField extends ObjectField { } [ToScriptString]() { - return 'invalid'; + return Field.toScriptString(this[ToValue](undefined)?.value); // not sure this is quite right since it doesn't recreate a proxy field, but better than 'invalid' ? } [ToString]() { return 'ProxyField'; diff --git a/src/fields/util.ts b/src/fields/util.ts index e3d1abc53..e439768ee 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -433,7 +433,8 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any lastValue = ObjectField.MakeCopy(receiver[prop]); }, prop: 'assign list', - } + }, + diff?.items ); } target[Update](op); -- cgit v1.2.3-70-g09d2 From c0d45c06df10d29cae5f46eeecb220a11588c3a1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 30 Jun 2023 23:43:59 -0400 Subject: fixed onBrowseClick for notetaking. fixed panning when in onBrowse explore mode. fixed switching dashboards to not display an empty stack. --- src/client/util/DocumentManager.ts | 23 +++++++++++------ src/client/views/DashboardView.tsx | 3 ++- .../views/collections/CollectionDockingView.tsx | 1 + .../views/collections/CollectionNoteTakingView.tsx | 3 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 30 ++++++++++------------ src/client/views/nodes/DocumentView.tsx | 5 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 7 files changed, 38 insertions(+), 29 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7e3302067..351f9ef7c 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -228,7 +228,7 @@ export class DocumentManager { public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => { const docViewPath = targetDocView.docViewPath.slice(); let rootContextView = docViewPath.shift(); - await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined }))); + await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden; else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) DocumentViewInternal.addDocTabFunc(rootContextView.rootDoc, options.openLocation); }; @@ -242,7 +242,7 @@ export class DocumentManager { public showDocument = async ( targetDoc: Doc, // document to display options: DocFocusOptions, // options for how to navigate to target - finished?: () => void + finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => { const docContextPath = DocumentManager.GetContextPath(targetDoc, true); if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false; @@ -269,22 +269,29 @@ export class DocumentManager { docContextPath.shift(); const childViewIterator = async (docView: DocumentView) => { const innerDoc = docContextPath.shift(); - return { viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined }; + return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined }; }; + if (rootContextView) { const target = await this.focusViewsInPath(rootContextView, options, childViewIterator); this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc); - } - finished?.(); + finished?.(target.focused); + } else finished?.(false); }; - focusViewsInPath = async (docView: DocumentView, options: DocFocusOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt; childDocView: Opt }>) => { + focusViewsInPath = async ( + docView: DocumentView, // + options: DocFocusOptions, + iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt; childDocView: Opt; focused: boolean }> + ) => { let contextView: DocumentView | undefined; // view containing context that contains target + let focused = false; while (true) { docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise(res => docView.iconify(res)) : undefined; - docView.props.focus(docView.rootDoc, options); // focus the view within its container + const nextFocus = docView.props.focus(docView.rootDoc, options); // focus the view within its container + focused = focused || (nextFocus === undefined ? false : true); const { childDocView, viewSpec } = await iterator(docView); - if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView }; + if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused }; contextView = docView; docView = childDocView; } diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 6aae302ac..f6d843201 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -347,7 +347,8 @@ export class DashboardView extends React.Component { }, ], }; - Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true); + if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); + else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true); return reset; }; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index a5d7e7864..3bf3f1a74 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -359,6 +359,7 @@ export class CollectionDockingView extends CollectionSubView() { } catch (e) {} this._goldenLayout?.destroy(); window.removeEventListener('resize', this.onResize); + window.removeEventListener('mouseup', this.onPointerUp); this._reactionDisposer?.(); this._lightboxReactionDisposer?.(); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index f1c4c2cdf..fb995301a 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -192,7 +192,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (found) { const top = found.getBoundingClientRect().top; const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); - if (Math.floor(localTop[1]) !== 0) { + if (Math.floor(localTop[1]) !== 0 && Math.ceil(this.props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) { let focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); return focusSpeed; @@ -252,6 +252,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { layout_showTitle={this.props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} onClick={this.onChildClickHandler} + onBrowseClick={this.props.onBrowseClick} onDoubleClick={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ef396c6b3..ba31916a7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -2256,22 +2256,20 @@ class CollectionFreeFormBackgroundGrid extends React.Component { + if (!focused) { + const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; + let containers = dv.props.docViewPath(); + let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + for (var cont of containers) { + parFfview = parFfview ?? cont.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + } + while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview + ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime); + Doc.linkFollowHighlight(dv?.props.Document, false); + } + }); } ScriptingGlobals.add(CollectionBrowseClick); ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b6f1626f8..733ee1ed1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -900,8 +900,9 @@ export class DocumentViewInternal extends DocComponent [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; - /// disable pointer events on content when there's an enabled onClick script, or if contents are marked inactive - contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler) || this.isContentActive() === false ? 'none' : this.pointerEvents); + /// disable pointer events on content when there's an enabled onClick script (but not the browse script), or if contents are marked inactive + contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.()) || this.isContentActive() === false ? 'none' : this.pointerEvents); + @computed get contents() { TraceMobx(); const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index da0fc9ffb..026864ddd 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2079,7 +2079,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Sat, 1 Jul 2023 13:25:40 -0400 Subject: turned off notetaking chrome in browse mode. fixed pointereventrs for text in/out of browse mode. changed background to be gray by default --- src/client/util/DocumentManager.ts | 2 +- src/client/views/StyleProvider.tsx | 2 +- src/client/views/collections/CollectionNoteTakingView.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 351f9ef7c..fb6bc67d8 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -289,7 +289,7 @@ export class DocumentManager { while (true) { docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise(res => docView.iconify(res)) : undefined; const nextFocus = docView.props.focus(docView.rootDoc, options); // focus the view within its container - focused = focused || (nextFocus === undefined ? false : true); + focused = focused || (nextFocus === undefined ? false : true); // keep track of whether focusing on a view needed to actually change anything const { childDocView, viewSpec } = await iterator(docView); if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused }; contextView = docView; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 330ccc583..f293733fb 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -227,7 +227,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : 'linear-gradient(#065fff, #85c1f9)')); + : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : Colors.MEDIUM_GRAY)); break; //if (doc._type_collection !== CollectionViewType.Freeform && doc._type_collection !== CollectionViewType.Time) return "rgb(62,62,62)"; default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index fb995301a..53a42d2a6 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -47,7 +47,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { @observable _cursor: CursorProperty = 'grab'; @observable _scroll = 0; @computed get chromeHidden() { - return BoolCast(this.layoutDoc.chromeHidden); + return BoolCast(this.layoutDoc.chromeHidden) || this.props.onBrowseClick?.() ? true : false; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 026864ddd..62b3443d4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2079,7 +2079,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Sun, 2 Jul 2023 12:36:37 -0400 Subject: made multicolumn/row views fit contents to panel and center. changed collection drop to propagate when embed is not enabled. fixed image box drop . made goldenlayout tabs selectable. turned off leaving pushpins on drag out. fixed long press to disable on drag. --- src/client/views/DocComponent.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 11 ++++++----- src/client/views/collections/TabDocView.tsx | 1 + .../CollectionMulticolumnView.scss | 9 ++++++--- .../collectionMulticolumn/CollectionMulticolumnView.tsx | 17 +++++++++++------ .../collectionMulticolumn/CollectionMultirowView.scss | 10 +++++++--- .../collectionMulticolumn/CollectionMultirowView.tsx | 17 +++++++++++------ src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/ImageBox.tsx | 6 +++--- 9 files changed, 47 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 3de40a640..70d208a0b 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -173,7 +173,7 @@ export function ViewBoxAnnotatableComponent

() } const first = doc instanceof Doc ? doc : doc[0]; if (!first?._dragOnlyWithinContainer && addDocument !== returnFalse) { - return this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey); + return this.removeDocument(doc, annotationKey, false) && addDocument(doc, annotationKey); } return false; }; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 39fb2db1e..78789247f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -205,7 +205,7 @@ export function CollectionSubView(moreProps?: X) { protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; if (docDragData) { - let added = false; + let added = undefined; const dropAction = docDragData.dropAction || docDragData.userDropAction; const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]); const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); @@ -215,7 +215,8 @@ export function CollectionSubView(moreProps?: X) { const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { const canAdd = de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc); - added = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse); + const moved = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse); + added = canAdd || moved ? moved : undefined; } else { ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); added = addedDocs.length ? this.addDocument(addedDocs) : true; @@ -225,9 +226,9 @@ export function CollectionSubView(moreProps?: X) { added = this.addDocument(docDragData.droppedDocuments); !added && alert('You cannot perform this move'); } - !added && e.preventDefault(); - e.stopPropagation(); - return added; + added === false && !this.props.isAnnotationOverlay && e.preventDefault(); + added === true && e.stopPropagation(); + return added ? true : false; } else if (de.complete.annoDragData) { e.stopPropagation(); const dropCreator = de.complete.annoDragData.dropDocCreator; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 0dcf17b48..118b216bf 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -335,6 +335,7 @@ export class TabDocView extends React.Component { private onActiveContentItemChanged(contentItem: any) { if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) { this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab; + if (!this._view) setTimeout(() => SelectionManager.SelectView(this._view, false)); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. } } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index 821c8d804..f87a06033 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -8,6 +8,11 @@ display: flex; flex-direction: column; width: 100%; + align-items: center; + + .contentFittingDocumentView { + width: unset; + } .label-wrapper { display: flex; @@ -15,7 +20,6 @@ justify-content: center; height: 20px; } - } .multiColumnResizer { @@ -30,5 +34,4 @@ transition: 0.5s background-color ease; } } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 6dcd2d422..10532b9d9 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -238,7 +238,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { ? true : undefined; }; - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { + getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { return ( this.lookupPixels(layout); + const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); + const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(height() * aspect, width())); + const docheight = () => Math.min(docwidth() / aspect, height()); const dxf = () => this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)) + .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin)) .scale(this.props.NativeDimScaling?.() || 1); - const width = () => this.lookupPixels(layout); - const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -

- {this.getDisplayDoc(layout, dxf, width, height)} +
+ {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)}
, Transform, width: () => number, height: () => number) => { + getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { return ( this.lookupPixels(layout); + const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); + const docheight = () => Math.min(width() / aspect, height()); + const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(width(), docheight() * aspect)); const dxf = () => this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)) + .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2) .scale(this.props.NativeDimScaling?.() || 1); - const height = () => this.lookupPixels(layout); - const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -
- {this.getDisplayDoc(layout, dxf, width, height)} +
+ {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)}
, { if (de.complete.docDragData) { - let added = true; + let added: boolean | undefined = undefined; const targetIsBullseye = (ele: HTMLElement): boolean => { if (!ele) return false; if (ele === this._overlayIconRef.current) return true; @@ -156,8 +156,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent Date: Sun, 2 Jul 2023 19:06:56 -0400 Subject: improved highlighting of tabs to show focus/active. added. menu item to open a tab in lightbox --- .../views/collections/CollectionDockingView.scss | 6 + .../views/collections/CollectionDockingView.tsx | 10 +- src/client/views/collections/TabDocView.tsx | 144 +++++++++++---------- src/client/views/nodes/DocumentView.tsx | 4 + .../views/nodes/formattedText/FormattedTextBox.tsx | 11 +- 5 files changed, 104 insertions(+), 71 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 78e44dfa2..4c15d5eed 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -15,6 +15,12 @@ cursor: grab; color: $black; } +.collectiondockingview-container .lm_splitter { + opacity: 0.2; + &:hover { + opacity: 1; + } +} .lm_title.focus-visible { -webkit-appearance: none; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 3bf3f1a74..2ed55b3ca 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -29,6 +29,7 @@ import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { TabDocView } from './TabDocView'; import React = require('react'); +import { DocumentManager } from '../../util/DocumentManager'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -410,7 +411,14 @@ export class CollectionDockingView extends CollectionSubView() { if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) { const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : ''; if (className.includes('lm_maximise')) this._flush = UndoManager.StartBatch('tab maximize'); - else if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE(); + else { + const tabTarget = (e.target as HTMLElement)?.parentElement?.className.includes('lm_tab') ? (e.target as HTMLElement).parentElement : (e.target as HTMLElement); + const map = Array.from(this.tabMap).find(tab => tab.element[0] === tabTarget); + if (map?.DashDoc && DocumentManager.Instance.getFirstDocumentView(map.DashDoc)) { + SelectionManager.SelectView(DocumentManager.Instance.getFirstDocumentView(map.DashDoc), false); + } + if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE(); + } } } if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 118b216bf..83edc60df 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -43,12 +43,17 @@ interface TabDocViewProps { } @observer export class TabDocView extends React.Component { + static _firstTab = true; _mainCont: HTMLDivElement | null = null; _tabReaction: IReactionDisposer | undefined; @observable _activated: boolean = false; @observable _panelWidth = 0; @observable _panelHeight = 0; @observable _isActive: boolean = false; + @observable _isAnyChildContentActive = false; + @computed get _isContentActive() { + return SelectionManager.Views().some(view => view.rootDoc === this._document) || this._isAnyChildContentActive; + } @observable _document: Doc | undefined; @observable _view: DocumentView | undefined; @@ -61,9 +66,7 @@ export class TabDocView extends React.Component { return 'transparent'; } @computed get tabColor() { - let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); - if (tabColor === 'transparent') return 'black'; - return tabColor; + return this._isContentActive ? Colors.WHITE : Colors.MEDIUM_GRAY; } @computed get tabTextColor() { return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); @@ -191,7 +194,7 @@ export class TabDocView extends React.Component { } }); tab._disposers.selectionDisposer = reaction( - () => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc), + () => SelectionManager.Views().some(view => view.rootDoc === this._document), action(selected => { if (selected) this._activated = true; const toggle = tab.element[0].children[2].children[0] as HTMLInputElement; @@ -322,11 +325,13 @@ export class TabDocView extends React.Component { } componentDidUpdate() { this._view && DocumentManager.Instance.AddView(this._view); + if (TabDocView._firstTab) SelectionManager.SelectView(this._view, false); } componentWillUnmount() { this._tabReaction?.(); this._view && DocumentManager.Instance.RemoveView(this._view); + TabDocView._firstTab = false; this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged); } @@ -405,11 +410,15 @@ export class TabDocView extends React.Component { }; PanelWidth = () => this._panelWidth; PanelHeight = () => this._panelHeight; - miniMapColor = () => this.tabColor; + miniMapColor = () => Colors.MEDIUM_GRAY; tabView = () => this._view; disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform; - hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap); - + whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive); + tabs = () => Array.from(CollectionDockingView.Instance?.tabMap ?? new Set()); + isContentActive = () => + SelectionManager.Views().some(dv => dv.rootDoc === this._document) || + this._isAnyChildContentActive || + (this.tabs().findIndex(tab => tab.DashDoc === this._document) === 0 && !this.tabs().some(tab => SelectionManager.Views().some(dv => dv.rootDoc === tab.DashDoc))); @computed get docView() { return !this._activated || !this._document ? null : ( <> @@ -427,7 +436,7 @@ export class TabDocView extends React.Component { DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} onBrowseClick={MainView.Instance.exploreMode} waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick} - isContentActive={returnTrue} + isContentActive={this.isContentActive} isDocumentActive={returnFalse} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} @@ -441,30 +450,15 @@ export class TabDocView extends React.Component { ScreenToLocalTransform={this.ScreenToLocalTransform} dontCenter={'y'} rootSelected={returnTrue} - whenChildContentsActiveChanged={emptyFunction} + whenChildContentsActiveChanged={this.whenChildContentActiveChanges} focus={this.focusFunc} docViewPath={returnEmptyDoclist} bringToFront={emptyFunction} pinToPres={TabDocView.PinDoc} /> - - {this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}
}> -
e.stopPropagation()} - onClick={action(e => { - e.stopPropagation(); - this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap; - })}> - -
- + {this.disableMinimap() || this._document._type_collection !== CollectionViewType.Freeform ? null : ( + + )} ); } @@ -495,7 +489,6 @@ export class TabDocView extends React.Component { interface TabMinimapViewProps { document: Doc; - hideMinimap: () => boolean; tabView: () => DocumentView | undefined; addDocTab: (doc: Doc, where: OpenWhere) => boolean; PanelWidth: () => number; @@ -573,43 +566,64 @@ export class TabMinimapView extends React.Component { const miniLeft = 50 + ((NumCast(this.props.document._freeform_panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2; const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2; const miniSize = this.returnMiniSize(); - return this.props.hideMinimap() ? null : ( -
- -
-
-
-
+ return ( + <> + {' '} + {this.props.document?.layout_hideMinimap ? null : ( +
+ +
+
+
+
+ )} + {this.props.document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}
}> +
e.stopPropagation()} + onClick={action(e => { + e.stopPropagation(); + this.props.document!.layout_hideMinimap = !this.props.document!.layout_hideMinimap; + })}> + +
+ + ); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c10c0005d..19f9f15a4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -729,6 +729,10 @@ export class DocumentViewInternal extends DocComponent LightboxView.SetLightboxDoc(this.rootDoc), icon: 'hand-point-right' }); + } !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 62b3443d4..f1305b64b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -879,11 +879,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.generateImage(), icon: 'star' }); optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' }); - optionItems.push({ - description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns', - event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR), - icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars', - }); + this.props.renderDepth && + optionItems.push({ + description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns', + event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR), + icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars', + }); !Doc.noviceMode && optionItems.push({ description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`, -- cgit v1.2.3-70-g09d2 From 823a9433829babb9fa1ec86fa0edafa3a44bc086 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Jul 2023 11:18:24 -0400 Subject: changed font icon ui for windows to avoid blur --- src/client/views/nodes/button/FontIconBox.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss index f3b43501b..9d9fa26b0 100644 --- a/src/client/views/nodes/button/FontIconBox.scss +++ b/src/client/views/nodes/button/FontIconBox.scss @@ -18,7 +18,7 @@ .fontIconBox-label { color: $white; - bottom: 0; + bottom: -1; position: absolute; text-align: center; font-size: 7px; @@ -27,7 +27,7 @@ border-radius: 8px; padding: 0; width: 100%; - font-family: 'ROBOTO'; + font-family: 'system-ui'; text-transform: uppercase; font-weight: bold; transition: 0.15s; -- cgit v1.2.3-70-g09d2 From 334f921d6e439983d5f3605739cc4221c53a43fc Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Jul 2023 11:33:16 -0400 Subject: fixed set native pixel size --- src/client/views/nodes/ImageBox.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0bbdff719..909a420fe 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -170,14 +170,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1); const nscale = NumCast(this.props.PanelWidth()) / scaling; - const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']); const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); - this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nh; - this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nh; - this.rootDoc._freeform_panX = nh * NumCast(this.rootDoc._freeform_panX); - this.rootDoc._freeform_panY = nh * NumCast(this.rootDoc._freeform_panY); - this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nh * NumCast(this.dataDoc._freeform_panXMax) : undefined; - this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nh * NumCast(this.dataDoc._freeform_panXMin) : undefined; + this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; + this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw; + this.rootDoc._freeform_panX = nw * NumCast(this.rootDoc._freeform_panX); + this.rootDoc._freeform_panY = nw * NumCast(this.rootDoc._freeform_panY); + this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined; + this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined; this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined; this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined; }); -- cgit v1.2.3-70-g09d2 From 638a3ce3bcd4aa7287544be82d8d9d07ee963600 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 4 Jul 2023 09:15:38 -0400 Subject: fixed undo stack when typing, then switching tabs. combined mark settings into one dispatch on text box load. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f1305b64b..44cb56d53 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1521,8 +1521,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent mark.type === schema.marks.user_mark) ? [schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })] : []), + ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })], ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []), ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []), ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []), @@ -1556,6 +1554,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent disposer?.()); this.endUndoTypingBatch(); + FormattedTextBox.LiveTextUndo?.end(); + FormattedTextBox.LiveTextUndo = undefined; this.unhighlightSearchTerms(); this._editorView?.destroy(); RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined); -- cgit v1.2.3-70-g09d2