diff options
| author | Sophie Zhang <sophie_zhang@brown.edu> | 2024-01-25 11:35:26 -0500 |
|---|---|---|
| committer | Sophie Zhang <sophie_zhang@brown.edu> | 2024-01-25 11:35:26 -0500 |
| commit | f3dab2a56db5e4a6a3dca58185d94e1ff7d1dc32 (patch) | |
| tree | a7bc895266b53bb620dbd2dd71bad2e83b555446 /src/client/views/linking | |
| parent | b5c5410b4af5d2c68d2107d3f064f6e3ec4ac3f2 (diff) | |
| parent | 136f3d9f349d54e8bdd73b6380ea47c19e5edebf (diff) | |
Merge branch 'master' into sophie-ai-images
Diffstat (limited to 'src/client/views/linking')
| -rw-r--r-- | src/client/views/linking/LinkMenu.scss | 6 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenu.tsx | 23 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuGroup.tsx | 18 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuItem.scss | 2 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuItem.tsx | 104 | ||||
| -rw-r--r-- | src/client/views/linking/LinkPopup.tsx | 17 | ||||
| -rw-r--r-- | src/client/views/linking/LinkRelationshipSearch.tsx | 2 |
7 files changed, 91 insertions, 81 deletions
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index 0b9f32eee..636b6415c 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -1,4 +1,4 @@ -@import '../global/globalCssVariables'; +@import '../global/globalCssVariables.module.scss'; .linkMenu { width: auto; @@ -11,7 +11,9 @@ display: inline-block; position: relative; border: 1px solid #e4e4e4; - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); + box-shadow: + 0 10px 20px rgba(0, 0, 0, 0.19), + 0 6px 6px rgba(0, 0, 0, 0.23); max-height: 230px; overflow-y: scroll; z-index: 10; diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 9dc133e28..12b83414c 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -1,13 +1,14 @@ -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView } from '../nodes/DocumentView'; -import { LinkDocPreview } from '../nodes/LinkDocPreview'; +import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenu.scss'; import { LinkMenuGroup } from './LinkMenuGroup'; -import React = require('react'); -import { SettingsManager } from '../../util/SettingsManager'; interface Props { docView: DocumentView; @@ -20,9 +21,13 @@ interface Props { * the outermost component for the link menu of a node that contains a list of its linked nodes */ @observer -export class LinkMenu extends React.Component<Props> { +export class LinkMenu extends ObservableReactComponent<Props> { _editorRef = React.createRef<HTMLDivElement>(); @observable _linkMenuRef = React.createRef<HTMLDivElement>(); + constructor(props: any) { + super(props); + makeObservable(this); + } clear = () => this.props.clearLinkEditor?.(); @@ -34,7 +39,7 @@ export class LinkMenu extends React.Component<Props> { } onPointerDown = action((e: PointerEvent) => { - LinkDocPreview.Clear(); + LinkInfo.Clear(); if (!this._linkMenuRef.current?.contains(e.target as any) && !this._editorRef.current?.contains(e.target as any)) { this.clear(); } @@ -47,16 +52,16 @@ export class LinkMenu extends React.Component<Props> { */ renderAllGroups = (groups: Map<string, Array<Doc>>): Array<JSX.Element> => { const linkItems = Array.from(groups.entries()).map(group => ( - <LinkMenuGroup key={group[0]} itemHandler={this.props.itemHandler} docView={this.props.docView} sourceDoc={this.props.docView.props.Document} group={group[1]} groupType={group[0]} clearLinkEditor={this.clear} /> + <LinkMenuGroup key={group[0]} itemHandler={this.props.itemHandler} docView={this.props.docView} sourceDoc={this.props.docView.Document} group={group[1]} groupType={group[0]} clearLinkEditor={this.clear} /> )); return linkItems.length ? linkItems : this.props.style ? [] : [<p key="none">No links have been created yet. Drag the linking button onto another document to create a link.</p>]; }; render() { - const sourceDoc = this.props.docView.rootDoc; + const sourceDoc = this.props.docView.Document; const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc; - const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds()); + const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds); return ( <div className="linkMenu" ref={this._linkMenuRef} style={{ ...style, background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index c1a5a634c..028d3da53 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -7,7 +7,7 @@ import { LinkManager } from '../../util/LinkManager'; import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; import { LinkMenuItem } from './LinkMenuItem'; -import React = require('react'); +import * as React from 'react'; import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuGroupProps { @@ -46,19 +46,19 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { const groupItems = Array.from(set.keys()).map(linkDoc => { const sourceDoc = this.props.docView.anchorViewDoc ?? - (this.props.docView.rootDoc.type === DocumentType.LINK // - ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1') + (this.props.docView.Document.type === DocumentType.LINK // + ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(linkDoc.link_anchor_1) : DocCast(linkDoc.link_anchor_2) : this.props.sourceDoc); const destDoc = !sourceDoc ? undefined - : this.props.docView.rootDoc.type === DocumentType.LINK - ? 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)); + : this.props.docView.Document.type === DocumentType.LINK + ? 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)); return !destDoc || !sourceDoc ? null : ( <LinkMenuItem key={linkDoc[Id]} diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index e83f631a1..44c74236f 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -1,4 +1,4 @@ -@import '../global/globalCssVariables'; +@import '../global/globalCssVariables.module.scss'; .linkMenu-item { // border-top: 0.5px solid $medium-gray; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index bf2a4e1a9..dc4aee1ca 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,12 +1,13 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Tooltip } from '@material-ui/core'; -import { action, computed, observable } from 'mobx'; +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 { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; -import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; @@ -14,10 +15,10 @@ import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; -import { LinkDocPreview } from '../nodes/LinkDocPreview'; +import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import React = require('react'); interface LinkMenuItemProps { groupType: string; @@ -50,10 +51,13 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume } @observer -export class LinkMenuItem extends React.Component<LinkMenuItemProps> { +export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> { private _drag = React.createRef<HTMLDivElement>(); - _editRef = React.createRef<HTMLDivElement>(); + constructor(props: any) { + super(props); + makeObservable(this); + } @observable private _showMore: boolean = false; @action toggleShowMore(e: React.PointerEvent) { @@ -62,12 +66,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { } @computed get sourceAnchor() { - const ldoc = this.props.linkDoc; - if (this.props.sourceDoc !== ldoc.link_anchor_1 && this.props.sourceDoc !== ldoc.link_anchor_2) { - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_1); - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_2); + const ldoc = this._props.linkDoc; + if (this._props.sourceDoc !== ldoc.link_anchor_1 && this._props.sourceDoc !== ldoc.link_anchor_2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_2); } - return this.props.sourceDoc; + return this._props.sourceDoc; } onEdit = (e: React.PointerEvent) => { @@ -75,24 +79,24 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { this, e, e => { - const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'embed'); + const dragData = new DragManager.DocumentDragData([this._props.linkDoc], 'embed'); dragData.dropPropertiesToRemove = ['hidden']; DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y); return true; }, emptyFunction, action(() => { - const trail = DocCast(this.props.docView.rootDoc.presentationTrail); + const trail = DocCast(this._props.docView.Document.presentationTrail); if (trail) { Doc.ActivePresentation = trail; DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight); } else { - SelectionManager.SelectView(this.props.docView, false); - LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc; + SelectionManager.SelectView(this._props.docView, false); + LinkManager.currentLink = this._props.linkDoc === LinkManager.currentLink ? undefined : this._props.linkDoc; LinkManager.currentLinkAnchor = LinkManager.currentLink ? this.sourceAnchor : undefined; - if ((SettingsManager.propertiesWidth ?? 0) < 100) { - setTimeout(action(() => (SettingsManager.propertiesWidth = 250))); + if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) { + setTimeout(action(() => (SettingsManager.Instance.propertiesWidth = 250))); } } }) @@ -106,43 +110,44 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { 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?.(); + StartLinkTargetsDrag(eleClone, this._props.docView, e.x, e.y, this._props.sourceDoc, [this._props.linkDoc]); + this._props.clearLinkEditor?.(); return true; }, emptyFunction, () => { - this.props.clearLinkEditor?.(); - if (this.props.itemHandler) { - this.props.itemHandler?.(this.props.linkDoc); + this._props.clearLinkEditor?.(); + if (this._props.itemHandler) { + this._props.itemHandler?.(this._props.linkDoc); } else { const focusDoc = - Cast(this.props.linkDoc.link_anchor_1, Doc, null)?.annotationOn === this.props.sourceDoc - ? Cast(this.props.linkDoc.link_anchor_1, Doc, null) - : Cast(this.props.linkDoc.link_anchor_2, Doc, null)?.annotationOn === this.props.sourceDoc - ? Cast(this.props.linkDoc.link_anchor_12, Doc, null) - : undefined; - - if (focusDoc) this.props.docView.props.focus(focusDoc, { instant: true }); - LinkFollower.FollowLink(this.props.linkDoc, this.props.sourceDoc, false); + Cast(this._props.linkDoc.link_anchor_1, Doc, null)?.annotationOn === this._props.sourceDoc + ? Cast(this._props.linkDoc.link_anchor_1, Doc, null) + : Cast(this._props.linkDoc.link_anchor_2, Doc, null)?.annotationOn === this._props.sourceDoc + ? Cast(this._props.linkDoc.link_anchor_12, Doc, null) + : undefined; + + if (focusDoc) this._props.docView._props.focus(focusDoc, { instant: true }); + LinkFollower.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(() => LinkManager.Instance.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) as any as IconProp; - const title = StrCast(this.props.destinationDoc.title).length > 18 ? StrCast(this.props.destinationDoc.title).substr(0, 14) + '...' : this.props.destinationDoc.title; + const title = StrCast(this._props.destinationDoc.title).length > 18 ? StrCast(this._props.destinationDoc.title).substr(0, 14) + '...' : this._props.destinationDoc.title; const source = - this.props.sourceDoc.type === DocumentType.RTF - ? this.props.linkDoc.storedText - ? StrCast(this.props.linkDoc.storedText).length > 17 - ? StrCast(this.props.linkDoc.storedText).substr(0, 18) - : this.props.linkDoc.storedText + this._props.sourceDoc.type === DocumentType.RTF + ? this._props.linkDoc.storedText + ? StrCast(this._props.linkDoc.storedText).length > 17 + ? StrCast(this._props.linkDoc.storedText).substr(0, 18) + : this._props.linkDoc.storedText : undefined : undefined; @@ -154,7 +159,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { style={{ fontSize: this._hover ? 'larger' : undefined, fontWeight: this._hover ? 'bold' : undefined, - background: LinkManager.currentLink === this.props.linkDoc ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, + background: LinkManager.currentLink === this._props.linkDoc ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, }}> <div className="linkMenu-item-content expand-two"> <div @@ -170,14 +175,15 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { </div> <div className="linkMenu-text" - onPointerLeave={LinkDocPreview.Clear} + onPointerLeave={LinkInfo.Clear} onPointerEnter={e => - this.props.linkDoc && - this.props.clearLinkEditor && - LinkDocPreview.SetLinkInfo({ - docProps: this.props.docView.props, - linkSrc: this.props.sourceDoc, - linkDoc: this.props.linkDoc, + this._props.linkDoc && + this._props.clearLinkEditor && + LinkInfo.SetLinkInfo({ + DocumentView: this.docView, + styleProvider: this._props.docView._props.styleProvider, + linkSrc: this._props.sourceDoc, + linkDoc: this._props.linkDoc, showHeader: false, location: [(this._drag.current?.getBoundingClientRect().left ?? 100) + 40, (this._drag.current?.getBoundingClientRect().top ?? e.clientY) + 25], noPreview: false, @@ -194,10 +200,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { <FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" /> </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)} + {this._props.linkDoc.linksToAnnotation && Cast(this._props.destinationDoc.data, WebField)?.url.href === this._props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)} </p> </div> - {!this.props.linkDoc.link_description ? null : <p className="linkMenu-description">{StrCast(this.props.linkDoc.link_description).split('\n')[0].substring(0, 50)}</p>} + {!this._props.linkDoc.link_description ? null : <p className="linkMenu-description">{StrCast(this._props.linkDoc.link_description).split('\n')[0].substring(0, 50)}</p>} </div> <div className="linkMenu-item-buttons"> diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 9a9a89732..c9e3c203d 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,16 +1,16 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { EditorView } from 'prosemirror-view'; -import { Doc } from '../../../fields/Doc'; +import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { Doc } from '../../../fields/Doc'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; -import { OpenWhere } from '../nodes/DocumentView'; +import { DefaultStyleProvider } from '../StyleProvider'; +import { OpenWhere, returnEmptyDocViewList } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; -import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import React = require('react'); interface LinkPopupProps { linkFrom?: () => Doc | undefined; @@ -29,7 +29,7 @@ interface LinkPopupProps { @observer export class LinkPopup extends React.Component<LinkPopupProps> { @observable private linkURL: string = ''; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; // TODO: should check for valid URL @undoBatch @@ -61,7 +61,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> { <SearchBox Document={Doc.MySearcher} - DataDoc={Doc.MySearcher} + docViewPath={returnEmptyDocViewList} linkFrom={linkDoc} linkCreateAnchor={this.props.linkCreateAnchor} linkSearch={true} @@ -70,11 +70,10 @@ export class LinkPopup extends React.Component<LinkPopupProps> { isSelected={returnTrue} isContentActive={returnTrue} select={returnTrue} - setHeight={returnFalse} addDocument={undefined} addDocTab={returnTrue} pinToPres={emptyFunction} - rootSelected={returnTrue} + rootSelected={returnFalse} styleProvider={DefaultStyleProvider} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} @@ -82,9 +81,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> { PanelHeight={this.getPHeight} renderDepth={0} focus={emptyFunction} - docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 9662b2fea..0902d53b2 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; +import * as React from 'react'; import './LinkEditor.scss'; -import React = require('react'); interface link_relationshipSearchProps { results: string[] | undefined; |
