aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DashboardView.tsx6
-rw-r--r--src/client/views/DocComponent.tsx8
-rw-r--r--src/client/views/DocumentDecorations.tsx8
-rw-r--r--src/client/views/GestureOverlay.tsx95
-rw-r--r--src/client/views/InkControlPtHandles.tsx34
-rw-r--r--src/client/views/InkStrokeProperties.ts1
-rw-r--r--src/client/views/InkTranscription.tsx4
-rw-r--r--src/client/views/InkingStroke.tsx47
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/MainView.tsx19
-rw-r--r--src/client/views/Palette.scss30
-rw-r--r--src/client/views/Palette.tsx69
-rw-r--r--src/client/views/PropertiesButtons.tsx1
-rw-r--r--src/client/views/PropertiesView.tsx1
-rw-r--r--src/client/views/StyleProvider.tsx4
-rw-r--r--src/client/views/TemplateMenu.tsx5
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx4
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx8
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx9
-rw-r--r--src/client/views/collections/CollectionMenu.tsx3
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx19
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewColumn.tsx1
-rw-r--r--src/client/views/collections/CollectionPileView.tsx19
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx40
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx28
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx1
-rw-r--r--src/client/views/collections/CollectionSubView.tsx26
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx29
-rw-r--r--src/client/views/collections/CollectionView.tsx5
-rw-r--r--src/client/views/collections/TabDocView.tsx6
-rw-r--r--src/client/views/collections/TreeView.tsx62
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx28
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx4
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx40
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx19
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx20
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx8
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx2
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx4
-rw-r--r--src/client/views/linking/LinkPopup.tsx1
-rw-r--r--src/client/views/nodes/ComparisonBox.scss2
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx85
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx2
-rw-r--r--src/client/views/nodes/DataVizBox/components/LineChart.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.scss2
-rw-r--r--src/client/views/nodes/DocumentView.tsx76
-rw-r--r--src/client/views/nodes/FieldView.tsx2
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx7
-rw-r--r--src/client/views/nodes/ImageBox.tsx23
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx8
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx3
-rw-r--r--src/client/views/nodes/LabelBox.tsx2
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx2
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx5
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx2
-rw-r--r--src/client/views/nodes/PDFBox.tsx8
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx8
-rw-r--r--src/client/views/nodes/WebBox.tsx16
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx107
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx13
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx13
-rw-r--r--src/client/views/pdf/PDFViewer.tsx18
-rw-r--r--src/client/views/topbar/TopBar.scss437
-rw-r--r--src/client/views/topbar/TopBar.tsx30
68 files changed, 770 insertions, 835 deletions
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index e6025dc16..d91c17545 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -389,7 +389,7 @@ export class DashboardView extends React.Component {
_forceActive: true,
_width: 30,
_height: 30,
- _stayInCollection: true,
+ _dragOnlyWithinContainer: true,
_layout_hideContextMenu: true,
title: 'New trail',
toolTip: 'Create new trail',
@@ -412,7 +412,7 @@ export class DashboardView extends React.Component {
_layout_fitWidth: true,
_gridGap: 5,
_forceActive: true,
- childDropAction: 'embed',
+ childDragAction: 'embed',
treeViewTruncateTitleWidth: 150,
ignoreClick: true,
layout_headerButton: myTrailsBtn,
@@ -421,7 +421,7 @@ export class DashboardView extends React.Component {
_lockedPosition: true,
layout_boxShadow: '0 0',
childDontRegisterViews: true,
- targetDropAction: 'same',
+ dropAction: 'same',
isSystem: true,
layout_explainer: 'All of the trails that you have created will appear here.',
};
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index db24229dc..3de40a640 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -172,8 +172,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
return true;
}
const first = doc instanceof Doc ? doc : doc[0];
- if (!first?._stayInCollection && addDocument !== returnFalse) {
- return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey));
+ if (!first?._dragOnlyWithinContainer && addDocument !== returnFalse) {
+ return this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey);
}
return false;
};
@@ -213,14 +213,14 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
.map(doc => {
// only make a pushpin if we have acl's to edit the document
//DocUtils.LeavePushpin(doc);
- doc._stayInCollection = undefined;
+ doc._dragOnlyWithinContainer = undefined;
doc.embedContainer = this.props.Document;
if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc);
});
const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
- 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<Doc>(added);
targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now()));
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 528b82e3e..41ce08d3c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -603,7 +603,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
let actualdH = Math.max(docheight + dH * scale, 20);
let dX = !dWin ? 0 : scale * refCent[0] * (1 - (1 + dWin / refWidth));
let dY = !dHin ? 0 : scale * refCent[1] * (1 - (1 + dHin / refHeight));
- const preserveNativeDim = doc._nativeHeightUnfrozen === false && doc._nativeDimModifiable === false;
+ const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable;
const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
if (fixedAspect) {
if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) {
@@ -636,7 +636,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
}
}
if (!modifyNativeDim) {
- actualdH = (nheight / nwidth) * docwidth; //, actualdH);
+ actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH);
}
doc._height = actualdH;
}
@@ -756,7 +756,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
hideDecorations ||
seldocview.props.hideOpenButton ||
seldocview.rootDoc.layout_hideOpenButton ||
- SelectionManager.Views().some(docView => docView.rootDoc._stayInCollection || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
+ SelectionManager.Views().some(docView => docView.rootDoc._dragOnlyWithinContainer || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
this._isRounding ||
this._isRotating;
const hideDeleteButton =
@@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
seldocview.rootDoc.hideDeleteButton ||
SelectionManager.Views().some(docView => {
const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
- return (docView.rootDoc.stayInCollection && !docView.rootDoc._isTimelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+ return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin;
});
const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0951bff22..54ad519de 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -4,8 +4,7 @@ import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, Opt } from '../../fields/Doc';
import { InkData, InkTool } from '../../fields/InkField';
-import { ScriptField } from '../../fields/ScriptField';
-import { Cast, FieldValue, NumCast } from '../../fields/Types';
+import { NumCast } from '../../fields/Types';
import MobileInkOverlay from '../../mobile/MobileInkOverlay';
import { GestureUtils } from '../../pen-gestures/GestureUtils';
import { MobileInkOverlayContent } from '../../server/Message';
@@ -35,7 +34,6 @@ import { InkTranscription } from './InkTranscription';
import { checkInksToGroup } from './nodes/button/FontIconBox';
import { DocumentView } from './nodes/DocumentView';
import { RadialMenu } from './nodes/RadialMenu';
-import HorizontalPalette from './Palette';
import { Touchable } from './Touchable';
import TouchScrollableMenu, { TouchScrollableMenuItem } from './TouchScrollableMenu';
@@ -79,7 +77,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
private _overlayRef = React.createRef<HTMLDivElement>();
private _d1: Doc | undefined;
private _inkToTextDoc: Doc | undefined;
- private _thumbDoc: Doc | undefined;
private thumbIdentifier?: number;
private pointerIdentifier?: number;
private _hands: Map<number, React.Touch[]> = new Map<number, React.Touch[]>();
@@ -93,78 +90,12 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
GestureOverlay.Instances.push(this);
}
- static setupThumbButtons(doc: Doc) {
- const docProtoData: { title: string; icon: string; drag?: string; toolType?: string; ignoreClick?: boolean; pointerDown?: string; pointerUp?: string; clipboard?: Doc; backgroundColor?: string; dragFactory?: Doc }[] = [
- { title: 'use pen', icon: 'pen-nib', pointerUp: 'resetPen()', pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: 'blue' },
- { title: 'use highlighter', icon: 'highlighter', pointerUp: 'resetPen()', pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: 'yellow' },
- {
- title: 'notepad',
- icon: 'clipboard',
- pointerUp: 'GestureOverlay.Instance.closeFloatingDoc()',
- pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)',
- clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, isSystem: true }),
- backgroundColor: 'orange',
- },
- { title: 'interpret text', icon: 'font', toolType: 'inktotext', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'orange' },
- { title: 'ignore gestures', icon: 'signature', toolType: 'ignoregesture', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'green' },
- ];
- return docProtoData.map(data =>
- Docs.Create.FontIconDocument({
- _nativeWidth: 10,
- _nativeHeight: 10,
- _width: 10,
- _height: 10,
- title: data.title,
- icon: data.icon,
- toolType: data.toolType,
- _dropAction: data.pointerDown ? 'copy' : undefined,
- ignoreClick: data.ignoreClick,
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
- clipboard: data.clipboard,
- onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined,
- onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
- backgroundColor: data.backgroundColor,
- dragFactory: data.dragFactory,
- isSystem: true,
- })
- );
- }
-
- static setupThumbDoc(userDoc: Doc) {
- if (!userDoc.thumbDoc) {
- const thumbDoc = Docs.Create.LinearDocument(GestureOverlay.setupThumbButtons(userDoc), {
- _width: 100,
- _height: 50,
- ignoreClick: true,
- _lockedPosition: true,
- title: 'buttons',
- _layout_autoHeight: true,
- _yMargin: 5,
- linearView_IsExpanded: true,
- backgroundColor: 'white',
- isSystem: true,
- });
- thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
- _width: 300,
- _height: 25,
- _layout_autoHeight: true,
- linearView_IsExpanded: true,
- flexDirection: 'column',
- isSystem: true,
- });
- userDoc.thumbDoc = thumbDoc;
- }
- return Cast(userDoc.thumbDoc, Doc);
- }
-
componentWillUnmount() {
GestureOverlay.Instances.splice(GestureOverlay.Instances.indexOf(this), 1);
GestureOverlay.Instance = GestureOverlay.Instances.lastElement();
}
componentDidMount = () => {
GestureOverlay.Instance = this;
- this._thumbDoc = FieldValue(Cast(GestureOverlay.setupThumbDoc(Doc.UserDoc()), Doc));
- this._inkToTextDoc = FieldValue(Cast(this._thumbDoc?.inkToTextDoc, Doc));
};
// TODO: nda - add dragging groups with one finger drag and have to click into group to scroll within the group
@@ -395,24 +326,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
this.thumbIdentifier = thumb?.identifier;
this._hands.set(thumb.identifier, fingers);
- const others = fingers.filter(f => f !== thumb);
- const minX = Math.min(...others.map(f => f.clientX));
- const minY = Math.min(...others.map(f => f.clientY));
-
- // load up the palette collection around the thumb
- const thumbDoc = await Cast(GestureOverlay.setupThumbDoc(Doc.UserDoc()), Doc);
- if (thumbDoc) {
- runInAction(() => {
- RadialMenu.Instance._display = false;
- this._inkToTextDoc = FieldValue(Cast(thumbDoc.inkToTextDoc, Doc));
- this._thumbDoc = thumbDoc;
- this._thumbX = thumb.clientX;
- this._thumbY = thumb.clientY;
- this._menuX = thumb.clientX + 50;
- this._menuY = thumb.clientY;
- this._palette = <HorizontalPalette key="palette" x={minX} y={minY} thumb={[thumb.clientX, thumb.clientY]} thumbDoc={thumbDoc} />;
- });
- }
this.removeMoveListeners();
document.removeEventListener('touchmove', this.handleHandMove);
@@ -462,11 +375,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
if (Math.abs(pt.clientY - this._thumbY) > 10 * window.devicePixelRatio) {
this._selectedIndex = Math.min(Math.max(-1, -Math.ceil((pt.clientY - this._thumbY) / (10 * window.devicePixelRatio)) - 1), this._possibilities.length - 1);
}
- } else if (this._thumbDoc) {
- if (Math.abs(pt.clientX - this._thumbX) > 15 * window.devicePixelRatio) {
- this._thumbDoc.selectedIndex = Math.max(-1, NumCast(this._thumbDoc.selectedIndex) - Math.sign(pt.clientX - this._thumbX));
- this._thumbX = pt.clientX;
- }
}
}
}
@@ -485,7 +393,6 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
if (this.thumbIdentifier) this._hands.delete(this.thumbIdentifier);
this._palette = undefined;
this.thumbIdentifier = undefined;
- this._thumbDoc = undefined;
// this chunk of code is for handling the ink to text toolglass
let scriptWorked = false;
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index 9447b2e72..07e3270b1 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -182,8 +182,8 @@ export interface InkEndProps {
inkDoc: Doc;
inkView: InkingStroke;
screenSpaceLineWidth: number;
- startPt: PointData;
- endPt: PointData;
+ startPt: () => PointData;
+ endPt: () => PointData;
}
@observer
export class InkEndPtHandles extends React.Component<InkEndProps> {
@@ -191,29 +191,31 @@ export class InkEndPtHandles extends React.Component<InkEndProps> {
@observable _overEnd: boolean = false;
@action
- dragRotate = (e: React.PointerEvent, p1: () => { X: number; Y: number }, p2: () => { X: number; Y: number }) => {
+ dragRotate = (e: React.PointerEvent, pt1: () => { X: number; Y: number }, pt2: () => { X: number; Y: number }) => {
setupMoveUpEvents(
this,
e,
action(e => {
if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('stretch ink');
// compute stretch factor by finding scaling along axis between start and end points
- const v1 = { X: p1().X - p2().X, Y: p1().Y - p2().Y };
- const v2 = { X: e.clientX - p2().X, Y: e.clientY - p2().Y };
+ const p1 = pt1();
+ const p2 = pt2();
+ const v1 = { X: p1.X - p2.X, Y: p1.Y - p2.Y };
+ const v2 = { X: e.clientX - p2.X, Y: e.clientY - p2.Y };
const v1len = Math.sqrt(v1.X * v1.X + v1.Y * v1.Y);
const v2len = Math.sqrt(v2.X * v2.X + v2.Y * v2.Y);
const scaling = v2len / v1len;
const v1n = { X: v1.X / v1len, Y: v1.Y / v1len };
const v2n = { X: v2.X / v2len, Y: v2.Y / v2len };
const angle = Math.acos(v1n.X * v2n.X + v1n.Y * v2n.Y) * Math.sign(v1.X * v2.Y - v2.X * v1.Y);
- InkStrokeProperties.Instance.stretchInk(SelectionManager.Views(), scaling, p2(), v1n, e.shiftKey);
- InkStrokeProperties.Instance.rotateInk(SelectionManager.Views(), angle, p2());
+ InkStrokeProperties.Instance.stretchInk(SelectionManager.Views(), scaling, p2, v1n, e.shiftKey);
+ InkStrokeProperties.Instance.rotateInk(SelectionManager.Views(), angle, pt2()); // bcz: call pt2() func here because pt2 will have changed from previous stretchInk call
return false;
}),
action(() => {
this.props.inkView.controlUndo?.end();
this.props.inkView.controlUndo = undefined;
- UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
+ UndoManager.FilterBatches(['stroke', 'x', 'y', 'width', 'height']);
}),
returnFalse
);
@@ -237,20 +239,8 @@ export class InkEndPtHandles extends React.Component<InkEndProps> {
);
return (
<svg>
- {hdl('start', this.props.startPt, (e: React.PointerEvent) =>
- this.dragRotate(
- e,
- () => this.props.startPt,
- () => this.props.endPt
- )
- )}
- {hdl('end', this.props.endPt, (e: React.PointerEvent) =>
- this.dragRotate(
- e,
- () => this.props.endPt,
- () => this.props.startPt
- )
- )}
+ {hdl('start', this.props.startPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.startPt, this.props.endPt))}
+ {hdl('end', this.props.endPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.endPt, this.props.startPt))}
</svg>
);
}
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index d28981e17..abc4381a6 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -202,7 +202,6 @@ export class InkStrokeProperties {
@action
rotateInk = (inkStrokes: DocumentView[], angle: number, scrpt: PointData) => {
this.applyFunction(inkStrokes, (view: DocumentView, ink: InkData, xScale: number, yScale: number, inkStrokeWidth: number) => {
- view.rootDoc.rotation = NumCast(view.rootDoc.rotation) + angle;
const inkCenterPt = view.ComponentView?.ptFromScreen?.(scrpt);
return !inkCenterPt
? ink
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/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index c915ae65a..d0210d63b 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -21,7 +21,7 @@
Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class
*/
import React = require('react');
-import { action, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc } from '../../fields/Doc';
import { Height, Width } from '../../fields/DocSymbols';
@@ -88,7 +88,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
if (!addAsAnnotation && !pinProps) return this.rootDoc;
- const anchor = Docs.Create.InkConfigDocument({
+ const anchor = Docs.Create.ConfigDocument({
title: 'Ink anchor:' + this.rootDoc.title,
// set presentation timing for restoring shape
presDuration: 1100,
@@ -297,6 +297,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
*/
nearestScreenPt = () => this._nearestScrPt;
+ @computed get screenCtrlPts() {
+ const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+ return inkData
+ .map(point =>
+ this.screenToLocal()
+ .inverse()
+ .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)
+ )
+ .map(p => ({ X: p[0], Y: p[1] }));
+ }
+ startPt = () => this.screenCtrlPts[0];
+ endPt = () => this.screenCtrlPts.lastElement();
/**
* @param boundsLeft the screen space left coordinate of the ink stroke
* @param boundsTop the screen space top coordinate of the ink stroke
@@ -304,18 +316,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
*/
componentUI = (boundsLeft: number, boundsTop: number) => {
const inkDoc = this.props.Document;
- const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+ const { inkData, inkStrokeWidth } = this.inkScaledData();
const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke
const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
- const screenPts = inkData
- .map(point =>
- this.screenToLocal()
- .inverse()
- .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)
- )
- .map(p => ({ X: p[0], Y: p[1] }));
- const screenHdlPts = screenPts;
const startMarker = StrCast(this.layoutDoc.stroke_startMarker);
const endMarker = StrCast(this.layoutDoc.stroke_endMarker);
@@ -323,13 +327,13 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? (
!this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
<div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
- <InkEndPtHandles inkView={this} inkDoc={inkDoc} startPt={screenPts[0]} endPt={screenPts.lastElement()} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
+ <InkEndPtHandles inkView={this} inkDoc={inkDoc} startPt={this.startPt} endPt={this.endPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
</div>
)
) : (
<div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
{InteractionUtils.CreatePolyline(
- screenPts,
+ this.screenCtrlPts,
0,
0,
Colors.MEDIUM_BLUE,
@@ -350,8 +354,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
1.0,
false
)}
- <InkControlPtHandles inkView={this} inkDoc={inkDoc} inkCtrlPoints={inkData} screenCtrlPoints={screenHdlPts} nearestScreenPt={this.nearestScreenPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
- <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} />
+ <InkControlPtHandles inkView={this} inkDoc={inkDoc} inkCtrlPoints={inkData} screenCtrlPoints={this.screenCtrlPts} nearestScreenPt={this.nearestScreenPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
+ <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={this.screenCtrlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} />
</div>
);
};
@@ -403,20 +407,23 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
);
const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting);
const highlightIndex = highlight?.highlightIndex;
- const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent');
+ const highlightColor =
+ (!this.props.isSelected() || !isInkMask) && highlight?.highlightIndex
+ ? highlight?.highlightColor
+ : StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent');
// Invisible polygonal line that enables the ink to be selected by the user.
- const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false, mask: boolean = false) =>
+ const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false) =>
InteractionUtils.CreatePolyline(
inkData,
inkLeft,
inkTop,
- highlightColor,
+ mask && highlightColor === 'transparent' ? strokeColor : highlightColor,
inkStrokeWidth,
inkStrokeWidth + (fillColor ? (closed ? 2 : (highlightIndex ?? 0) + 2) : 2),
StrCast(this.layoutDoc.stroke_lineJoin),
StrCast(this.layoutDoc.stroke_lineCap),
StrCast(this.layoutDoc.stroke_bezier),
- !closed ? 'none' : !isInkMask && (fillColor === 'transparent' || suppressFill) ? 'none' : fillColor,
+ !closed || !fillColor || DashColor(fillColor).alpha() === 0 ? 'none' : fillColor,
'',
'',
markerScale,
@@ -456,7 +463,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
cursor: this.props.isSelected() ? 'default' : undefined,
}}
{...interactions}>
- {clickableLine(this.onPointerDown, undefined, isInkMask)}
+ {clickableLine(this.onPointerDown, isInkMask)}
{isInkMask ? null : inkLine}
</svg>
{!closed || (!RTFCast(this.rootDoc.text)?.Text && (!this.props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6b18caed0..b0b757388 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -15,6 +15,7 @@ import { TrackMovements } from '../util/TrackMovements';
import { CollectionView } from './collections/CollectionView';
import { MainView } from './MainView';
import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
+import { PingManager } from '../util/PingManager';
dotenv.config();
AssignAllExtensions();
@@ -48,6 +49,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0 }; // bcz: not sure
new LinkManager();
new TrackMovements();
new ReplayMovements();
+ new PingManager();
root.render(<MainView />);
}, 0);
})();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8c04c13f8..ec8f5989f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -489,6 +489,8 @@ export class MainView extends React.Component {
fa.faSquareRootAlt,
fa.faVolumeMute,
fa.faUserCircle,
+ fa.faHeart,
+ fa.faHeartBroken,
fa.faHighlighter,
fa.faRemoveFormat,
fa.faHandPointUp,
@@ -530,6 +532,7 @@ export class MainView extends React.Component {
});
initEventListeners = () => {
+ window.addEventListener('beforeunload', () => DocServer.UPDATE_SERVER_CACHE());
window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
window.addEventListener('dragover', e => e.preventDefault(), false);
// document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
@@ -571,7 +574,7 @@ export class MainView extends React.Component {
@action
createNewFolder = async () => {
- const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true });
+ const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true });
Doc.AddDocToList(Doc.MyFilesystem, 'data', folder);
};
@@ -582,6 +585,8 @@ export class MainView extends React.Component {
waitForDoubleClick = () => (this._exploreMode ? 'never' : undefined);
headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1);
mainScreenToLocalXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.topOfMainDocContent, 1);
+ addHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.AddDocToList(this.headerBarDoc, 'data', doc), true);
+ removeHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.RemoveDocFromList(this.headerBarDoc, 'data', doc), true);
@computed get headerBarDocView() {
return (
<div className="mainView-headerBar" style={{ height: this.headerBarDocHeight() }}>
@@ -589,18 +594,19 @@ export class MainView extends React.Component {
key="headerBarDoc"
Document={this.headerBarDoc}
DataDoc={undefined}
- addDocument={undefined}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={emptyFunction}
docViewPath={returnEmptyDoclist}
styleProvider={DefaultStyleProvider}
rootSelected={returnTrue}
- removeDocument={returnFalse}
+ addDocument={this.addHeaderDoc}
+ removeDocument={this.removeHeaderDoc}
fitContentsToBox={returnTrue}
isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events)
isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive
ScreenToLocalTransform={this.headerBarScreenXf}
childHideResizeHandles={returnTrue}
+ childDragAction="move"
dontRegisterView={true}
hideResizeHandles={true}
PanelWidth={this.headerBarDocWidth}
@@ -695,14 +701,13 @@ export class MainView extends React.Component {
sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1);
mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0);
static addDocTabFunc_impl = (doc: Doc, location: OpenWhere): boolean => {
- const whereFields = doc._type_collection === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':');
+ const whereFields = location.split(':');
const keyValue = whereFields[1]?.includes('KeyValue');
const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none;
- if (doc.dockingConfig) return DashboardView.openDashboard(doc);
+ if (doc.dockingConfig && !keyValue) return DashboardView.openDashboard(doc);
// prettier-ignore
switch (whereFields[0]) {
case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location);
- case OpenWhere.dashboard: return DashboardView.openDashboard(doc);
case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc);
case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods);
case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods);
@@ -866,7 +871,7 @@ export class MainView extends React.Component {
this._leftMenuFlyoutWidth = 0;
});
- remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.MyDockedBtns, 'data', doc), true);
+ remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && !doc.dragOnlyWithinContainer && Doc.RemoveDocFromList(Doc.MyDockedBtns, 'data', doc), true);
moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.MyDockedBtns, 'data', doc), true);
diff --git a/src/client/views/Palette.scss b/src/client/views/Palette.scss
deleted file mode 100644
index 0ec879288..000000000
--- a/src/client/views/Palette.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-.palette-container {
- .palette-thumb {
- touch-action: pan-x;
- position: absolute;
- height: 70px;
- overflow: hidden;
-
- .palette-thumbContent {
- transition: transform .3s;
- width: max-content;
- overflow: hidden;
-
- .collectionView {
- overflow: visible;
-
- .collectionLinearView-outer {
- overflow: visible;
- }
- }
- }
-
- .palette-cover {
- width: 50px;
- height: 50px;
- position: absolute;
- bottom: 0;
- border: 1px solid black;
- }
- }
-} \ No newline at end of file
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
deleted file mode 100644
index 749eb08a2..000000000
--- a/src/client/views/Palette.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { IReactionDisposer, observable, reaction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc } from '../../fields/Doc';
-import { NumCast } from '../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils';
-import { Transform } from '../util/Transform';
-import { DocumentView } from './nodes/DocumentView';
-import './Palette.scss';
-
-export interface PaletteProps {
- x: number;
- y: number;
- thumb: number[];
- thumbDoc: Doc;
-}
-
-@observer
-export default class Palette extends React.Component<PaletteProps> {
- private _selectedDisposer?: IReactionDisposer;
- @observable private _selectedIndex: number = 0;
-
- componentDidMount = () => {
- this._selectedDisposer = reaction(
- () => NumCast(this.props.thumbDoc.selectedIndex),
- i => (this._selectedIndex = i),
- { fireImmediately: true }
- );
- };
-
- componentWillUnmount = () => {
- this._selectedDisposer?.();
- };
-
- render() {
- return (
- <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
- <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
- <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}>
- <DocumentView
- Document={this.props.thumbDoc}
- DataDoc={undefined}
- addDocument={undefined}
- addDocTab={returnFalse}
- rootSelected={returnTrue}
- pinToPres={emptyFunction}
- removeDocument={undefined}
- ScreenToLocalTransform={Transform.Identity}
- PanelWidth={() => window.screen.width}
- PanelHeight={() => window.screen.height}
- renderDepth={0}
- isDocumentActive={returnTrue}
- isContentActive={emptyFunction}
- focus={emptyFunction}
- docViewPath={returnEmptyDoclist}
- styleProvider={returnEmptyString}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- childFilters={returnEmptyFilter}
- childFiltersByRanges={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- />
- <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
- </div>
- </div>
- </div>
- );
- }
-}
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/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 1f2e21dd5..09aac053a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -287,7 +287,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
pinToPres={emptyFunction}
bringToFront={returnFalse}
dontRegisterView={true}
- dropAction={undefined}
/>
</div>
);
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 939196f5d..0af9bfed2 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -90,6 +90,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const isAnchor = property.includes(':anchor');
const isAnnotated = property.includes(':annotated');
const isOpen = property.includes(':open');
+ const isEmpty = property.includes(':empty');
const boxBackground = property.includes(':box');
const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : '';
const lockedPosition = () => doc && BoolCast(doc._lockedPosition);
@@ -106,7 +107,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const url = doc?.icon ? img.url.href : img.url.href.replace(ext, '_s' + ext);
return <img src={url} width={20} height={15} style={{ margin: 'auto', display: 'block', objectFit: 'contain' }} />;
}
- return Doc.toIcon(doc, isOpen);
+ return Doc.toIcon(doc, isEmpty ? undefined : isOpen);
case StyleProp.TreeViewSortings:
const allSorts: { [key: string]: { color: string; label: string } | undefined } = {};
allSorts[TreeSort.Down] = { color: 'blue', label: '↓' };
@@ -265,6 +266,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
}
case StyleProp.PointerEvents:
const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
+ if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 62f47ba71..5c2ab3f70 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -97,8 +97,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
TraceMobx();
const firstDoc = this.props.docViews[0].props.Document;
const templateName = StrCast(firstDoc.layout_fieldKey, 'layout').replace('layout_', '');
- const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data);
- const addedTypes = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data);
+ const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
+ const addedTypes = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
const templateMenu: Array<JSX.Element> = [];
this.props.templates?.forEach((checked, template) => templateMenu.push(<TemplateToggle key={template} template={template} checked={checked} toggle={this.toggleTemplate} />));
templateMenu.push(<OtherToggle key={'default'} name={'Default'} checked={templateName === 'layout'} toggle={this.toggleDefault} />);
@@ -122,7 +122,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
rootSelected={returnFalse}
onCheckedClick={this.scriptField}
onChildClick={this.scriptField}
- dropAction={undefined}
isAnyChildContentActive={returnFalse}
isContentActive={returnTrue}
bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 0eb61a0b2..ea02bcd4c 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, Opt } from '../../../fields/Doc';
import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { returnFalse, returnZero, StopEvent } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero, StopEvent } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
@@ -60,6 +60,8 @@ export class CollectionCarouselView extends CollectionSubView() {
NativeHeight={returnZero}
onDoubleClick={this.onContentDoubleClick}
onClick={this.onContentClick}
+ isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.props.isContentActive}
+ isContentActive={this.props.childContentsActive ?? this.props.isContentActive() === false ? returnFalse : emptyFunction}
hideCaptions={show_captions ? true : false}
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={this.props.childLayoutTemplate}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e9cc2c894..a5d7e7864 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -174,9 +174,7 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
- return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1
- ? CollectionDockingView.CloseSplit(doc)
- : CollectionDockingView.AddSplit(doc, location, stack, panelName, keyValue);
+ return Array.from(CollectionDockingView.Instance?.tabMap.keys() ?? []).findIndex(tab => tab.DashDoc === doc) !== -1 ? CollectionDockingView.CloseSplit(doc) : CollectionDockingView.AddSplit(doc, location, stack, panelName, keyValue);
}
//
@@ -184,7 +182,7 @@ export class CollectionDockingView extends CollectionSubView() {
//
@action
public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
- if (document?._type_collection === CollectionViewType.Docking) return DashboardView.openDashboard(document);
+ if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document);
if (!CollectionDockingView.Instance) return false;
const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue);
if (tab) {
@@ -473,7 +471,7 @@ export class CollectionDockingView extends CollectionSubView() {
tabDestroyed = (tab: any) => {
this._flush = this._flush ?? UndoManager.StartBatch('tab movement');
- if (tab.DashDoc && ![DocumentType.KVP, DocumentType.PRES].includes(tab.DashDoc?.type)) {
+ if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) {
Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
}
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<CMVFieldRowPr
rowDrop = action((e: Event, de: DragManager.DropEvent) => {
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<CollectionViewMenu
if (docDragData?.draggedDocuments.length) {
this._buttonizableCommands?.filter(c => 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 675f23970..f1c4c2cdf 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -10,7 +10,7 @@ import { listSpec } from '../../../fields/Schema';
import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, smoothScroll, Utils } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SnappingManager } from '../../util/SnappingManager';
@@ -250,7 +250,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
rootSelected={this.rootSelected}
layout_showTitle={this.props.childlayout_showTitle}
- dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={noteTakingDocTransform}
@@ -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;
}
@@ -619,7 +620,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
@computed get backgroundEvents() {
- return SnappingManager.GetIsDragging();
+ return this.props.isContentActive() === false ? 'none' : undefined;
}
observer: any;
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<CSVFieldColu
columnDrop = action((e: Event, de: DragManager.DropEvent) => {
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 57d9bbb49..91be31289 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -52,20 +52,25 @@ export class CollectionPileView extends CollectionSubView() {
@computed get toggleIcon() {
return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' });
}
+ @computed get contentEvents() {
+ const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
+ return this.props.isContentActive() && isStarburst ? undefined : 'none';
+ }
// returns the contents of the pileup in a CollectionFreeFormView
@computed get contents() {
- const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
return (
- <div className="collectionPileView-innards" style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : 'none' }}>
+ <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}>
<CollectionFreeFormView
- {...this.props}
- childContentsActive={returnFalse}
+ {...this.props} //
layoutEngine={this.layoutEngine}
addDocument={this.addPileDoc}
- childCanEmbedOnDrag={true}
- childClickScript={this.toggleIcon}
moveDocument={this.removePileDoc}
+ // pile children never have their contents active, but will be document active whenever the entire pile is.
+ childContentsActive={returnFalse}
+ childDocumentsActive={this.props.isDocumentActive}
+ childDragAction="move"
+ childClickScript={this.toggleIcon}
/>
</div>
);
@@ -103,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,
@@ -126,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.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index a55b70e22..a19d8e696 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -104,7 +104,7 @@
.collectionStackedTimeline-left-resizer,
.collectionStackedTimeline-resizer {
- background: $medium-gray;
+ background: $dark-gray;
position: absolute;
top: 0;
height: 100%;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 9d5cb257a..ad84d859d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -119,8 +119,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
// onClick play scripts
CollectionStackedTimeline.RangeScript =
CollectionStackedTimeline.RangeScript ||
- ScriptField.MakeFunction(`setTimeout(() => scriptContext.clickAnchor(this, clientX))`, {
- // setTimeout is a hack to run script in its own properly named undo group (instead of being part of the generic onClick)
+ ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, {
self: Doc.name,
scriptContext: 'any',
clientX: 'number',
@@ -370,22 +369,22 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
// handles dragging and dropping markers in timeline
@action
internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number) {
- if (!de.embedKey && this.props.Document._isGroup) return false;
- if (!super.onInternalDrop(e, de)) return false;
-
- // 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);
- });
+ 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) => {
@@ -406,7 +405,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
_label_minFontSize: 12,
_label_maxFontSize: 24,
- _stayInCollection: true,
+ _dragOnlyWithinContainer: true,
backgroundColor: 'rgba(128, 128, 128, 0.5)',
layout_hideLinkButton: true,
onClick: FollowLinkScript(),
@@ -528,6 +527,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
);
}
+ @computed get timelineEvents() {
+ return this.props.isContentActive() ? 'all' : this.props.isContentActive() === false ? 'none' : undefined;
+ }
render() {
const overlaps: {
anchorStartTime: number;
@@ -540,7 +542,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
}));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
return this.clipDuration === 0 ? null : (
- <div ref={this.createDashEventsTarget} style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : undefined }}>
+ <div ref={this.createDashEventsTarget} style={{ pointerEvents: this.timelineEvents }}>
<div
className="collectionStackedTimeline-timelineContainer"
style={{ width: this.props.PanelWidth(), cursor: SnappingManager.GetIsDragging() ? 'grab' : '' }}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3c0d8cbc3..4756b4cd3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -17,7 +17,7 @@ import { CollectionViewType } from '../../documents/DocumentTypes';
import { DragManager, dropActionType } from '../../util/DragManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
-import { undoBatch } from '../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
@@ -295,7 +295,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return this.addDocument?.(newDoc);
}
};
- isContentActive = () => (this.props.isSelected() || this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
+ isContentActive = () => (this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
@observable _renderCount = 5;
isChildContentActive = () =>
@@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
rootSelected={this.rootSelected}
layout_showTitle={this.props.childlayout_showTitle}
- dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={stackedDocTransform}
@@ -402,11 +402,15 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
// This following three functions must be from the view Mehek showed
columnDividerDown = (e: React.PointerEvent) => {
runInAction(() => (this._cursor = 'grabbing'));
+ const batch = UndoManager.StartBatch('stacking width');
setupMoveUpEvents(
this,
e,
this.onDividerMove,
- action(() => (this._cursor = 'grab')),
+ action(() => {
+ this._cursor = 'grab';
+ batch.end();
+ }),
emptyFunction
);
};
@@ -455,18 +459,24 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
const docs = this.childDocList;
// still figuring out where to add the document
if (docs && newDocs.length) {
+ newDocs.forEach(newdoc => 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;
};
@@ -700,7 +710,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
@computed get backgroundEvents() {
- return SnappingManager.GetIsDragging();
+ return this.props.isContentActive() === false ? 'none' : undefined;
}
observer: any;
render() {
@@ -710,7 +720,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
SetValue: this.addGroup,
contents: '+ ADD A GROUP',
};
- const buttonMenu = this.rootDoc.buttonMenu;
+ const buttonMenu = this.rootDoc.layout_headerButton;
const noviceExplainer = this.rootDoc.layout_explainer;
return (
<>
@@ -727,7 +737,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
style={{
overflowY: this.isContentActive() ? 'auto' : 'hidden',
background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
- pointerEvents: (this.props.pointerEvents?.() as any) ?? (this.backgroundEvents ? 'all' : undefined),
+ pointerEvents: (this.props.pointerEvents?.() as any) ?? this.backgroundEvents,
}}
onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
onDrop={this.onExternalDrop.bind(this)}
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<CSVFieldC
columnDrop = action((e: Event, de: DragManager.DropEvent) => {
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 d1b7f6ff6..39fb2db1e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -185,12 +185,14 @@ export function CollectionSubView<X>(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 targetDropAction 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();
}
@@ -212,22 +214,22 @@ export function CollectionSubView<X>(moreProps?: X) {
const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
if (movedDocs.length) {
- const canAdd = this.props.Document._type_collection === CollectionViewType.Pile || de.embedKey || this.props.Document.allowOverlayDrop || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
- added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
+ 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);
} else {
- ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
+ ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
added = addedDocs.length ? this.addDocument(addedDocs) : true;
}
- added && e.stopPropagation();
- return added;
} else {
- ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
+ 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/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 60e6815e5..192d48c64 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -34,8 +34,6 @@ export class CollectionTimeView extends CollectionSubView() {
async componentDidMount() {
this.props.setContentView?.(this);
- //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), "");
- ///const childText = "const embedding = getEmbedding(self); switchView(embedding, detailView); embedding.dropAction='embed'; useRightSplit(embedding, shiftKey); ";
runInAction(() => {
this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name });
this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ed1e0c067..4cd3885f5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,7 +3,6 @@ import { observer } from 'mobx-react';
import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData, Height, Width } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
-import { InkTool } from '../../../fields/InkField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -90,8 +89,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
// these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
@observable _isAnyChildContentActive = false;
whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
- isContentActive = (outsideReaction?: boolean) =>
- Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction) ? true : false;
+ isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this.props.isContentActive() ? true : false);
componentWillUnmount() {
this._isDisposing = true;
@@ -142,11 +140,16 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
};
- protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+ 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;
}
};
@@ -261,7 +264,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@observable _renderCount = 1;
@computed get treeViewElements() {
TraceMobx();
- const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
+ const dragAction = StrCast(this.doc.childDragAction) as dropActionType;
const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false;
if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
@@ -276,7 +279,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
addDoc,
this.remove,
moveDoc,
- dropAction,
+ dragAction,
this.props.addDocTab,
this.props.styleProvider,
this.screenToLocalTransform,
@@ -383,7 +386,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@observable _headerHeight = 0;
@computed get content() {
const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
- const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined);
+ const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined);
const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar;
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}>
@@ -396,6 +399,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
<div
className="collectionTreeView-contents"
key="tree"
+ ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}
style={{
...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
overflow: 'auto',
@@ -419,8 +423,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
minHeight: '100%',
}}
onWheel={e => e.stopPropagation()}
- onDrop={this.onTreeDrop}
- ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}>
+ onDrop={this.onTreeDrop}>
<ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul>
</div>
</div>
@@ -440,12 +443,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
setContentView={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
- pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone}
+ pointerEvents={this.props.isContentActive() && SnappingManager.GetIsDragging() ? returnAll : returnNone}
isAnnotationOverlay={true}
isAnnotationOverlayScrollable={true}
childDocumentsActive={this.props.isDocumentActive}
fieldKey={this.props.fieldKey + '_annotations'}
- dropAction={'move'}
+ dropAction="move"
select={emptyFunction}
addDocument={this.addAnnotationDocument}
removeDocument={this.remAnnotationDocument}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7913d3188..c33519afb 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -9,6 +9,7 @@ import { TraceMobx } from '../../../fields/util';
import { returnEmptyString } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { CollectionViewType } from '../../documents/DocumentTypes';
+import { dropActionType } from '../../util/DragManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ContextMenu } from '../ContextMenu';
@@ -55,7 +56,7 @@ interface CollectionViewProps_ extends FieldViewProps {
childHideDecorationTitle?: () => boolean;
childHideResizeHandles?: () => boolean;
childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection
- childCanEmbedOnDrag?: boolean;
+ childDragAction?: dropActionType;
childXPadding?: number;
childYPadding?: number;
childLayoutString?: string;
@@ -220,7 +221,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles);
childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle);
childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
- isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive();
+ isContentActive = (outsideReaction?: boolean) => (this.isAnyChildContentActive() ? true : this.props.isContentActive());
render() {
TraceMobx();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 75e4e8abf..97d4d989b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -348,10 +348,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
// lightbox - will add the document to any collection along the path from the document to the docking view that has a field isLightbox. if none is found, it adds to the full screen lightbox
addDocTab = (doc: Doc, location: OpenWhere) => {
SelectionManager.DeselectAll();
- const whereFields = doc._type_collection === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':');
+ const whereFields = location.split(':');
const keyValue = whereFields[1]?.includes('KeyValue');
const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none;
- if (doc.dockingConfig) return DashboardView.openDashboard(doc);
+ if (doc.dockingConfig && !keyValue) return DashboardView.openDashboard(doc);
// prettier-ignore
switch (whereFields[0]) {
case undefined:
@@ -364,7 +364,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
}
return LightboxView.AddDocTab(doc, location);
- case OpenWhere.dashboard: return DashboardView.openDashboard(doc);
case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc);
case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods);
case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, undefined, keyValue);
@@ -584,7 +583,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
isContentActive={emptyFunction}
isAnyChildContentActive={returnFalse}
select={emptyFunction}
- dropAction={undefined}
isSelected={returnFalse}
dontRegisterView={true}
fieldKey={Doc.LayoutFieldKey(this.props.document)}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 9039875c1..8d8d895c6 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
@@ -21,7 +21,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../util/UndoManager';
import { EditableView } from '../EditableView';
import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss';
import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
@@ -45,7 +45,7 @@ export interface TreeViewProps {
dataDoc?: Doc;
treeViewParent: Doc;
renderDepth: number;
- dropAction: dropActionType;
+ dragAction: dropActionType;
addDocTab: (doc: Doc, where: OpenWhere) => boolean;
panelWidth: () => number;
panelHeight: () => number;
@@ -276,7 +276,7 @@ export class TreeView extends React.Component<TreeViewProps> {
};
onPointerEnter = (e: React.PointerEvent): void => {
this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
- if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+ if (e.buttons === 1 && SnappingManager.GetIsDragging() && this.props.isContentActive()) {
this._header.current!.className = 'treeView-header';
document.removeEventListener('pointermove', this.onDragMove, true);
document.removeEventListener('pointerup', this.onDragUp, true);
@@ -341,13 +341,13 @@ export class TreeView extends React.Component<TreeViewProps> {
};
makeFolder = () => {
- const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _stayInCollection: true, isFolder: true });
+ const folder = Docs.Create.TreeDocument([], { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true });
TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
return this.props.addDocument(folder);
};
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<TreeViewProps> {
@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<TreeViewProps> {
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;
@@ -391,7 +402,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd;
if (canAdd) {
this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
- const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
+ const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = false);
return res;
}
@@ -460,7 +471,7 @@ export class TreeView extends React.Component<TreeViewProps> {
addDoc,
remDoc,
moveDoc,
- this.props.dropAction,
+ this.props.dragAction,
this.props.addDocTab,
this.titleStyleProvider,
this.props.ScreenToLocalTransform,
@@ -585,12 +596,12 @@ export class TreeView extends React.Component<TreeViewProps> {
downY = e.clientY;
e.stopPropagation();
}}
- onClick={e => {
+ onClick={undoable(e => {
if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
!this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
e.stopPropagation();
}
- }}>
+ }, 'sort order')}>
{!docs
? null
: TreeView.GetChildElements(
@@ -604,7 +615,7 @@ export class TreeView extends React.Component<TreeViewProps> {
addDoc,
remDoc,
moveDoc,
- StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType,
+ StrCast(this.doc.childDragAction, this.props.dragAction) as dropActionType,
this.props.addDocTab,
this.titleStyleProvider,
this.props.ScreenToLocalTransform,
@@ -673,7 +684,7 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderBullet() {
TraceMobx();
- const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : '')) || 'question';
+ const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question';
const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined;
return (
<div
@@ -857,7 +868,6 @@ export class TreeView extends React.Component<TreeViewProps> {
};
titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - this.headerEleWidth - treeBulletWidth();
- return18 = () => 18;
/**
* Renders the EditableView title element for placement into the tree.
*/
@@ -905,7 +915,6 @@ export class TreeView extends React.Component<TreeViewProps> {
hideDecorationTitle={this.props.treeView.outlineMode}
hideResizeHandles={this.props.treeView.outlineMode}
styleProvider={this.titleStyleProvider}
- enableDragWhenActive={true}
onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
docViewPath={this.props.treeView.props.docViewPath}
treeViewDoc={this.props.treeView.props.Document}
@@ -915,17 +924,18 @@ export class TreeView extends React.Component<TreeViewProps> {
pinToPres={emptyFunction}
onClick={this.onChildClick}
onDoubleClick={this.onChildDoubleClick}
- dropAction={this.props.dropAction}
+ dragAction={this.props.dragAction}
moveDocument={this.move}
removeDocument={this.props.removeDoc}
ScreenToLocalTransform={this.getTransform}
- NativeHeight={this.return18}
+ NativeHeight={return18}
NativeWidth={returnZero}
+ shouldNotScale={returnTrue}
PanelWidth={this.titleWidth}
- PanelHeight={this.return18}
+ 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}
@@ -950,7 +960,7 @@ export class TreeView extends React.Component<TreeViewProps> {
fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? 'bold' : undefined,
textDecoration: Doc.GetT(this.doc, 'title', 'string', true) ? 'underline' : undefined,
outline: this.doc === Doc.ActiveDashboard ? 'dashed 1px #06123232' : undefined,
- pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined,
+ pointerEvents: !this.props.isContentActive() ? 'none' : undefined,
}}>
{view}
</div>
@@ -1132,7 +1142,7 @@ export class TreeView extends React.Component<TreeViewProps> {
add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean,
remove: undefined | ((doc: Doc | Doc[]) => boolean),
move: DragManager.MoveFunction,
- dropAction: dropActionType,
+ dragAction: dropActionType,
addDocTab: (doc: Doc, where: OpenWhere) => boolean,
styleProvider: undefined | StyleProviderFunc,
screenToLocalXf: () => Transform,
@@ -1218,7 +1228,7 @@ export class TreeView extends React.Component<TreeViewProps> {
panelHeight={rowHeight}
dontRegisterView={dontRegisterView}
moveDocument={move}
- dropAction={dropAction}
+ dragAction={dragAction}
addDocTab={addDocTab}
ScreenToLocalTransform={screenToLocalXf}
isContentActive={isContentActive}
@@ -1239,6 +1249,6 @@ export class TreeView extends React.Component<TreeViewProps> {
ScriptingGlobals.add(function TreeView_addNewFolder() {
TreeView._editTitleOnLoad = { id: Utils.GenerateGuid(), parent: undefined };
- const opts = { title: 'Untitled folder', _stayInCollection: true, isFolder: true };
+ const opts = { title: 'Untitled folder', _dragOnlyWithinContainer: true, isFolder: true };
return Doc.AddDocToList(Doc.MyFilesystem, 'data', Docs.Create.TreeDocument([], opts, TreeView._editTitleOnLoad.id));
});
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 11151e74e..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<Partial<collection
@undoBatch
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) {
- // dragged document is a child of this collection
- if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.embedContainer !== this.props.Document) {
- // if the source doc view's embedContainer isn't this same freeformcollectionlinkDragData.dragDocument.embedContainer === this.props.Document
+ let added = false;
+ // do nothing if link is dropped into any freeform view parent of dragged document
+ if (!linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.rootDoc) {
const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' });
- this.props.addDocument?.(source);
+ added = this.props.addDocument?.(source) ? true : false;
de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
}
- e.stopPropagation(); // do nothing if link is dropped into any freeform view parent of dragged document
- return true;
+ e.stopPropagation();
+ !added && e.preventDefault();
+ return added;
}
return false;
}
@@ -1240,7 +1241,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
};
- isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+ isContentActive = () => this.props.isContentActive();
@undoBatch
@action
@@ -1267,7 +1268,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
const pointerEvents = DocumentDecorations.Instance.Interacting
? 'none'
- : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
+ : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.());
return pointerEvents;
};
getChildDocView(entry: PoolData) {
@@ -1297,8 +1298,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
- isContentActive={this.props.childContentsActive ?? emptyFunction}
+ isDocumentActive={this.props.childDocumentsActive?.() || this.rootDoc._isGroup ? this.props.isDocumentActive : this.isContentActive}
+ isContentActive={this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction}
focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
addDocTab={this.addDocTab}
addDocument={this.props.addDocument}
@@ -1308,10 +1309,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
docViewPath={this.props.docViewPath}
styleProvider={this.getClusterColor}
- canEmbedOnDrag={this.props.childCanEmbedOnDrag}
+ dragAction={(this.rootDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
dataProvider={this.childDataProvider}
sizeProvider={this.childSizeProvider}
- dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
bringToFront={this.bringToFront}
layout_showTitle={this.props.childlayout_showTitle}
dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
@@ -1535,7 +1535,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
// create an anchor that saves information about the current state of the freeform view (pan, zoom, view type)
- const anchor = Docs.Create.CollectionConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presTransition: 500, annotationOn: this.rootDoc });
+ const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presTransition: 500, annotationOn: this.rootDoc });
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc);
if (addAsAnnotation) {
@@ -1987,7 +1987,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onDragOver={e => e.preventDefault()}
onContextMenu={this.onContextMenu}
style={{
- pointerEvents: SnappingManager.GetIsDragging() && this.childDocs.includes(DragManager.docsBeingDragged.lastElement()) ? 'all' : (this.props.pointerEvents?.() as any),
+ pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : (this.props.pointerEvents?.() as any),
textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
transform: `scale(${this.nativeDimScaling || 1})`,
width: `${100 / (this.nativeDimScaling || 1)}%`,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 534275610..5febbe83e 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -337,7 +337,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
onClick = (e: React.MouseEvent): void => {
if (this.props.pointerEvents?.() === 'none') return;
- if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+ if (Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
if (Doc.ActiveTool === InkTool.None) {
if (!(e.nativeEvent as any).marqueeHit) {
(e.nativeEvent as any).marqueeHit = true;
@@ -385,8 +385,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
newCollection._width = this.Bounds.width;
newCollection._height = this.Bounds.height;
newCollection._isGroup = makeGroup;
+ newCollection._dragWhenActive = makeGroup;
newCollection.forceActive = makeGroup;
- newCollection.enableDragWhenActive = makeGroup;
newCollection.x = this.Bounds.left;
newCollection.y = this.Bounds.top;
newCollection.layout_fitWidth = true;
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index e8ae88ae5..cd8b7a0cc 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -368,7 +368,7 @@ export class CollectionGridView extends CollectionSubView() {
<div
className="collectionGridView-contents"
ref={this.createDashEventsTarget}
- style={{ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined }}
+ style={{ pointerEvents: !this.props.isContentActive() ? 'none' : undefined }}
onContextMenu={this.onContextMenu}
onPointerDown={this.onPointerDown}
onDrop={this.onExternalDrop}>
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 65578f214..8f90e4444 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
-import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, Opt } from '../../../../fields/Doc';
@@ -50,34 +50,10 @@ export class CollectionLinearView extends CollectionSubView() {
width => this.childDocs.length && (this.layoutDoc._width = width),
{ fireImmediately: true }
);
-
- this._selectedDisposer = reaction(
- () => NumCast(this.layoutDoc.selectedIndex),
- i =>
- runInAction(() => {
- this._selectedIndex = i;
- let selected: any = undefined;
- this.childLayoutPairs.map(async (pair, ind) => {
- const isSelected = this._selectedIndex === ind;
- if (isSelected) {
- selected = pair;
- } else {
- ScriptCast(DocCast(pair.layout.proto)?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
- }
- });
- if (selected && selected.layout) {
- ScriptCast(DocCast(selected.layout.proto)?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
- }
- }),
- { fireImmediately: true }
- );
}
protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
- //used for stacking and masonry view
- this._dropDisposer && this._dropDisposer();
- if (ele) {
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
- }
+ this._dropDisposer?.();
+ if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
};
dimension = () => NumCast(this.rootDoc._height);
@@ -89,12 +65,8 @@ export class CollectionLinearView extends CollectionSubView() {
@action
exitLongLinks = () => {
- if (DocumentLinksButton.StartLink) {
- if (DocumentLinksButton.StartLink.Document) {
- action((e: React.PointerEvent<HTMLDivElement>) => {
- Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc);
- });
- }
+ if (DocumentLinksButton.StartLink?.Document) {
+ action((e: React.PointerEvent<HTMLDivElement>) => Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc));
}
DocumentLinksButton.StartLink = undefined;
DocumentLinksButton.StartLinkView = undefined;
@@ -201,7 +173,7 @@ export class CollectionLinearView extends CollectionSubView() {
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
pinToPres={emptyFunction}
- dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ dragAction={(this.layoutDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
rootSelected={this.props.isSelected}
removeDocument={this.props.removeDocument}
ScreenToLocalTransform={docXf}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 34fa0343d..6dcd2d422 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -5,7 +5,6 @@ import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { returnFalse } from '../../../../Utils';
import { DragManager, dropActionType } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
import { DocumentView } from '../../nodes/DocumentView';
@@ -194,11 +193,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
let dropInd = -1;
if (de.complete.docDragData && this._mainCont) {
let curInd = -1;
- de.complete.docDragData?.droppedDocuments.forEach(
- action((d: Doc) => {
- curInd = this.childDocs.indexOf(d);
- })
- );
+ de.complete.docDragData?.droppedDocuments.forEach(d => (curInd = this.childDocs.indexOf(d)));
Array.from(this._mainCont.children).forEach((child, index) => {
const brect = child.getBoundingClientRect();
if (brect.x < de.x && brect.x + brect.width > de.x) {
@@ -225,6 +220,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
}
})
);
+ return true;
}
}
return false;
@@ -234,7 +230,14 @@ export class CollectionMulticolumnView extends CollectionSubView() {
onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
- isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
+ isChildContentActive = () => {
+ const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive;
+ return this.props.isContentActive?.() === false || childDocsActive === false
+ ? false //
+ : this.props.isDocumentActive?.() && childDocsActive
+ ? true
+ : undefined;
+ };
getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
return (
<DocumentView
@@ -248,7 +251,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+ dragAction={(this.props.Document.childDragAction ?? this.props.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
suppressSetHeight={true}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bab77ed48..4df5dad5a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -5,7 +5,6 @@ import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { returnFalse } from '../../../../Utils';
import { DragManager, dropActionType } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
import { DocumentView } from '../../nodes/DocumentView';
@@ -194,11 +193,7 @@ export class CollectionMultirowView extends CollectionSubView() {
let dropInd = -1;
if (de.complete.docDragData && this._mainCont) {
let curInd = -1;
- de.complete.docDragData?.droppedDocuments.forEach(
- action((d: Doc) => {
- curInd = this.childDocs.indexOf(d);
- })
- );
+ de.complete.docDragData?.droppedDocuments.forEach(d => (curInd = this.childDocs.indexOf(d)));
Array.from(this._mainCont.children).forEach((child, index) => {
const brect = child.getBoundingClientRect();
if (brect.y < de.y && brect.y + brect.height > de.y) {
@@ -225,6 +220,7 @@ export class CollectionMultirowView extends CollectionSubView() {
}
})
);
+ return true;
}
}
return false;
@@ -234,7 +230,14 @@ export class CollectionMultirowView extends CollectionSubView() {
onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
- isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false);
+ isChildContentActive = () => {
+ const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive;
+ return this.props.isContentActive?.() === false || childDocsActive === false
+ ? false //
+ : this.props.isDocumentActive?.() && childDocsActive
+ ? true
+ : undefined;
+ };
getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
return (
<DocumentView
@@ -248,7 +251,7 @@ export class CollectionMultirowView extends CollectionSubView() {
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+ dropAction={StrCast(this.rootDoc.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
@@ -257,6 +260,7 @@ export class CollectionMultirowView extends CollectionSubView() {
hideResizeHandles={this.props.childHideResizeHandles?.()}
hideDecorationTitle={this.props.childHideDecorationTitle?.()}
fitContentsToBox={this.props.fitContentsToBox}
+ dragAction={this.props.childDragAction}
focus={this.props.focus}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 15424de98..ee5bf82ed 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -434,7 +434,6 @@ export class CollectionSchemaView extends CollectionSubView() {
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
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;
@@ -952,7 +951,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
styleProvider={DefaultStyleProvider}
waitForDoubleClickToClick={returnNever}
defaultDoubleClick={returnIgnore}
- enableDragWhenActive={true}
+ dragAction="move"
onClickScriptDisable="always"
focus={this.props.schema.focusDocument}
childFilters={this.props.schema.childDocFilters}
@@ -970,7 +969,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
hideLinkAnchors={true}
layout_fitWidth={returnTrue}
scriptContext={this}
- canEmbedOnDrag={true}
/>
</div>
);
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 4f3503751..e8e606030 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -53,13 +53,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
onPointerEnter = (e: any) => {
- if (!SnappingManager.GetIsDragging()) return;
- document.removeEventListener('pointermove', this.onPointerMove);
- document.addEventListener('pointermove', this.onPointerMove);
+ if (SnappingManager.GetIsDragging() && this.props.isContentActive()) {
+ document.removeEventListener('pointermove', this.onPointerMove);
+ document.addEventListener('pointermove', this.onPointerMove);
+ }
};
onPointerMove = (e: any) => {
- if (!SnappingManager.GetIsDragging()) return;
const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.embedContainer === this.schemaDoc); // this.schemaView?._selectedDocs.has(doc) ?? false;
if (this._ref && dragIsRow) {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 97264508c..a958f53ea 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -76,7 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
isSelected: returnFalse,
setHeight: returnFalse,
select: emptyFunction,
- dropAction: 'embed',
+ dragAction: 'move',
bringToFront: emptyFunction,
renderDepth: 1,
isContentActive: returnFalse,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 5af05e491..737d675aa 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -78,7 +78,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
e,
e => {
const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'embed');
- dragData.removeDropProperties = ['hidden'];
+ dragData.dropPropertiesToRemove = ['hidden'];
DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
return true;
},
@@ -170,7 +170,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
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/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 664a0fa4f..745efea08 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -70,7 +70,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
linkSearch={true}
linkCreated={this.props.linkCreated}
fieldKey="data"
- dropAction="move"
isSelected={returnTrue}
isContentActive={returnTrue}
select={returnTrue}
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 1cc09a63c..2290e0711 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,47 +31,56 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
get clipWidthKey() {
return '_' + this.props.fieldKey + '_clipWidth';
}
-
componentDidMount() {
this.props.setContentView?.(this);
}
-
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
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);
}
};
@undoBatch
- private internalDrop = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+ 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 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;
- this.dataDoc[fieldKey] = droppedDocs.lastElement();
+ !added && e.preventDefault();
+ e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
+ return added;
}
};
private registerSliding = (e: React.PointerEvent<HTMLDivElement>, 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
@@ -85,8 +93,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
};
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
- const anchor = Docs.Create.ComparisonConfigDocument({
- title: 'ImgAnchor:' + this.rootDoc.title,
+ const anchor = Docs.Create.ConfigDocument({
+ title: 'CompareAnchor:' + this.rootDoc.title,
// set presentation timing properties for restoring view
presTransition: 1000,
annotationOn: this.rootDoc,
@@ -105,12 +113,29 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
e.stopPropagation; // prevent click event action (slider movement) in registerSliding
delete this.dataDoc[fieldKey];
};
+ moveDoc = (doc: Doc, addDocument: (document: Doc | Doc[]) => 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<Doc>, props: Opt<DocumentViewProps>, 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 +143,35 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
className={`clear-button ${which}`}
onPointerDown={e => e.stopPropagation()} // prevent triggering slider movement in registerSliding
onClick={e => this.clearDoc(e, which)}>
- <FontAwesomeIcon className={`clear-button ${which}`} icon={'times'} size="sm" />
+ <FontAwesomeIcon className={`clear-button ${which}`} icon="times" size="sm" />
</div>
);
};
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 ? (
<>
<DocumentView
{...this.props}
+ Document={targetDoc}
+ DataDoc={undefined}
+ moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
+ removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2}
NativeWidth={returnZero}
NativeHeight={returnZero}
- isContentActive={returnFalse}
+ isContentActive={emptyFunction}
isDocumentActive={returnFalse}
- styleProvider={this.docStyleProvider}
- Document={targetDoc}
- DataDoc={undefined}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ styleProvider={this._isAnyChildContentActive ? this.props.styleProvider : this.docStyleProvider}
hideLinkButton={true}
- pointerEvents={returnNone}
+ pointerEvents={this._isAnyChildContentActive ? undefined : returnNone}
/>
{clearButton(which)}
</> // placeholder image if doc is missing
) : (
<div className="placeholder">
- <FontAwesomeIcon className="upload-icon" icon={'cloud-upload-alt'} size="lg" />
+ <FontAwesomeIcon className="upload-icon" icon="cloud-upload-alt" size="lg" />
</div>
);
};
@@ -157,7 +184,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
};
return (
- <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
+ <div className={`comparisonBox${this.props.isContentActive() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
{displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)}
<div className="clip-div" style={{ width: this.clipWidth + '%', transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, 'gray') }}>
{displayBox(`${this.fieldKey}_1`, 0, 0)}
@@ -169,7 +196,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
left: `calc(${this.clipWidth + '%'} - 0.5px)`,
cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (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 */
>
<div className="slide-handle" />
</div>
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index baa45e278..0fe24fe8d 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -73,7 +73,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
const anchor =
this._chartRenderer?.getAnchor(pinProps) ??
- Docs.Create.DataVizConfigDocument({
+ Docs.Create.ConfigDocument({
// when we clear selection -> we should have it so chartBox getAnchor returns undefined
// this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
/*put in some options*/
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 661061d51..6b564b0c9 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -163,7 +163,7 @@ export class LineChart extends React.Component<LineChartProps> {
// create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc)
getAnchor = (pinProps?: PinProps) => {
- const anchor = Docs.Create.LineChartConfigDocument({
+ const anchor = Docs.Create.ConfigDocument({
//
title: 'line doc selection' + this._currSelected?.x,
});
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index cfad67912..b25540dd3 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;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3d32631c0..6b37dc419 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -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';
@@ -68,7 +69,6 @@ export enum OpenWhere {
addLeft = 'add:left',
addRight = 'add:right',
addBottom = 'add:bottom',
- dashboard = 'dashboard',
close = 'close',
fullScreen = 'fullScreen',
toggle = 'toggle',
@@ -160,9 +160,11 @@ export interface DocumentViewSharedProps {
CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
PanelWidth: () => number;
PanelHeight: () => number;
+ shouldNotScale?: () => boolean;
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<StyleProviderFunc>;
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<string>;
@@ -314,7 +315,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@computed get titleHeight() {
return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
}
- @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
+ get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
}
@computed get finalLayoutKey() {
@@ -355,11 +356,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
componentDidMount() {
this.setupHandlers();
}
-
+ 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();
+ }
+ };
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 +394,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
dragData.moveDocument = this.props.moveDocument;
- dragData.canEmbed = this.props.canEmbedOnDrag;
+ dragData.canEmbed = this.rootDoc.dragAction ?? this.props.dragAction ? true : false;
const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
DragManager.StartDocumentDrag(
@@ -478,7 +485,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
: '';
DocumentViewInternal.addDocTabFunc = oldFunc;
};
- clickFunc = () => (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)) {
@@ -486,8 +493,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
preventDefault = false;
}
-
- this._singleClickFunc = clickFunc ?? (() => 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);
@@ -506,7 +518,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onPointerDown = (e: React.PointerEvent): void => {
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 +547,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
//if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._type_collection !== CollectionViewType.Docking) e.preventDefault();
// listen to move events if document content isn't active or document is draggable
- if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.enableDragWhenActive || this.rootDoc.enableDragWhenActive)) {
+ if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || BoolCast(this.rootDoc._dragWhenActive))) {
document.addEventListener('pointermove', this.onPointerMove);
}
}
@@ -549,7 +561,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
this.cleanupPointerEvents();
- this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType));
+ this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dragAction || this.props.dragAction || undefined) as dropActionType));
}
};
@@ -567,8 +579,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.onPointerUpHandler?.script) {
this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
} else if (e.button === 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
- this._doubleTap = this.rootDoc.defaultDoubleClick !== 'ignore' && Date.now() - this._lastTap < Utils.CLICK_TIME;
- if (!this.props.isSelected(true)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
+ this._doubleTap = (this.onDoubleClickHandler?.script || this.rootDoc.defaultDoubleClick !== 'ignore') && Date.now() - this._lastTap < Utils.CLICK_TIME;
+ if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
}
if (DocumentView.LongPress) e.preventDefault();
};
@@ -608,16 +620,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- 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();
+ e.preventDefault();
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;
+ return true;
}
const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
if (linkdrag) {
linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor();
if (linkdrag.linkSourceDoc) {
- e.stopPropagation();
if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
}
@@ -625,8 +638,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
}
+ e.stopPropagation();
+ return true;
}
}
+ return false;
};
@undoBatch
@@ -851,7 +867,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
setHeight = (height: number) => (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 +890,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
.some(doc => 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 +909,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<div
className="documentView-contentsView"
style={{
- pointerEvents: (isInk ? 'none' : this.pointerEvents) ?? 'all',
+ pointerEvents: (isInk ? 'none' : this.contentPointerEvents()) ?? 'all',
height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
}}>
{!this._retryThumb || !this.thumbShown() ? null : (
@@ -1085,7 +1105,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
);
const targetDoc = layout_showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
const background = StrCast(
- SharingManager.Instance.users.find(users => 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('%', '');
@@ -1357,7 +1377,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth));
}
@computed get shouldNotScale() {
- return (this.layout_fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
+ return this.props.shouldNotScale?.() || (this.layout_fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
}
@computed get effectiveNativeWidth() {
return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
@@ -1580,7 +1600,7 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data);
let wid = linkSource[Width]();
- let embedding:Doc|undefined;
+ let embedding: Doc | undefined;
const links = LinkManager.Links(linkSource);
links.forEach(link => {
const other = LinkManager.getOppositeAnchor(link, linkSource);
@@ -1594,6 +1614,6 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSour
Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
}
});
- embedding && DocServer.UPDATE_SERVER_CACHE();// if a new embedding was made, update the client's server cache so that it will not come back as a promise
+ embedding && DocServer.UPDATE_SERVER_CACHE(); // if a new embedding was made, update the client's server cache so that it will not come back as a promise
return links;
});
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<FieldViewProps> {
public static LayoutString(fieldType: { name: string }, fieldStr: string) {
- return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={"data} />"
+ return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={'data'} />"
}
@computed
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 1a78583f9..61711417f 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -43,7 +43,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
);
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
- const anchor = Docs.Create.FunctionPlotConfigDocument({
+ const anchor = Docs.Create.ConfigDocument({
//
annotationOn: this.rootDoc,
});
@@ -80,9 +80,10 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
@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 5b302e7ce..f67930a3f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -78,7 +78,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
const anchor =
this._getAnchor?.(this._savedAnnotations, false) ?? // use marquee anchor, otherwise, save zoom/pan as anchor
- Docs.Create.ImageConfigDocument({
+ Docs.Create.ConfigDocument({
title: 'ImgAnchor:' + this.rootDoc.title,
presPanX: NumCast(this.layoutDoc._freeform_panX),
presPanY: NumCast(this.layoutDoc._freeform_panY),
@@ -135,19 +135,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@action
drop = (e: Event, de: DragManager.DropEvent) => {
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<ViewBoxAnnotatableProp
this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
- e.stopPropagation();
}
}
+ !added && e.preventDefault();
+ e.stopPropagation();
+ return added;
}
+ return false;
};
@undoBatch
@@ -387,7 +388,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
ref={this._overlayIconRef}
onPointerDown={e => 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 +506,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
})}
style={{
- display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
+ display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
width: this.props.PanelWidth() ? undefined : `100%`,
height: this.props.PanelWidth() ? undefined : `100%`,
pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 5b6b0b5a7..a6712a3db 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -213,18 +213,18 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
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 64f25cb22..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<KeyValuePairProps> {
isSelected: returnFalse,
setHeight: returnFalse,
select: emptyFunction,
- dropAction: 'embed',
bringToFront: emptyFunction,
renderDepth: 1,
isContentActive: returnFalse,
@@ -110,7 +109,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
X
</button>
<input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
- <div className="keyValuePair-keyField" style={{ marginLeft: 35 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
+ <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
{'('.repeat(parenCount)}
{props.fieldKey}
{')'.repeat(parenCount)}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 52f3575cb..4439be0cd 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -74,7 +74,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
if (docDragData && missingParams?.includes((e.target as any).textContent)) {
this.paramsDoc[(e.target as any).textContent] = new List<Doc>(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/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<FieldViewProps>() {
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<ViewBoxAnnotatableProps
return this.addDocument(doc, annotationKey);
};
- pointerEvents = () => {
- 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 (
<div className="mapBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
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<ViewBoxAnnotatableProps
};
pointerEvents = () => {
- 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 c210176b0..fd4c6366b 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -238,13 +238,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
ele = document.createElement('div');
ele.append(this._pdfViewer.selectionContent()!);
}
- const docAnchor = () => {
- const anchor = Docs.Create.PdfConfigDocument({
+ const docAnchor = () =>
+ Docs.Create.ConfigDocument({
title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)),
annotationOn: this.rootDoc,
});
- return anchor;
- };
const annoAnchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations(), true);
const anchor = annoAnchor ?? docAnchor();
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.rootDoc);
@@ -561,7 +559,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div>
);
}
- 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;
@@ -594,7 +591,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
pdf={this._pdf}
focus={this.focus}
url={this.pdfUrl!.url.pathname}
- isContentActive={this.isPdfContentActive}
anchorMenuClick={this.anchorMenuClick}
loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
setPdfViewer={this.setPdfViewer}
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<ViewBoxAnnotatable
// sets field of the corresponding field key (param name) to be dropped document
@action
onDrop = (e: Event, de: DragManager.DropEvent, fieldKey: string) => {
- 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/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2ff0245d2..34a1229ba 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -323,7 +323,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
} catch (e) {}
const anchor =
this._getAnchor(this._savedAnnotations, false) ??
- Docs.Create.WebConfigDocument({
+ Docs.Create.ConfigDocument({
title: StrCast(this.rootDoc.title + ' ' + this.layoutDoc._layout_scrollTop),
y: NumCast(this.layoutDoc._layout_scrollTop),
annotationOn: this.rootDoc,
@@ -918,7 +918,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
ScreenToLocalTransform={this.scrollXf}
NativeDimScaling={returnOne}
focus={this.focus}
- dropAction="embed"
childFilters={childFilters}
select={emptyFunction}
isAnyChildContentActive={returnFalse}
@@ -1003,8 +1002,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return this.props.styleProvider?.(doc, props, property);
};
- pointerEvents = () => (!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<ViewBoxAnnotatableProps
<div
className="webBox"
ref={this._mainCont}
- style={{ pointerEvents: this.pointerEvents(), position: SnappingManager.GetIsDragging() ? 'absolute' : undefined, display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined }}>
+ style={{
+ pointerEvents: this.pointerEvents(), //
+ position: SnappingManager.GetIsDragging() ? 'absolute' : undefined,
+ display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
+ }}>
<div className="webBox-background" style={{ backgroundColor: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor) }} />
<div
className="webBox-container"
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 115777c18..da0fc9ffb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -244,7 +244,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
if (!pinProps && this._editorView?.state.selection.empty) return this.rootDoc;
- const anchor = Docs.Create.TextConfigDocument({ annotationOn: this.rootDoc });
+ const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc.title), annotationOn: this.rootDoc });
this.addDocument(anchor);
this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc);
@@ -297,7 +297,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
};
dispatchTransaction = (tx: Transaction) => {
- if (this._editorView) {
+ if (this._editorView && (this._editorView as any).docView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
@@ -531,36 +531,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- 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 {
@@ -963,7 +977,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (this._editorView && this._recordingStart) {
if (this._break) {
const textanchorFunc = () => {
- const tanch = Docs.Create.TextConfigDocument({ title: 'dictation anchor' });
+ const tanch = Docs.Create.ConfigDocument({ title: 'dictation anchor' });
return this.addDocument(tanch) ? tanch : undefined;
};
const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
@@ -1003,7 +1017,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (sel.from !== sel.to) {
const anchor =
anchorDoc ??
- Docs.Create.TextConfigDocument({
+ Docs.Create.ConfigDocument({
//
title: 'text(' + this._editorView?.state.doc.textBetween(sel.from, sel.to) + ')',
annotationOn: this.dataDoc,
@@ -1023,6 +1037,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter));
this.dataDoc[UpdatingFromServer] = this.dataDoc[ForceServerWrite] = false;
anchor.text = selectedText;
+ anchor.title = selectedText.substring(0, 30);
return anchor;
}
return anchorDoc ?? this.rootDoc;
@@ -1138,11 +1153,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
() => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layout_autoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins }),
({ sidebarHeight, textHeight, layout_autoHeight, marginsHeight }) => {
const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight));
- if (layout_autoHeight && newHeight && newHeight !== this.rootDoc.height && !this.props.dontRegisterView) {
+ if (
+ (!Array.from(FormattedTextBox._globalHighlights).includes('Bold Text') || this.props.isSelected()) && //
+ layout_autoHeight &&
+ newHeight &&
+ newHeight !== this.rootDoc.height &&
+ !this.props.dontRegisterView
+ ) {
this.props.setHeight?.(newHeight);
}
},
- { fireImmediately: true }
+ { fireImmediately: !Array.from(FormattedTextBox._globalHighlights).includes('Bold Text') }
);
this._disposers.links = reaction(
() => LinkManager.Links(this.dataDoc), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks
@@ -1216,7 +1237,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (this._editorView && selected) {
RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props);
- this.autoLink();
+ setTimeout(this.autoLink, 20);
}
// Accessing editor and text doc for gpt assisted text edits
if (this._editorView && selected) {
@@ -1830,7 +1851,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
tryUpdateScrollHeight = () => {
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);
@@ -1841,6 +1862,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
// if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
+
if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
setScrollHeight();
} else {
@@ -2013,17 +2035,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
_oldWheel: any;
render() {
TraceMobx();
- const active = this.props.isContentActive() || this.props.isSelected();
- const selected = active;
+ const active = this.props.isContentActive();
const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
- const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
- if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
+ if (!active && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
const minimal = this.props.ignoreAutoHeight;
const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
const paddingY = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
- const selPad = (selected && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
- const selPaddingClass = selected && !this.layoutDoc._createDocOnCR && paddingY >= 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., <FormattedTextBox height='{this._headerHeight}px' >
return styleFromLayoutString?.height === '0px' ? null : (
<div
@@ -2044,7 +2064,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
width: `${100 / scale}%`,
height: `${100 / scale}%`,
}),
- display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
+ display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
transition: 'inherit',
// overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
@@ -2059,7 +2079,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
style={{
overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
- pointerEvents: interactive ? undefined : 'none',
+ pointerEvents: Doc.ActiveTool === InkTool.None ? undefined : 'none',
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyDown}
@@ -2071,11 +2091,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
onPointerDown={this.onPointerDown}
onDoubleClick={this.onDoubleClick}>
<div
- className={`formattedTextBox-outer${selected ? '-selected' : ''}`}
+ className={`formattedTextBox-outer${active ? '-selected' : ''}`}
ref={this._scrollRef}
style={{
width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
- pointerEvents: !active && !SnappingManager.GetIsDragging() ? 'none' : undefined,
overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
}}
onScroll={this.onScroll}
@@ -2089,7 +2108,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
- pointerEvents: !active && !SnappingManager.GetIsDragging() ? (IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined) : undefined,
+ // pointerEvents: !active && IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined,
}}
/>
</div>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ac20126f1..ef1c3911c 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -300,8 +300,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
listItemDoc.presTransition = 500;
targetView?.setAnimEffect(listItemDoc, 500);
if (targetView?.docView && this.activeItem.presBulletExpand) {
- targetView.docView._animateScalingTo = 1.1;
- Doc.AddUnHighlightWatcher(() => (targetView!.docView!._animateScalingTo = 0));
+ targetView.docView._animateScalingTo = 1.2;
+ targetView.docView._animateScaleTime = 400;
+ Doc.AddUnHighlightWatcher(() => {
+ targetView.docView!._animateScaleTime = undefined;
+ targetView!.docView!._animateScalingTo = 0;
+ });
}
listItemDoc.opacity = undefined;
this.activeItem.presIndexed = presIndexed + 1;
@@ -1025,9 +1029,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
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.
*/
@@ -2458,9 +2459,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
childIgnoreNativeSize={true}
moveDocument={returnFalse}
ignoreUnrendered={true}
+ childDragAction="move"
//childLayoutFitWidth={returnTrue}
childOpacity={returnOne}
- //childLayoutString={PresElementBox.LayoutString('data')}
childClickScript={PresBox.navigateToDocScript}
childLayoutTemplate={this.childLayoutTemplate}
childXPadding={Doc.IsComicStyle(this.rootDoc) ? 20 : undefined}
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<FieldViewProps>() {
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<HTMLElement, string>();
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<FieldViewProps>() {
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<FieldViewProps>() {
<div
className="presItem-number"
title="select without navigation"
- style={{ pointerEvents: this.presBoxView?.isContentActive() ? 'all' : undefined }}
onPointerDown={e => {
e.stopPropagation();
if (this._itemRef.current && this._dragRef.current) {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index dd202418b..8f6b8cd41 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -483,7 +483,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
}
};
- pointerEvents = () => (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 (
<div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
@@ -514,10 +517,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
- opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+ opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length && this.props.isContentActive() ? [] : [Utils.IsOpaqueFilter()])];
childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
- if (this.inlineTextAnnotations.includes(doc)) return 'none';
+ if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none';
return 'all';
}
return this.props.styleProvider?.(doc, props, property);
@@ -536,8 +539,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
NativeWidth={returnZero}
NativeHeight={returnZero}
setContentView={emptyFunction} // override setContentView to do nothing
- pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
- childPointerEvents="all" // but freeform children need to get events to allow text editing, etc
+ pointerEvents={SnappingManager.GetIsDragging() && this.props.isContentActive() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
+ childPointerEvents={this.props.isContentActive() !== false ? 'all' : 'none'} // but freeform children need to get events to allow text editing, etc
renderDepth={this.props.renderDepth + 1}
isAnnotationOverlay={true}
fieldKey={this.props.fieldKey + '_annotations'}
@@ -549,7 +552,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
ScreenToLocalTransform={this.overlayTransform}
isAnyChildContentActive={returnFalse}
isAnnotationOverlayScrollable={true}
- dropAction="embed"
childFilters={childFilters}
select={emptyFunction}
bringToFront={emptyFunction}
@@ -558,14 +560,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
</div>
);
@computed get overlayTransparentAnnotations() {
- return this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length ? 'none' : undefined);
+ return this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length && this.props.isContentActive() ? 'none' : undefined);
}
@computed get overlayOpaqueAnnotations() {
return this.renderAnnotations(this.opaqueFilter, this.allAnnotations.some(anno => anno.mixBlendMode) ? 'hard-light' : undefined);
}
@computed get overlayLayer() {
return (
- <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
+ <div style={{ pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
{this.overlayTransparentAnnotations}
{this.overlayOpaqueAnnotations}
</div>
diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss
index a1131b92e..ede59a910 100644
--- a/src/client/views/topbar/TopBar.scss
+++ b/src/client/views/topbar/TopBar.scss
@@ -1,243 +1,256 @@
-@import "../global/globalCssVariables";
-
-
+@import '../global/globalCssVariables';
+
+.iconButton-container.primary {
+ color: white;
+ .iconButton-background {
+ filter: unset;
+ background: transparent;
+ }
+}
+.topbarHeart-red {
+ .iconButton-container.primary {
+ .iconButton-content {
+ color: red;
+ }
+ .iconButton-background {
+ background: black;
+ }
+ }
+}
.topbar-container {
- flex-direction: column;
- font-size: 10px;
- line-height: 1;
- overflow-y: auto;
- overflow-x: visible;
- background: $dark-gray;
- overflow: visible;
- z-index: 1000;
- align-items: center;
- height: $topbar-height;
- background-color: $dark-gray;
- border-bottom: $standard-border;
- padding: 0px 10px;
- cursor: default;
- display: flex;
- justify-content: center;
+ flex-direction: column;
+ font-size: 10px;
+ line-height: 1;
+ overflow-y: auto;
+ overflow-x: visible;
+ background: $dark-gray;
+ overflow: visible;
+ z-index: 1000;
+ align-items: center;
+ height: $topbar-height;
+ background-color: $dark-gray;
+ border-bottom: $standard-border;
+ padding: 0px 10px;
+ cursor: default;
+ display: flex;
+ justify-content: center;
+ width: 100%;
+
+ .topbar-inner-container {
+ display: flex;
+ flex-direction: row;
+ position: relative;
+ display: grid;
+ grid-auto-columns: 33.3% 33.3% 33.3%;
width: 100%;
+ align-items: center;
- .topbar-inner-container {
- display: flex;
- flex-direction: row;
- position: relative;
- display: grid;
- grid-auto-columns: 33.3% 33.3% 33.3%;
- width: 100%;
- align-items: center;
-
- // &:first-child {
- // height: 20px;
- // }
- }
-
- .topbar-button-text {
- color: $white;
- padding: 10px;
- size: 15;
+ // &:first-child {
+ // height: 20px;
+ // }
+ }
- &:hover {
- font-weight: 500;
- }
- }
+ .topbar-button-text {
+ color: $white;
+ padding: 10px;
+ size: 15;
- .topbar-button-icon {
- cursor: pointer;
- width: fit-content;
- display: flex;
- justify-content: center;
- gap: 4px;
- align-items: center;
- justify-self: center;
- align-self: center;
- padding: 5px;
- transition: linear 0.2s;
- color: $white;
-
- &:hover {
- background-color: darken($color: $light-gray, $amount: 20);
- font-weight: 500;
- }
- }
-
- .topbar-title {
- color: $white;
- font-size: 17;
+ &:hover {
font-weight: 500;
- }
+ }
+ }
- .topbar-center {
- grid-column: 2;
- display: inline-flex;
+ .topbar-button-icon {
+ cursor: pointer;
+ width: fit-content;
+ display: flex;
+ justify-content: center;
+ gap: 4px;
+ align-items: center;
+ justify-self: center;
+ align-self: center;
+ padding: 5px;
+ transition: linear 0.2s;
+ color: $white;
+
+ &:hover {
+ background-color: darken($color: $light-gray, $amount: 20);
+ font-weight: 500;
+ }
+ }
+
+ .topbar-title {
+ color: $white;
+ font-size: 17;
+ font-weight: 500;
+ }
+
+ .topbar-center {
+ grid-column: 2;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ gap: 5px;
+
+ .topbar-dashboard-header {
+ font-weight: 600;
+ }
+ }
+
+ .topbar-right {
+ grid-column: 3;
+ position: relative;
+ display: flex;
+ justify-content: flex-end;
+ gap: 5px;
+ margin-right: 5px;
+ }
+
+ .topbar-left {
+ grid-column: 1;
+ color: black;
+ font-family: 'Roboto';
+ position: relative;
+ display: flex;
+ width: fit-content;
+ gap: 5px;
+
+ .logo-container {
+ font-size: 15;
+ display: flex;
+ flex-direction: row;
justify-content: center;
align-items: center;
- gap: 5px;
-
- .topbar-dashboard-header {
- font-weight: 600;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+
+ .logo {
+ background-color: transparent;
+ width: 25px;
+ height: 25px;
+ margin-right: 5px;
}
- }
+ }
+ .topBar-icon:hover {
+ background-color: $close-red;
+ }
- .topbar-right {
- grid-column: 3;
- position: relative;
- display: flex;
- justify-content: flex-end;
- gap: 5px;
- margin-right: 5px;
- }
-
- .topbar-left {
- grid-column: 1;
- color: black;
+ .topbar-lozenge-user,
+ .topbar-lozenge {
+ height: 23;
+ font-size: 12;
+ color: white;
font-family: 'Roboto';
- position: relative;
+ font-weight: 400;
+ padding: 4px;
+ align-self: center;
+ margin-left: 7px;
display: flex;
- width: fit-content;
- gap: 5px;
-
- .logo-container {
- font-size: 15;
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
-
- .logo {
- background-color: transparent;
- width: 25px;
- height: 25px;
- margin-right: 5px;
-
- }
- }
+ align-items: center;
- .topBar-icon:hover {
- background-color: $close-red;
- }
+ .topbar-dashSelect {
+ border: none;
+ background-color: transparent;
+ color: black;
+ font-family: 'Roboto';
+ font-size: 17;
+ font-weight: 500;
- .topbar-lozenge-user,
- .topbar-lozenge {
- height: 23;
- font-size: 12;
- color: white;
- font-family: 'Roboto';
- font-weight: 400;
- padding: 4px;
- align-self: center;
- margin-left: 7px;
- display: flex;
- align-items: center;
-
- .topbar-dashSelect {
- border: none;
- background-color: transparent;
- color: black;
- font-family: 'Roboto';
- font-size: 17;
- font-weight: 500;
-
- &:hover {
- cursor: pointer;
- }
- }
+ &:hover {
+ cursor: pointer;
+ }
}
+ }
+
+ .topbar-logoff {
+ border-radius: 3px;
+ background: olivedrab;
+ color: white;
+ display: none;
+ margin-left: 5px;
+ padding: 1px 2px 1px 2px;
+ cursor: pointer;
+ }
- .topbar-logoff {
- border-radius: 3px;
- background: olivedrab;
- color: white;
- display: none;
- margin-left: 5px;
- padding: 1px 2px 1px 2px;
- cursor: pointer;
- }
+ .topbar-logoff {
+ background: red;
+ }
+ .topbar-lozenge-user:hover {
.topbar-logoff {
- background: red;
- }
-
- .topbar-lozenge-user:hover {
- .topbar-logoff {
- display: inline-block;
- }
- }
- }
-
- .topbar-barChild {
-
- &.topbar-collection {
- flex: 0 1 auto;
- margin-left: 2px;
- margin-right: 2px
+ display: inline-block;
}
-
- &.topbar-input {
- margin: 5px;
- border-radius: 20px;
- border: $dark-gray;
- display: block;
- width: 130px;
- -webkit-transition: width 0.4s;
- transition: width 0.4s;
- /* align-self: stretch; */
- outline: none;
-
- &:focus {
- width: 500px;
- outline: none;
- }
+ }
+ }
+
+ .topbar-barChild {
+ &.topbar-collection {
+ flex: 0 1 auto;
+ margin-left: 2px;
+ margin-right: 2px;
+ }
+
+ &.topbar-input {
+ margin: 5px;
+ border-radius: 20px;
+ border: $dark-gray;
+ display: block;
+ width: 130px;
+ -webkit-transition: width 0.4s;
+ transition: width 0.4s;
+ /* align-self: stretch; */
+ outline: none;
+
+ &:focus {
+ width: 500px;
+ outline: none;
}
+ }
- &.topbar-filter {
- align-self: stretch;
+ &.topbar-filter {
+ align-self: stretch;
- button {
- transform: none;
+ button {
+ transform: none;
- &:hover {
- transform: none;
- }
- }
+ &:hover {
+ transform: none;
+ }
}
+ }
- &.topbar-submit {
- margin-left: 2px;
- margin-right: 2px
- }
+ &.topbar-submit {
+ margin-left: 2px;
+ margin-right: 2px;
+ }
- &.topbar-close {
- color: $white;
- max-height: $topbar-height;
- }
- }
+ &.topbar-close {
+ color: $white;
+ max-height: $topbar-height;
+ }
+ }
}
.topbar-results {
- display: flex;
- flex-direction: column;
- top: 300px;
- display: flex;
- flex-direction: column;
- height: 100%;
- overflow: visible;
-
- .no-result {
- width: 500px;
- background: $light-gray;
- padding: 10px;
- height: 50px;
- text-transform: uppercase;
- text-align: left;
- font-weight: bold;
- }
-} \ No newline at end of file
+ display: flex;
+ flex-direction: column;
+ top: 300px;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: visible;
+
+ .no-result {
+ width: 500px;
+ background: $light-gray;
+ padding: 10px;
+ height: 50px;
+ text-transform: uppercase;
+ text-align: left;
+ font-weight: bold;
+ }
+}
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 1b1e69876..1d9c25e3c 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,14 +1,16 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, Size, Type } from 'browndash-components';
-import { action, computed, observable } from 'mobx';
+import { Button, IconButton, FontSize, Size, Type } from 'browndash-components';
+import { action, computed, observable, reaction } from 'mobx';
+import { Tooltip } from '@mui/material';
import { observer } from 'mobx-react';
import * as React from 'react';
import { FaBug, FaCamera, FaStamp } from 'react-icons/fa';
-import { Doc } from '../../../fields/Doc';
+import { Doc } from '../../../fields/Doc';
import { AclAdmin } from '../../../fields/DocSymbols';
import { StrCast } from '../../../fields/Types';
import { GetEffectiveAcl } from '../../../fields/util';
import { DocumentManager } from '../../util/DocumentManager';
+import { PingManager } from '../../util/PingManager';
import { ReportManager } from '../../util/ReportManager';
import { ServerStats } from '../../util/ServerStats';
import { SettingsManager } from '../../util/SettingsManager';
@@ -35,7 +37,16 @@ export class TopBar extends React.Component {
};
@observable textColor: string = Colors.LIGHT_GRAY;
- @observable backgroundColor: string = Colors.DARK_GRAY;
+ @computed get backgroundColor() {
+ return PingManager.Instance.IsBeating ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY;
+ }
+
+ @observable happyHeart: boolean = PingManager.Instance.IsBeating;
+ setHappyHeart = action((status: boolean) => (this.happyHeart = status));
+ dispose = reaction(
+ () => PingManager.Instance.IsBeating,
+ isBeating => this.setHappyHeart(isBeating)
+ );
/**
* Returns the left hand side of the topbar.
@@ -140,6 +151,17 @@ export class TopBar extends React.Component {
<IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={ReportManager.Instance.open} icon={<FaBug />} />
<IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
<IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
+ <Tooltip title={<div className="dash-tooltip">{'Server connection ' + (PingManager.Instance.IsBeating ? 'active' : 'broken')}</div>}>
+ <div className={'topbarHeart' + (this.happyHeart ? '' : '-red')}>
+ <IconButton
+ size={Size.SMALL}
+ onClick={PingManager.Instance.showAlert}
+ tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running'}
+ color={this.happyHeart ? Colors.LIGHT_BLUE : Colors.ERROR_RED}
+ icon={<FontAwesomeIcon icon={this.happyHeart ? 'heart' : 'heart-broken'} />}
+ />
+ </div>
+ </Tooltip>
{/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.textColor} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
</div>
);