diff options
Diffstat (limited to 'src/client/views/nodes/LinkAnchorBox.tsx')
-rw-r--r-- | src/client/views/nodes/LinkAnchorBox.tsx | 167 |
1 files changed, 91 insertions, 76 deletions
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 7fd289a97..85a8622ec 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,30 +1,31 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -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 { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +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 { LinkManager } from "../../util/LinkManager"; -import { SelectionManager } from "../../util/SelectionManager"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { ViewBoxBaseComponent } from "../DocComponent"; -import { LinkEditor } from "../linking/LinkEditor"; -import { StyleProp } from "../StyleProvider"; -import { FieldView, FieldViewProps } from "./FieldView"; -import "./LinkAnchorBox.scss"; -import { LinkDocPreview } from "./LinkDocPreview"; -import React = require("react"); -const higflyout = require("@hig/flyout"); +import { DragManager } from '../../util/DragManager'; +import { LinkFollower } from '../../util/LinkFollower'; +import { SelectionManager } from '../../util/SelectionManager'; +import { ContextMenu } from '../ContextMenu'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { ViewBoxBaseComponent } from '../DocComponent'; +import { LinkEditor } from '../linking/LinkEditor'; +import { StyleProp } from '../StyleProvider'; +import { FieldView, FieldViewProps } from './FieldView'; +import './LinkAnchorBox.scss'; +import { LinkDocPreview } from './LinkDocPreview'; +import React = require('react'); +const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; - @observer export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(LinkAnchorBox, fieldKey); + } _doubleTap = false; _lastTap: number = 0; _ref = React.createRef<HTMLDivElement>(); @@ -38,7 +39,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, false); - } + }; onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { const cdiv = this._ref && this._ref.current && this._ref.current.parentElement; if (!this._isOpen && cdiv) { @@ -47,20 +48,20 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { 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"]; + 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[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100; + this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100; } } return false; }); @action onClick = (e: React.MouseEvent) => { - if ((e.button === 2 || e.ctrlKey || !this.layoutDoc.isLinkButton)) { + if (e.button === 2 || e.ctrlKey || !this.layoutDoc.isLinkButton) { this.props.select(false); } if (!this._doubleTap && !e.ctrlKey && e.button < 2) { @@ -68,10 +69,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { this._editing = true; anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false); if (anchorContainerDoc && !this.layoutDoc.onClick && !this._isOpen) { - this._timeout = setTimeout(action(() => { - LinkManager.FollowLink(this.rootDoc, anchorContainerDoc, this.props, false); - this._editing = false; - }), 300 - (Date.now() - this._lastTap)); + this._timeout = setTimeout( + action(() => { + LinkFollower.FollowLink(this.rootDoc, anchorContainerDoc, this.props, false); + this._editing = false; + }), + 300 - (Date.now() - this._lastTap) + ); e.stopPropagation(); } } else { @@ -81,17 +85,17 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { this.openLinkEditor(e); e.stopPropagation(); } - } + }; openLinkDocOnRight = (e: React.MouseEvent) => { - this.props.addDocTab(this.rootDoc, "add:right"); - } + this.props.addDocTab(this.rootDoc, 'add:right'); + }; openLinkTargetOnRight = (e: React.MouseEvent) => { const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null)); alias._isLinkButton = undefined; - alias.layoutKey = "layout"; - this.props.addDocTab(alias, "add:right"); - } + alias.layoutKey = 'layout'; + this.props.addDocTab(alias, 'add:right'); + }; @action openLinkEditor = action((e: React.MouseEvent) => { SelectionManager.DeselectAll(); @@ -100,56 +104,67 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() { specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Open Link Target on Right", event: () => this.openLinkTargetOnRight(e), icon: "eye" }); - funcs.push({ description: "Open Link on Right", event: () => this.openLinkDocOnRight(e), icon: "eye" }); - funcs.push({ description: "Open Link Editor", event: () => this.openLinkEditor(e), icon: "eye" }); - funcs.push({ description: "Toggle Always Show Link", event: () => this.props.Document.linkDisplay = !this.props.Document.linkDisplay, icon: "eye" }); + funcs.push({ description: 'Open Link Target on Right', event: () => this.openLinkTargetOnRight(e), icon: 'eye' }); + funcs.push({ description: 'Open Link on Right', event: () => this.openLinkDocOnRight(e), icon: 'eye' }); + funcs.push({ description: 'Open Link Editor', event: () => this.openLinkEditor(e), icon: 'eye' }); + funcs.push({ description: 'Toggle Always Show Link', event: () => (this.props.Document.linkDisplay = !this.props.Document.linkDisplay), icon: 'eye' }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); - } + ContextMenu.Instance.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); + }; 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 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 : .25; + 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 flyout = ( <div className="linkAnchorBoxBox-flyout" title=" " onPointerOver={() => Doc.UnBrushDoc(this.rootDoc)}> - <LinkEditor sourceDoc={Cast(this.dataDoc[this.fieldKey], Doc, null)} hideback={true} linkDoc={this.rootDoc} showLinks={action(() => { })} /> - {!this._forceOpen ? (null) : <div className="linkAnchorBox-linkCloser" onPointerDown={action(() => this._isOpen = this._editing = this._forceOpen = false)}> - <FontAwesomeIcon color="dimgray" icon={"times"} size={"sm"} /> - </div>} + <LinkEditor sourceDoc={Cast(this.dataDoc[this.fieldKey], Doc, null)} hideback={true} linkDoc={this.rootDoc} showLinks={action(() => {})} /> + {!this._forceOpen ? null : ( + <div className="linkAnchorBox-linkCloser" onPointerDown={action(() => (this._isOpen = this._editing = this._forceOpen = false))}> + <FontAwesomeIcon color="dimgray" icon={'times'} size={'sm'} /> + </div> + )} + </div> + ); + return ( + <div + className={`linkAnchorBox-cont${small ? '-small' : ''}`} + onPointerLeave={LinkDocPreview.Clear} + onPointerEnter={e => + LinkDocPreview.SetLinkInfo({ + docProps: this.props, + linkSrc: linkSource, + linkDoc: this.rootDoc, + showHeader: true, + location: [e.clientX, e.clientY + 20], + }) + } + onPointerDown={this.onPointerDown} + onClick={this.onClick} + title={targetTitle} + onContextMenu={this.specificContextMenu} + ref={this._ref} + style={{ + background, + left: `calc(${x}% - ${small ? 2.5 : 7.5}px)`, + top: `calc(${y}% - ${small ? 2.5 : 7.5}px)`, + transform: `scale(${anchorScale})`, + }}> + {!this._editing && !this._forceOpen ? null : ( + <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} open={this._forceOpen ? true : undefined} onOpen={() => (this._isOpen = true)} onClose={action(() => (this._isOpen = this._forceOpen = this._editing = false))}> + <span className="linkAnchorBox-button"> + <FontAwesomeIcon icon={'eye'} size={'lg'} /> + </span> + </Flyout> + )} </div> ); - return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} - onPointerLeave={LinkDocPreview.Clear} - onPointerEnter={e => LinkDocPreview.SetLinkInfo({ - docProps: this.props, - linkSrc: linkSource, - linkDoc: this.rootDoc, - showHeader: true, - location: [e.clientX, e.clientY + 20] - })} - onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu} - ref={this._ref} - style={{ - background, - left: `calc(${x}% - ${small ? 2.5 : 7.5}px)`, - top: `calc(${y}% - ${small ? 2.5 : 7.5}px)`, - transform: `scale(${anchorScale})` - }} > - {!this._editing && !this._forceOpen ? (null) : - <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} open={this._forceOpen ? true : undefined} onOpen={() => this._isOpen = true} onClose={action(() => this._isOpen = this._forceOpen = this._editing = false)}> - <span className="linkAnchorBox-button" > - <FontAwesomeIcon icon={"eye"} size={"lg"} /> - </span> - </Flyout>} - </div>; } } |