aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts34
-rw-r--r--src/client/util/DragManager.ts7
-rw-r--r--src/client/views/StyleProvider.tsx9
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx9
-rw-r--r--src/client/views/nodes/DocumentView.tsx386
-rw-r--r--src/client/views/nodes/WebBox.tsx4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx9
-rw-r--r--src/client/views/pdf/PDFViewer.tsx6
9 files changed, 197 insertions, 269 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 95daecc64..8fd906dc7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,4 +1,4 @@
-import { runInAction } from "mobx";
+import { runInAction, action } from "mobx";
import { basename, extname } from "path";
import { DateField } from "../../fields/DateField";
import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
@@ -53,6 +53,8 @@ import { PresElementBox } from "../views/presentationview/PresElementBox";
import { SearchBox } from "../views/search/SearchBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { DocumentType } from "./DocumentTypes";
+import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
+import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup";
const path = require('path');
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
@@ -1011,11 +1013,37 @@ export namespace DocUtils {
DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d }, "audio link", "audio timeline"));
}
- export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean) {
+ export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
const sv = DocumentManager.Instance.getDocumentView(source.doc);
if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return;
if (target.doc === Doc.UserDoc()) return undefined;
+
+ const makeLink = action((linkDoc: Doc, showPopup: number[]) => {
+ LinkManager.currentLink = linkDoc;
+
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = showPopup[0];
+ TaskCompletionBox.popupY = showPopup[1] - 33;
+ TaskCompletionBox.taskCompleted = true;
+
+ LinkDescriptionPopup.popupX = showPopup[0];
+ LinkDescriptionPopup.popupY = showPopup[1];
+ LinkDescriptionPopup.descriptionPopup = true;
+
+ const rect = document.body.getBoundingClientRect();
+ if (LinkDescriptionPopup.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.popupX -= 190;
+ TaskCompletionBox.popupX -= 40;
+ }
+ if (LinkDescriptionPopup.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.popupY -= 40;
+ TaskCompletionBox.popupY -= 40;
+ }
+
+ setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
+ });
+
const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id);
Doc.GetProto(linkDoc)["anchor1-useLinkSmallAnchor"] = source.doc.useLinkSmallAnchor;
Doc.GetProto(linkDoc)["anchor2-useLinkSmallAnchor"] = target.doc.useLinkSmallAnchor;
@@ -1024,7 +1052,7 @@ export namespace DocUtils {
Doc.GetProto(linkDoc)["acl-Public"] = linkDoc["acl-Public"] = SharingPermissions.Add;
linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null);
Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title');
-
+ showPopup && makeLink(linkDoc, showPopup);
return linkDoc;
}
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 4704d9e71..1a58b4bf1 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -109,6 +109,7 @@ export namespace DragManager {
this.linkDragData = dragData instanceof LinkDragData ? dragData : undefined;
this.columnDragData = dragData instanceof ColumnDragData ? dragData : undefined;
}
+ linkDocument?: Doc;
aborted: boolean;
docDragData?: DocumentDragData;
annoDragData?: PdfAnnoDragData;
@@ -143,8 +144,7 @@ export namespace DragManager {
droppedDocuments: Doc[] = [];
linkSourceDocument: Doc;
dontClearTextBox?: boolean;
- linkDocument?: Doc;
- linkDropCallback?: (data: { linkDocument?: Doc }) => void;
+ linkDropCallback?: (data: { linkDocument: Doc }) => void;
}
export class ColumnDragData {
constructor(colKey: SchemaHeaderField) {
@@ -161,7 +161,6 @@ export namespace DragManager {
this.annotationDocument = annotationDoc;
this.offset = [0, 0];
}
- linkDocument?: Doc;
targetContext: Doc | undefined;
dragDocument: Doc;
annotationDocument: Doc;
@@ -169,7 +168,7 @@ export namespace DragManager {
offset: number[];
dropAction: dropActionType;
userDropAction: dropActionType;
- linkDropCallback?: (data: { linkDocument?: Doc }) => void;
+ linkDropCallback?: (data: { linkDocument: Doc }) => void;
}
export function MakeDropTarget(
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index f2569edbd..912d718cf 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -70,20 +70,24 @@ export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentVie
export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string): any {
const docProps = testDocProps(props) ? props : undefined;
const selected = property.includes(":selected");
+ const isCaption = property.includes(":caption");
+ const isAnchor = property.includes(":anchor");
const isBackground = () => StrListCast(doc?.layers).includes(StyleLayers.Background);
const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
switch (property.split(":")[0]) {
case StyleProp.DocContents: return undefined;
+ case StyleProp.LinkSource: return isAnchor && docProps?.Document; // pass the LinkSource to the LinkAnchorBox
case StyleProp.WidgetColor: return darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
- case StyleProp.HideLinkButton: return props?.dontRegisterView || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
+ case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
!Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
(doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") :
undefined);
case StyleProp.Color:
+ if (isCaption) return "white";
const backColor = backgroundCol() || "black";
const col = Color(backColor).rgb();
const colsum = (col.red() + col.green() + col.blue());
@@ -93,6 +97,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
case StyleProp.BorderRounding: return StrCast(doc?._borderRounding, StrCast(doc?.borderRounding));
case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) || doc?.type === DocumentType.RTF) && doc?._showTitle && !doc?._showTitleHover ? 15 : 0;
case StyleProp.BackgroundColor: {
+ if (isAnchor && docProps) return "transparent";
+ if (isCaption) return "rgba(0,0,0 ,0.4)";
if (Doc.UserDoc().renderStyle === "comic") return "transparent";
let docColor: Opt<string> = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
if (!docProps) {
@@ -144,6 +150,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
}
}
case StyleProp.PointerEvents:
+ if (isAnchor && docProps) return "none";
if (props?.pointerEvents === "none") return "none";
const layer = doc && props?.layerProvider?.(doc);
if (opacity() === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none";
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 67ad2b769..d17e87db4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -280,7 +280,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
} else {
const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
this.props.addDocument?.(source);
- linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation", ""); // TODODO this is where in text links get passed
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation", ""); // TODODO this is where in text links get passed
e.stopPropagation();
return true;
}
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 06aa852cc..e7a94580a 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -50,16 +50,15 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
const linkDrag = UndoManager.StartBatch("Drag Link");
this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View.props.Document, e.pageX, e.pageY, {
dragComplete: dropEv => {
- const linkDoc = dropEv.linkDragData?.linkDocument as Doc; // equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
- if (this.props.View && linkDoc) {
- !linkDoc.linkRelationship && (Doc.GetProto(linkDoc).linkRelationship = "hyperlink");
+ if (this.props.View && dropEv.linkDocument) {// dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
+ !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = "hyperlink");
// we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks)
// the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures
// however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView
// The documentView passes a function prop returning this link doc to its descendants who can react to changes to it.
- dropEv.linkDragData?.linkDropCallback?.(dropEv.linkDragData);
- runInAction(() => this.props.View.LinkBeingCreated = linkDoc);
+ dropEv.linkDragData?.linkDropCallback?.(dropEv as { linkDocument: Doc }); // bcz: typescript can't figure out that this is valid even though we tested dropEv.linkDocument above
+ runInAction(() => this.props.View.LinkBeingCreated = dropEv.linkDocument);
setTimeout(action(() => this.props.View.LinkBeingCreated = undefined), 0);
}
linkDrag?.end();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a005a5db4..da10f2a69 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -153,6 +153,25 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
super(props);
}
+ componentDidMount() { this.componentDidUpdate(); }
+ componentDidUpdate() {
+ this.componentWillUnmount();
+ if (this._mainCont.current) {
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
+ this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
+ this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
+ this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
+ }
+ }
+ componentWillUnmount() {
+ this._dropDisposer?.();
+ this._gestureEventDisposer?.();
+ this._multiTouchDisposer?.();
+ this._holdDisposer?.();
+ Doc.UnBrushDoc(this.props.Document);
+ }
+
+
handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
this.removeMoveListeners();
this.removeEndListeners();
@@ -194,6 +213,113 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
+ handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
+ if (!e.nativeEvent.cancelBubble && !this.props.isSelected()) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ this.removeMoveListeners();
+ this.addMoveListeners();
+ this.removeEndListeners();
+ this.addEndListeners();
+ }
+ }
+
+ handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
+ SelectionManager.DeselectAll();
+ if (this.Document.onPointerDown) return;
+ const touch = me.touchEvent.changedTouches.item(0);
+ if (touch) {
+ this._downX = touch.clientX;
+ this._downY = touch.clientY;
+ if (!e.nativeEvent.cancelBubble) {
+ if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
+ this.removeMoveListeners();
+ this.addMoveListeners();
+ this.removeEndListeners();
+ this.addEndListeners();
+ e.stopPropagation();
+ }
+ }
+ }
+
+ handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
+ if ((e as any).formattedHandled) { e.stopPropagation; return; }
+ if (e.cancelBubble && this.active) {
+ this.removeMoveListeners();
+ }
+ else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+ const touch = me.touchEvent.changedTouches.item(0);
+ if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
+ if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) {
+ this.cleanUpInteractions();
+ this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
+ }
+ }
+ e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
+ e.preventDefault();
+ }
+ }
+
+ @action
+ handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
+ const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
+ const pt1 = myTouches[0];
+ const pt2 = myTouches[1];
+ const oldPoint1 = this.prevPoints.get(pt1.identifier);
+ const oldPoint2 = this.prevPoints.get(pt2.identifier);
+ const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
+ if (pinching !== 0 && oldPoint1 && oldPoint2) {
+ const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX));
+ const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY));
+ const dX = -1 * Math.sign(dW);
+ const dY = -1 * Math.sign(dH);
+
+ if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
+ const doc = Document(this.props.Document);
+ const layoutDoc = Document(Doc.Layout(this.props.Document));
+ let nwidth = Doc.NativeWidth(layoutDoc);
+ let nheight = Doc.NativeHeight(layoutDoc);
+ const width = (layoutDoc._width || 0);
+ const height = (layoutDoc._height || (nheight / nwidth * width));
+ const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale;
+ const actualdW = Math.max(width + (dW * scale), 20);
+ const actualdH = Math.max(height + (dH * scale), 20);
+ doc.x = (doc.x || 0) + dX * (actualdW - width);
+ doc.y = (doc.y || 0) + dY * (actualdH - height);
+ const fixedAspect = e.ctrlKey || (nwidth && nheight);
+ if (fixedAspect && (!nwidth || !nheight)) {
+ Doc.SetNativeWidth(layoutDoc, nwidth = layoutDoc._width || 0);
+ Doc.SetNativeHeight(layoutDoc, nheight = layoutDoc._height || 0);
+ }
+ if (nwidth > 0 && nheight > 0) {
+ if (Math.abs(dW) > Math.abs(dH)) {
+ if (!fixedAspect) {
+ Doc.SetNativeWidth(layoutDoc, actualdW / (layoutDoc._width || 1) * Doc.NativeWidth(layoutDoc));
+ }
+ layoutDoc._width = actualdW;
+ if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width;
+ else layoutDoc._height = actualdH;
+ }
+ else {
+ if (!fixedAspect) {
+ Doc.SetNativeHeight(layoutDoc, actualdH / (layoutDoc._height || 1) * Doc.NativeHeight(doc));
+ }
+ layoutDoc._height = actualdH;
+ if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height;
+ else layoutDoc._width = actualdW;
+ }
+ } else {
+ dW && (layoutDoc._width = actualdW);
+ dH && (layoutDoc._height = actualdH);
+ dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false);
+ }
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+
@action
onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
@@ -209,43 +335,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
SelectionManager.DeselectAll();
}
- @action
- componentDidMount() {
- this.componentDidUpdate();
- }
-
- @action
- componentDidUpdate() {
- this._dropDisposer?.();
- this._gestureEventDisposer?.();
- this._multiTouchDisposer?.();
- this._holdDisposer?.();
- if (this._mainCont.current) {
- this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
- this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
- this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
- this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
- }
- }
-
- @action
- componentWillUnmount() {
- this._dropDisposer?.();
- this._gestureEventDisposer?.();
- this._multiTouchDisposer?.();
- this._holdDisposer?.();
- Doc.UnBrushDoc(this.props.Document);
- }
-
startDragging(x: number, y: number, dropAction: dropActionType) {
if (this._mainCont.current) {
const dragData = new DragManager.DocumentDragData([this.props.Document]);
const [left, top] = this.props.ScreenToLocalTransform().scale(this.ContentScale).inverse().transformPoint(0, 0);
dragData.offset = this.props.ScreenToLocalTransform().scale(this.ContentScale).transformDirection(x - left, y - top);
dragData.dropAction = dropAction;
+ dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
dragData.moveDocument = this.props.moveDocument;
- dragData.treeViewDoc = this.props.treeViewDoc;
DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.layoutDoc.onDragStart });
}
}
@@ -334,116 +432,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
stopPropagate && e.stopPropagation();
preventDefault && e.preventDefault();
}
- }).bind(this);
-
- handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
- SelectionManager.DeselectAll();
- if (this.Document.onPointerDown) return;
- const touch = me.touchEvent.changedTouches.item(0);
- if (touch) {
- this._downX = touch.clientX;
- this._downY = touch.clientY;
- if (!e.nativeEvent.cancelBubble) {
- if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
- this.removeMoveListeners();
- this.addMoveListeners();
- this.removeEndListeners();
- this.addEndListeners();
- e.stopPropagation();
- }
- }
- }
-
- handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
- if ((e as any).formattedHandled) { e.stopPropagation; return; }
- if (e.cancelBubble && this.active) {
- this.removeMoveListeners();
- }
- else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
-
- const touch = me.touchEvent.changedTouches.item(0);
- if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
- if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) {
- this.cleanUpInteractions();
- this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
- }
- }
- e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
- e.preventDefault();
- }
- }
-
- handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
- if (!e.nativeEvent.cancelBubble && !this.props.isSelected()) {
- e.stopPropagation();
- e.preventDefault();
-
- this.removeMoveListeners();
- this.addMoveListeners();
- this.removeEndListeners();
- this.addEndListeners();
- }
- }
-
-
- @action
- handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
- const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
- const pt1 = myTouches[0];
- const pt2 = myTouches[1];
- const oldPoint1 = this.prevPoints.get(pt1.identifier);
- const oldPoint2 = this.prevPoints.get(pt2.identifier);
- const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
- if (pinching !== 0 && oldPoint1 && oldPoint2) {
- const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX));
- const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY));
- const dX = -1 * Math.sign(dW);
- const dY = -1 * Math.sign(dH);
-
- if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
- const doc = Document(this.props.Document);
- const layoutDoc = Document(Doc.Layout(this.props.Document));
- let nwidth = Doc.NativeWidth(layoutDoc);
- let nheight = Doc.NativeHeight(layoutDoc);
- const width = (layoutDoc._width || 0);
- const height = (layoutDoc._height || (nheight / nwidth * width));
- const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale;
- const actualdW = Math.max(width + (dW * scale), 20);
- const actualdH = Math.max(height + (dH * scale), 20);
- doc.x = (doc.x || 0) + dX * (actualdW - width);
- doc.y = (doc.y || 0) + dY * (actualdH - height);
- const fixedAspect = e.ctrlKey || (nwidth && nheight);
- if (fixedAspect && (!nwidth || !nheight)) {
- Doc.SetNativeWidth(layoutDoc, nwidth = layoutDoc._width || 0);
- Doc.SetNativeHeight(layoutDoc, nheight = layoutDoc._height || 0);
- }
- if (nwidth > 0 && nheight > 0) {
- if (Math.abs(dW) > Math.abs(dH)) {
- if (!fixedAspect) {
- Doc.SetNativeWidth(layoutDoc, actualdW / (layoutDoc._width || 1) * Doc.NativeWidth(layoutDoc));
- }
- layoutDoc._width = actualdW;
- if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width;
- else layoutDoc._height = actualdH;
- }
- else {
- if (!fixedAspect) {
- Doc.SetNativeHeight(layoutDoc, actualdH / (layoutDoc._height || 1) * Doc.NativeHeight(doc));
- }
- layoutDoc._height = actualdH;
- if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height;
- else layoutDoc._width = actualdW;
- }
- } else {
- dW && (layoutDoc._width = actualdW);
- dH && (layoutDoc._height = actualdH);
- dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false);
- }
- }
- e.stopPropagation();
- e.preventDefault();
- }
- }
+ })
onPointerDown = (e: React.PointerEvent): void => {
// continue if the event hasn't been canceled AND we are using a moues or this is has an onClick or onDragStart function (meaning it is a button document)
@@ -527,11 +516,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
@undoBatch @action
- toggleRaiseWhenDragged = () => {
- this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined;
- }
-
- @undoBatch @action
toggleFollowLink = (location: Opt<string>, zoom: boolean, setPushpin: boolean): void => {
this.Document.ignoreClick = false;
this.Document.isLinkButton = !this.Document.isLinkButton;
@@ -564,7 +548,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this.Document.isPushpin = false;
this.Document.onClick = this.layoutDoc.onClick = undefined;
}
-
@undoBatch
noOnClick = (): void => {
this.Document.ignoreClick = false;
@@ -585,45 +568,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
"linking to document tabs not yet supported. Drop link on document content.");
return;
}
- const makeLink = action((linkDoc: Doc) => {
- LinkManager.currentLink = linkDoc;
-
- TaskCompletionBox.textDisplayed = "Link Created";
- TaskCompletionBox.popupX = de.x;
- TaskCompletionBox.popupY = de.y - 33;
- TaskCompletionBox.taskCompleted = true;
-
- LinkDescriptionPopup.popupX = de.x;
- LinkDescriptionPopup.popupY = de.y;
- LinkDescriptionPopup.descriptionPopup = true;
-
- const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
- TaskCompletionBox.popupX -= 40;
- }
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
- TaskCompletionBox.popupY -= 40;
- }
-
- setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
- });
- if (de.complete.annoDragData) {
- /// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner
- e.stopPropagation();
- de.complete.annoDragData.linkDocument = DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link");
- de.complete.annoDragData.linkDocument && makeLink(de.complete.annoDragData.linkDocument);
- }
- if (de.complete.linkDragData) {
+ const linkSource = de.complete.annoDragData ? de.complete.annoDragData.annotationDocument : de.complete.linkDragData ? de.complete.linkDragData.linkSourceDocument : undefined;
+ if (linkSource && linkSource !== this.props.Document) {
e.stopPropagation();
- const linkSource = de.complete.linkDragData.linkSourceDocument;
- if (linkSource !== this.props.Document) {
- const linkDoc = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, `link`);
- linkSource !== this.props.Document && (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed
- linkDoc && makeLink(linkDoc);
- }
-
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, "link", undefined, undefined, undefined, [de.x, de.y]);
}
}
@@ -707,7 +655,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : [];
zorderItems.push({ description: "Bring to Front", event: () => SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" });
zorderItems.push({ description: "Send to Back", event: () => SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" });
- zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: this.toggleRaiseWhenDragged, icon: "expand-arrows-alt" });
+ zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: undoBatch(action(() => this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined)), icon: "expand-arrows-alt" });
!zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" });
onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
@@ -784,17 +732,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
});
}
- rootSelected = (outsideReaction?: boolean) => {
- return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
- }
-
+ rootSelected = (outsideReaction?: boolean) => { return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; }
panelHeight = () => this.props.PanelHeight() - this.headerMargin;
parentActive = (outsideReaction: boolean) => this.props.layerProvider?.(this.layoutDoc) === false ? this.props.parentActive(outsideReaction) : false;
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
contentScaling = () => this.ContentScale;
onClickFunc = () => this.onClickHandler;
- onDoubleClickFunc = () => this.onDoubleClickHandler;
-
+ makeLink = () => this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined.
@observable contentsActive: () => boolean = returnFalse;
@action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive;
@@ -805,41 +749,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
pointerEvents: this.props.contentPointerEvents as any,
height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
}}>
- <DocumentContentsView key={1}
- renderDepth={this.props.renderDepth}
- Document={this.props.Document}
- DataDoc={this.props.DataDoc}
- fitContentsToDoc={this.props.fitContentsToDoc}
- ContainingCollectionView={this.props.ContainingCollectionView}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- PanelWidth={this.props.PanelWidth}
- PanelHeight={this.props.PanelHeight}
+ <DocumentContentsView key={1} {...this.props}
scaling={this.contentScaling}
- layerProvider={this.props.layerProvider}
- styleProvider={this.props.styleProvider}
- LayoutTemplateString={this.props.LayoutTemplateString}
- LayoutTemplate={this.props.LayoutTemplate}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
+ PanelHeight={this.panelHeight}
contentsActive={this.setContentsActive}
parentActive={this.parentActive}
- whenActiveChanged={this.props.whenActiveChanged}
- makeLink={this.makeLink}
- focus={this.props.focus}
- dontRegisterView={this.props.dontRegisterView}
- addDocument={this.props.addDocument}
- removeDocument={this.props.removeDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres}
ScreenToLocalTransform={this.screenToLocal}
- ignoreAutoHeight={this.props.ignoreAutoHeight}
- bringToFront={this.props.bringToFront}
- isSelected={this.props.isSelected}
- select={this.props.select}
+ makeLink={this.makeLink}
rootSelected={this.rootSelected}
- scriptContext={this.props.scriptContext}
onClick={this.onClickFunc}
layoutKey={this.finalLayoutKey} />
{this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
@@ -859,26 +776,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
}
- makeLink = () => this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined.
-
@undoBatch
hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true)
anchorPanelWidth = () => this.props.PanelWidth() || 1;
anchorPanelHeight = () => this.props.PanelHeight() || 1;
- anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
- if (testDocProps(props)) {
- switch (property.split(":")[0]) {
- case StyleProp.BackgroundColor: return "transparent"; // background of linkanchor documentView is transparent since it covers the whole document
- case StyleProp.HideLinkButton: return true; // don't want linkAnchor documentview to show its own link button
- case StyleProp.PointerEvents: return "none"; // don't want linkAnchor documentView to handle events (since it covers the whole document). However, the linkAnchorBox itself is set to pointerEvent all
- }
- } else {
- switch (property.split(":")[0]) {
- case StyleProp.LinkSource: return this.props.Document; // pass the LinkSource to the LinkAnchorBox
- }
- }
- return this.props.styleProvider?.(doc, props, property);
- }
+ anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => this.props.styleProvider?.(doc, props, property + ":anchor");
@computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); }
@computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); }
@@ -904,11 +806,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(d, this.props.Document)}`)} />
</div >);
}
- captionStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps>, property: string) => {
- if (property === StyleProp.Color) return "white";
- if (property === StyleProp.BackgroundColor) return "rgba(0,0,0 ,0.4)";
- return this.props?.styleProvider?.(doc, props, property);
- }
+ captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ":caption");
@computed get innards() {
TraceMobx();
const showTitle = this.ShowTitle;
@@ -938,9 +836,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
display={"block"}
fontSize={10}
GetValue={() => Field.toString((this.dataDoc || this.props.Document)[showTitle.split(";")[0]] as any as Field)}
- SetValue={undoBatch((value: string) => {
- showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true;
- })}
+ SetValue={undoBatch((value) => showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true)}
/>
</div>);
return this.props.hideTitle || (!showTitle && !showCaption) ?
@@ -988,7 +884,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onContextMenu={this.onContextMenu}
onKeyDown={this.onKeyDown}
onPointerDown={this.onPointerDown}
- onClick={this.onClick.bind(this)}
+ onClick={this.onClick}
onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))}
onPointerLeave={action(e => {
let entered = false;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 125bf62f0..8e824a447 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -546,8 +546,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
- if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) {
- e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ if (!e.aborted && e.annoDragData && !e.linkDocument) {
+ e.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
annotationDoc.isLinkButton = true;
annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document;
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f82e533ad..0bb483b41 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -478,11 +478,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
de.complete.annoDragData.linkDropCallback = this.linkDrop;
}
}
- linkDrop = (data: { linkDocument?: Doc }) => {
- const linkDoc = data.linkDocument!;
- const anchor1Title = linkDoc.anchor1 instanceof Doc ? StrCast(linkDoc.anchor1.title) : "-untitled-";
- const anchor1Id = linkDoc.anchor1 instanceof Doc ? linkDoc.anchor1[Id] : "";
- this.makeLinkToSelection(linkDoc[Id], anchor1Title, "add:right", anchor1Id);
+ linkDrop = (data: { linkDocument: Doc }) => {
+ const anchor1Title = data.linkDocument.anchor1 instanceof Doc ? StrCast(data.linkDocument.anchor1.title) : "-untitled-";
+ const anchor1Id = data.linkDocument.anchor1 instanceof Doc ? data.linkDocument.anchor1[Id] : "";
+ this.makeLinkToSelection(data.linkDocument[Id], anchor1Title, "add:right", anchor1Id);
}
getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index be64754af..d6d500702 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -633,12 +633,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
- if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) {
- e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ if (!e.aborted && e.annoDragData && !e.linkDocument) {
+ e.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
}
annotationDoc.isLinkButton = true; // prevents link button fro showing up --- maybe not a good thing?
annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document;
- e.annoDragData && e.annoDragData.linkDocument && e.annoDragData?.linkDropCallback?.({ linkDocument: e.annoDragData.linkDocument });
+ e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument above
}
});
}