diff options
Diffstat (limited to 'src/client/views/linking')
-rw-r--r-- | src/client/views/linking/LinkMenuGroup.tsx | 31 | ||||
-rw-r--r-- | src/client/views/linking/LinkMenuItem.tsx | 77 | ||||
-rw-r--r-- | src/client/views/linking/LinkPopup.tsx | 22 | ||||
-rw-r--r-- | src/client/views/linking/LinkRelationshipSearch.tsx | 63 |
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> - ); - } -} |