aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-12-15 13:01:18 -0500
committerbobzel <zzzman@gmail.com>2020-12-15 13:01:18 -0500
commit7b82359d68bf2fbc91d8851e2eb80c8b22930fd2 (patch)
treea92e6b2e6f9a11ef3001dc82008908caea4e69ce /src
parent2c3b8155deea0bc7916e4bcded7c969d155cbd38 (diff)
simplifying dragging to make links by moving linkDocument to event, instead of dragData. moved link anchor and caption styling to default style provider. CURRENTLY, typing text, brushing doc highlights along with a bunch of other things ARE BROKEN ..
Diffstat (limited to 'src')
-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
}
});
}