1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc } from '../../../fields/Doc';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
import { LinkFollower } from '../../util/LinkFollower';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxBaseComponent } from '../DocComponent';
import { StyleProp } from '../StyleProvider';
import { FieldView, FieldViewProps } from './FieldView';
import './LinkAnchorBox.scss';
import { LinkDocPreview } from './LinkDocPreview';
import React = require('react');
import { LinkManager } from '../../util/LinkManager';
import globalCssVariables = require('../global/globalCssVariables.scss');
import { SelectionManager } from '../../util/SelectionManager';
@observer
export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LinkAnchorBox, fieldKey);
}
_doubleTap = false;
_lastTap: number = 0;
_ref = React.createRef<HTMLDivElement>();
_isOpen = false;
_timeout: NodeJS.Timeout | undefined;
@observable _x = 0;
@observable _y = 0;
onPointerDown = (e: React.PointerEvent) => {
const anchorContainerDoc = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource);
setupMoveUpEvents(
this,
e,
this.onPointerMove,
emptyFunction,
(e, doubleTap) => {
if (doubleTap) LinkFollower.FollowLink(this.rootDoc, anchorContainerDoc, this.props, false);
else this.props.select(false);
},
false
);
};
onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
const cdiv = this._ref?.current?.parentElement;
if (!this._isOpen && cdiv) {
const bounds = cdiv.getBoundingClientRect();
const pt = Utils.getNearestPointInPerimeter(bounds.left, bounds.top, bounds.width, bounds.height, e.clientX, e.clientY);
const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
if (separation > 100) {
const dragData = new DragManager.DocumentDragData([this.rootDoc]);
dragData.dropAction = 'alias';
dragData.removeDropProperties = ['anchor1_x', 'anchor1_y', 'anchor2_x', 'anchor2_y', 'isLinkButton'];
DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
return true;
} else {
this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100;
this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100;
this.rootDoc.linkAutoMove = false;
}
}
return false;
});
specificContextMenu = (e: React.MouseEvent): void => {};
render() {
TraceMobx();
const small = this.props.PanelWidth() <= 1; // this happens when rendered in a treeView
const x = NumCast(this.rootDoc[this.fieldKey + '_x'], 100);
const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100);
const linkSource = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource);
const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor');
const anchor = this.fieldKey === 'anchor1' ? 'anchor2' : 'anchor1';
const anchorScale = !this.dataDoc[this.fieldKey + '-useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title);
const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('anchor1') ? 'anchor1' : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('anchor2') ? 'anchor2' : '';
return (
<div
ref={this._ref}
title={targetTitle}
className={`linkAnchorBox-cont${small ? '-small' : ''}`}
onPointerEnter={e =>
LinkDocPreview.SetLinkInfo({
docProps: this.props,
linkSrc: linkSource,
linkDoc: this.rootDoc,
showHeader: true,
location: [e.clientX, e.clientY + 20],
noPreview: false,
})
}
onPointerDown={this.onPointerDown}
onContextMenu={this.specificContextMenu}
style={{
border: selView && this.rootDoc[selView] === this.rootDoc[this.fieldKey] ? `solid ${globalCssVariables.MEDIUM_GRAY} 2px` : undefined,
background,
left: `calc(${x}% - ${small ? 2.5 : 7.5}px)`,
top: `calc(${y}% - ${small ? 2.5 : 7.5}px)`,
transform: `scale(${anchorScale})`,
cursor: 'grab',
}}
/>
);
}
}
|