aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/linking
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/linking')
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx31
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx77
-rw-r--r--src/client/views/linking/LinkPopup.tsx22
-rw-r--r--src/client/views/linking/LinkRelationshipSearch.tsx63
4 files changed, 67 insertions, 126 deletions
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 60def5d45..cd735318e 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -1,14 +1,16 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
+/* eslint-disable react/require-default-props */
+import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
+import * as React from 'react';
import { Doc, StrListCast } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { Cast, DocCast } from '../../../fields/Types';
-import { LinkManager } from '../../util/LinkManager';
+import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentView } from '../nodes/DocumentView';
import './LinkMenu.scss';
import { LinkMenuItem } from './LinkMenuItem';
-import * as React from 'react';
-import { DocumentType } from '../../documents/DocumentTypes';
interface LinkMenuGroupProps {
sourceDoc: Doc;
@@ -22,25 +24,24 @@ interface LinkMenuGroupProps {
@observer
export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
private _menuRef = React.createRef<HTMLDivElement>();
+ @observable _collapsed = false;
getBackgroundColor = (): string | undefined => {
- const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
+ const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
let color: string | undefined;
// if this link's relationship property is not default "link", set its color
- if (link_relationshipList) {
- const relationshipIndex = link_relationshipList.indexOf(this.props.groupType);
+ if (linkRelationshipList) {
+ const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType);
const RGBcolor: string = linkColorList[relationshipIndex];
if (RGBcolor) {
- //set opacity to 0.25 by modifiying the rgb string
+ // set opacity to 0.25 by modifiying the rgb string
color = RGBcolor.slice(0, RGBcolor.length - 1) + ', 0.25)';
}
}
return color;
};
- @observable _collapsed = false;
-
render() {
const set = new Set<Doc>(this.props.group);
const groupItems = Array.from(set.keys()).map(linkDoc => {
@@ -57,8 +58,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1')
? DocCast(linkDoc.link_anchor_2)
: DocCast(linkDoc.link_anchor_1)
- : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) ||
- LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null)?.annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null));
+ : Doc.getOppositeAnchor(linkDoc, sourceDoc) || Doc.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null)?.annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null));
return !destDoc || !sourceDoc ? null : (
<LinkMenuItem
key={linkDoc[Id]}
@@ -76,7 +76,12 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
return (
<div className="linkMenu-group" ref={this._menuRef}>
- <div className="linkMenu-group-name" onClick={action(() => (this._collapsed = !this._collapsed))} style={{ background: this.getBackgroundColor() }}>
+ <div
+ className="linkMenu-group-name"
+ onClick={action(() => {
+ this._collapsed = !this._collapsed;
+ })}
+ style={{ background: this.getBackgroundColor() }}>
<p className={this.props.groupType === '*' || this.props.groupType === '' ? '' : 'expand-one'}> {this.props.groupType}:</p>
</div>
{this._collapsed ? null : <div className="linkMenu-group-wrapper">{groupItems}</div>}
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index a2c9d10b6..9ce04ffac 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -1,24 +1,25 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils';
+import { emptyFunction } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { Cast, DocCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { DocumentType } from '../../documents/DocumentTypes';
-import { DocumentManager } from '../../util/DocumentManager';
-import { DragManager, dropActionType } from '../../util/DragManager';
-import { LinkFollower } from '../../util/LinkFollower';
+import { DragManager } from '../../util/DragManager';
+import { dropActionType } from '../../util/DropActionTypes';
import { LinkManager } from '../../util/LinkManager';
-import { SelectionManager } from '../../util/SelectionManager';
-import { SettingsManager } from '../../util/SettingsManager';
+import { SnappingManager } from '../../util/SnappingManager';
import { undoBatch } from '../../util/UndoManager';
import { ObservableReactComponent } from '../ObservableReactComponent';
-import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
import { LinkInfo } from '../nodes/LinkDocPreview';
+import { OpenWhere } from '../nodes/OpenWhere';
import './LinkMenuItem.scss';
interface LinkMenuItemProps {
@@ -34,14 +35,14 @@ interface LinkMenuItemProps {
// drag links and drop link targets (embedding them if needed)
export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) {
- const draggedDocs = (specificLinks ? specificLinks : LinkManager.Links(sourceDoc)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
+ const draggedDocs = (specificLinks || LinkManager.Links(sourceDoc)).map(link => Doc.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
if (draggedDocs.length) {
const moddrag: Doc[] = [];
- for (const draggedDoc of draggedDocs) {
+ draggedDocs.forEach(async draggedDoc => {
const doc = await Cast(draggedDoc.annotationOn, Doc);
if (doc) moddrag.push(doc);
- }
+ });
const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
dragData.canEmbed = true;
@@ -77,7 +78,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
onIconDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => {
- const ancestor = DocumentManager.LinkCommonAncestor(this._props.linkDoc);
+ const ancestor = DocumentView.linkCommonAncestor(this._props.linkDoc);
if (!ancestor?.ComponentView?.removeDocument?.(this._props.linkDoc)) {
ancestor?.ComponentView?.addDocument?.(this._props.linkDoc);
}
@@ -88,10 +89,10 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
setupMoveUpEvents(
this,
e,
- e => {
+ moveEv => {
const dragData = new DragManager.DocumentDragData([this._props.linkDoc], dropActionType.embed);
dragData.dropPropertiesToRemove = ['hidden'];
- DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
+ DragManager.StartDocumentDrag([this._editRef.current!], dragData, moveEv.x, moveEv.y);
return true;
},
emptyFunction,
@@ -101,12 +102,16 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
Doc.ActivePresentation = trail;
DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight);
} else {
- SelectionManager.SelectView(this._props.docView, false);
+ DocumentView.SelectView(this._props.docView, false);
LinkManager.Instance.currentLink = this._props.linkDoc === LinkManager.Instance.currentLink ? undefined : this._props.linkDoc;
LinkManager.Instance.currentLinkAnchor = LinkManager.Instance.currentLink ? this.sourceAnchor : undefined;
- if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
- setTimeout(action(() => (SettingsManager.Instance.propertiesWidth = 250)));
+ if ((SnappingManager.PropertiesWidth ?? 0) < 100) {
+ setTimeout(
+ action(() => {
+ SnappingManager.SetPropertiesWidth(250);
+ })
+ );
}
}
})
@@ -117,11 +122,13 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
setupMoveUpEvents(
this,
e,
- e => {
- const eleClone: any = this._drag.current!.cloneNode(true);
- eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`;
- StartLinkTargetsDrag(eleClone, this._props.docView, e.x, e.y, this._props.sourceDoc, [this._props.linkDoc]);
- this._props.clearLinkEditor?.();
+ moveEv => {
+ const eleClone: any = this._drag.current?.cloneNode(true);
+ if (eleClone) {
+ eleClone.style.transform = `translate(${moveEv.x}px, ${moveEv.y}px)`;
+ StartLinkTargetsDrag(eleClone, this._props.docView, moveEv.x, moveEv.y, this._props.sourceDoc, [this._props.linkDoc]);
+ this._props.clearLinkEditor?.();
+ }
return true;
},
emptyFunction,
@@ -138,17 +145,17 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
: undefined;
if (focusDoc) this._props.docView._props.focus(focusDoc, { instant: true });
- LinkFollower.FollowLink(this._props.linkDoc, this._props.sourceDoc, false);
+ DocumentView.FollowLink(this._props.linkDoc, this._props.sourceDoc, false);
}
}
);
};
- deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this._props.linkDoc))));
+ deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => Doc.DeleteLink?.(this._props.linkDoc))));
@observable _hover = false;
docView = () => this._props.docView;
render() {
- const destinationIcon = Doc.toIcon(this._props.destinationDoc) as any as IconProp;
+ const destinationIcon = Doc.toIcon(this._props.destinationDoc);
const title = StrCast(this._props.destinationDoc.title).length > 18 ? StrCast(this._props.destinationDoc.title).substr(0, 14) + '...' : this._props.destinationDoc.title;
@@ -164,25 +171,29 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
return (
<div
className="linkMenu-item"
- onPointerEnter={action(e => (this._hover = true))}
- onPointerLeave={action(e => (this._hover = false))}
+ onPointerEnter={action(() => {
+ this._hover = true;
+ })}
+ onPointerLeave={action(() => {
+ this._hover = false;
+ })}
style={{
fontSize: this._hover ? 'larger' : undefined,
fontWeight: this._hover ? 'bold' : undefined,
- background: LinkManager.Instance.currentLink === this._props.linkDoc ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
+ background: LinkManager.Instance.currentLink === this._props.linkDoc ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor,
}}>
<div className="linkMenu-item-content expand-two">
<div
ref={this._drag}
- className="linkMenu-name" //title="drag to view target. click to customize."
+ className="linkMenu-name" // title="drag to view target. click to customize."
onPointerDown={this.onLinkButtonDown}>
<div className="linkMenu-item-buttons">
- <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Edit Link</div>}>
+ <Tooltip disableInteractive title={<div className="dash-tooltip">Edit Link</div>}>
<div className="linkMenu-icon-wrapper" ref={this._editRef} onPointerDown={this.onEdit} onClick={e => e.stopPropagation()}>
<FontAwesomeIcon className="linkMenu-icon" icon="edit" size="sm" />
</div>
</Tooltip>
- <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Show/Hide Link</div>}>
+ <Tooltip disableInteractive title={<div className="dash-tooltip">Show/Hide Link</div>}>
<div className="linkMenu-icon-wrapper" onPointerDown={this.onIconDown}>
<FontAwesomeIcon className="linkMenu-icon" icon={destinationIcon} size="sm" />
</div>
@@ -211,7 +222,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
</p>
) : null}
<div className="linkMenu-title-wrapper">
- <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Follow Link</div>}>
+ <Tooltip disableInteractive title={<div className="dash-tooltip">Follow Link</div>}>
<p className="linkMenu-destination-title">
{this._props.linkDoc.linksToAnnotation && Cast(this._props.destinationDoc.data, WebField)?.url.href === this._props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}
</p>
@@ -221,7 +232,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
</div>
<div className="linkMenu-item-buttons">
- <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Delete Link</div>}>
+ <Tooltip disableInteractive title={<div className="dash-tooltip">Delete Link</div>}>
<div className="linkMenu-deleteButton" onPointerDown={this.deleteLink} onClick={e => e.stopPropagation()}>
<FontAwesomeIcon className="fa-icon" icon="trash" size="sm" />
</div>
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index c9e3c203d..9fb1c0fdc 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -1,14 +1,12 @@
-import { action, observable } from 'mobx';
+/* eslint-disable react/require-default-props */
import { observer } from 'mobx-react';
-import { EditorView } from 'prosemirror-view';
import * as React from 'react';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
+import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils';
+import { emptyFunction } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { Transform } from '../../util/Transform';
-import { undoBatch } from '../../util/UndoManager';
import { DefaultStyleProvider } from '../StyleProvider';
-import { OpenWhere, returnEmptyDocViewList } from '../nodes/DocumentView';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+import { returnEmptyDocViewList } from '../nodes/DocumentView';
import { SearchBox } from '../search/SearchBox';
import './LinkPopup.scss';
@@ -28,16 +26,6 @@ interface LinkPopupProps {
@observer
export class LinkPopup extends React.Component<LinkPopupProps> {
- @observable private linkURL: string = '';
- @observable public view?: EditorView = undefined;
-
- // TODO: should check for valid URL
- @undoBatch
- makeLinkToURL = (target: string, lcoation: string) => ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, OpenWhere.addRight, target, target);
-
- @action
- onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => (this.linkURL = e.target.value);
-
getPWidth = () => 500;
getPHeight = () => 500;
@@ -64,7 +52,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
docViewPath={returnEmptyDocViewList}
linkFrom={linkDoc}
linkCreateAnchor={this.props.linkCreateAnchor}
- linkSearch={true}
+ linkSearch
linkCreated={this.props.linkCreated}
fieldKey="data"
isSelected={returnTrue}
diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx
deleted file mode 100644
index 0902d53b2..000000000
--- a/src/client/views/linking/LinkRelationshipSearch.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import './LinkEditor.scss';
-
-interface link_relationshipSearchProps {
- results: string[] | undefined;
- display: string;
- //callback fn to set rel + hide dropdown upon setting
- handleRelationshipSearchChange: (result: string) => void;
- toggleSearch: () => void;
-}
-@observer
-export class link_relationshipSearch extends React.Component<link_relationshipSearchProps> {
- handleResultClick = (e: React.MouseEvent) => {
- const relationship = (e.target as HTMLParagraphElement).textContent;
- if (relationship) {
- this.props.handleRelationshipSearchChange(relationship);
- }
- };
-
- handleMouseEnter = () => {
- this.props.toggleSearch();
- };
-
- handleMouseLeave = () => {
- this.props.toggleSearch();
- };
-
- /**
- * Render an empty div to increase the height of LinkEditor to accommodate 2+ results
- */
- emptyDiv = () => {
- if (this.props.results && this.props.results.length > 2 && this.props.display === 'block') {
- return <div style={{ height: '50px' }} />;
- }
- };
-
- render() {
- return (
- <div className="linkEditor-relationship-dropdown-container">
- <div className="linkEditor-relationship-dropdown" style={{ display: this.props.display }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
- {
- // return a dropdown of relationship results if there exist results
- this.props.results ? (
- this.props.results.map(result => {
- return (
- <p key={result} onClick={this.handleResultClick}>
- {result}
- </p>
- );
- })
- ) : (
- <p>No matching relationships</p>
- )
- }
- </div>
-
- {/*Render an empty div to increase the height of LinkEditor to accommodate 2+ results */}
- {this.emptyDiv()}
- </div>
- );
- }
-}