diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Utils.ts | 1 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 21 | ||||
-rw-r--r-- | src/client/util/LinkManager.ts | 13 | ||||
-rw-r--r-- | src/client/views/MarqueeAnnotator.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx | 12 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/linking/LinkEditor.tsx | 39 | ||||
-rw-r--r-- | src/client/views/linking/LinkMenu.tsx | 2 | ||||
-rw-r--r-- | src/client/views/linking/LinkPopup.scss | 2 | ||||
-rw-r--r-- | src/client/views/linking/LinkPopup.tsx | 44 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/LinkDescriptionPopup.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 23 | ||||
-rw-r--r-- | src/client/views/search/SearchBox.tsx | 39 | ||||
-rw-r--r-- | src/client/views/topbar/TopBar.scss | 1 |
16 files changed, 136 insertions, 74 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index 194c38a6f..f9ca8646f 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -439,6 +439,7 @@ export function emptyFunction() { } export function unimplementedFunction() { throw new Error("This function is not implemented, but should be."); } + export type Without<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; export type Predicate<K, V> = (entry: [K, V]) => boolean; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 48886aa3b..91bd8e772 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,7 +1,7 @@ import { action, runInAction } from "mobx"; -import { basename, extname } from "path"; +import { basename } from "path"; import { DateField } from "../../fields/DateField"; -import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing, updateCachedAcls } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Initializing, Opt, updateCachedAcls, WidthSym } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { HtmlField } from "../../fields/HtmlField"; import { InkField } from "../../fields/InkField"; @@ -13,20 +13,20 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; -import { MessageStore } from "../../server/Message"; import { Upload } from "../../server/SharedMediaTypes"; import { OmitKeys, Utils } from "../../Utils"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { DocServer } from "../DocServer"; import { Networking } from "../Network"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { DocumentManager } from "../util/DocumentManager"; import { dropActionType } from "../util/DragManager"; import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox"; import { LinkManager } from "../util/LinkManager"; import { Scripting } from "../util/Scripting"; import { undoBatch, UndoManager } from "../util/UndoManager"; -import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { ContextMenu } from "../views/ContextMenu"; import { ContextMenuProps } from "../views/ContextMenuItem"; @@ -36,30 +36,29 @@ import { AudioBox } from "../views/nodes/AudioBox"; import { ColorBox } from "../views/nodes/ColorBox"; import { ComparisonBox } from "../views/nodes/ComparisonBox"; import { DocFocusOptions } from "../views/nodes/DocumentView"; +import { EquationBox } from "../views/nodes/EquationBox"; +import { FieldViewProps } from "../views/nodes/FieldView"; import { FilterBox } from "../views/nodes/FilterBox"; import { FontIconBox } from "../views/nodes/FontIconBox"; import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; +import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox"; import { ImageBox } from "../views/nodes/ImageBox"; import { KeyValueBox } from "../views/nodes/KeyValueBox"; import { LabelBox } from "../views/nodes/LabelBox"; import { LinkBox } from "../views/nodes/LinkBox"; import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup"; import { PDFBox } from "../views/nodes/PDFBox"; -import { PresBox } from "../views/nodes/trails/PresBox"; import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; import { ScriptingBox } from "../views/nodes/ScriptingBox"; import { SliderBox } from "../views/nodes/SliderBox"; import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; +import { PresBox } from "../views/nodes/trails/PresBox"; +import { PresElementBox } from "../views/nodes/trails/PresElementBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; -import { PresElementBox } from "../views/nodes/trails/PresElementBox"; import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; -import { EquationBox } from "../views/nodes/EquationBox"; -import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox"; -import { CurrentUserUtils } from "../util/CurrentUserUtils"; -import { FieldViewProps } from "../views/nodes/FieldView"; const path = require('path'); const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -270,6 +269,8 @@ export class DocumentOptions { useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox border?: string; //for searchbox hoverBackgroundColor?: string; // background color of a label when hovered + linkRelationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor) + linkColorList?: List<string>; // colors of links corresponding to specific link relationships } export namespace Docs { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 3579083e4..84ff3a3ff 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -3,6 +3,7 @@ import { computedFn } from "mobx-utils"; import { DirectLinksSym, Doc, DocListCast, Field, Opt } from "../../fields/Doc"; import { List } from "../../fields/List"; import { ProxyField } from "../../fields/Proxy"; +import { listSpec } from "../../fields/Schema"; import { BoolCast, Cast, PromiseValue, StrCast } from "../../fields/Types"; import { LightboxView } from "../views/LightboxView"; import { DocumentViewSharedProps, ViewAdjustment } from "../views/nodes/DocumentView"; @@ -33,6 +34,7 @@ export class LinkManager { static links: Doc[] = []; constructor() { LinkManager._instance = this; + this.createLinkrelationshipLists(); setTimeout(() => { LinkManager.userLinkDBs = []; const addLinkToDoc = (link: Doc) => { @@ -97,6 +99,17 @@ export class LinkManager { }); } + + public createLinkrelationshipLists = () => { + //create new lists for link relations and their associated colors if the lists don't already exist + if (!Doc.UserDoc().linkRelationshipList && !Doc.UserDoc().linkColorList) { + const linkRelationshipList = new List<string>(); + const linkColorList = new List<string>(); + Doc.UserDoc().linkRelationshipList = linkRelationshipList; + Doc.UserDoc().linkColorList = linkColorList; + } + } + public addLink(linkDoc: Doc, checkExists = false) { if (!checkExists || !DocListCast(Doc.LinkDBDoc().data).includes(linkDoc)) { Doc.AddDocToList(Doc.LinkDBDoc(), "data", linkDoc); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index a3a3bce56..fa1a4cfea 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -68,6 +68,8 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> { AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true)); AnchorMenu.Instance.Highlight = this.highlight; AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => this.highlight("rgba(173, 216, 230, 0.75)", true, savedAnnotations); + AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor; + /** * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation. * It also initiates a Drag/Drop interaction to place the text annotation. diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index a8f5e6dd2..0c44df64c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -9,6 +9,9 @@ import { SnappingManager } from "../../../util/SnappingManager"; import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); +import { LinkManager } from "../../../util/LinkManager"; +import { List } from "../../../fields/List"; + export interface CollectionFreeFormLinkViewProps { A: DocumentView; @@ -173,8 +176,15 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo render() { if (!this.renderData) return (null); const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; + LinkManager.currentLink = this.props.LinkDocs[0]; + const linkRelationship = LinkManager.currentLink?.linkRelationship; //get string representing relationship + const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>; + const linkColorList = Doc.UserDoc().linkColorList as List<string>; + //access stroke color using index of the relationship in the color list (default black) + const strokeColor = linkRelationshipList.indexOf(linkRelationship) == -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)]; + console.log(strokeColor); return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<> - <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2" }} + <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }} d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} /> {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} > {StrCast(this.props.LinkDocs[0].description)} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 5e0b31754..e812064b7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -9,6 +9,7 @@ import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); import { DocumentType } from "../../../documents/DocumentTypes"; +import { LinkManager } from "../../../util/LinkManager"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index f74b422d3..7d6f4caf2 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -2,12 +2,14 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../fields/Doc"; -import { DateCast, StrCast } from "../../../fields/Types"; +import { Doc, StrListCast } from "../../../fields/Doc"; +import { Cast, DateCast, StrCast } from "../../../fields/Types"; import { LinkManager } from "../../util/LinkManager"; import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import React = require("react"); +import { listSpec } from "../../../fields/Schema"; +import { List } from "../../../fields/List"; interface LinkEditorProps { @@ -39,6 +41,16 @@ export class LinkEditor extends React.Component<LinkEditorProps> { setRelationshipValue = action((value: string) => { if (LinkManager.currentLink) { LinkManager.currentLink.linkRelationship = value; + const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); + const linkColorList = StrListCast(Doc.UserDoc().linkColorList); + // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color + if (linkRelationshipList && !linkRelationshipList.includes(value)) { + linkRelationshipList.push(value); + const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")"; + linkColorList.push(randColor) + console.log(randColor) + console.log("linkRelList size: " + linkRelationshipList.length); + } this.relationshipButtonColor = "rgb(62, 133, 55)"; setTimeout(action(() => this.relationshipButtonColor = ""), 750); return true; @@ -70,7 +82,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { } onDown = () => this.setDescripValue(this.description); - onRelationshipDown = () => this.setRelationshipValue(this.description); + onRelationshipDown = () => this.setRelationshipValue(this.relationship); @action handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; } @@ -87,10 +99,11 @@ export class LinkEditor extends React.Component<LinkEditorProps> { style={{ width: "100%" }} id="input" value={this.relationship} - placeholder={"enter link label"} + placeholder={"Enter link relationship"} // color={"rgb(88, 88, 88)"} onKeyDown={this.onRelationshipKey} onChange={this.handleRelationshipChange} + onBlur={this.onRelationshipDown} ></input> </div> <div className="linkEditor-description-add-button" @@ -110,7 +123,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { style={{ width: "100%" }} id="input" value={this.description} - placeholder={"enter link label"} + placeholder={"Enter link description"} // color={"rgb(88, 88, 88)"} onKeyDown={this.onKey} onChange={this.handleChange} @@ -149,35 +162,35 @@ export class LinkEditor extends React.Component<LinkEditorProps> { <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("default")}> Default - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("add:left")}> Always open in new left pane - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("add:right")}> Always open in new right pane - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("replace:right")}> Always replace right tab - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("replace:left")}> Always replace left tab - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("fullScreen")}> Always open full screen - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("add")}> Always open in a new tab - </div> + </div> <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("replace")}> Replace Tab - </div> + </div> {this.props.linkDoc.linksToAnnotation ? <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior("openExternal")}> diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 6fc860447..53fe3f682 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -41,7 +41,7 @@ export class LinkMenu extends React.Component<Props> { /** * maps each link to a JSX element to be rendered - * @param groups LinkManager containing info of all of the links + * @param groups containing info of all of the links * @returns list of link JSX elements if there at least one linked element */ renderAllGroups = (groups: Map<string, Array<Doc>>): Array<JSX.Element> => { diff --git a/src/client/views/linking/LinkPopup.scss b/src/client/views/linking/LinkPopup.scss index 8ae65158d..60c9ebfcd 100644 --- a/src/client/views/linking/LinkPopup.scss +++ b/src/client/views/linking/LinkPopup.scss @@ -5,7 +5,7 @@ height: 200px; width: 200px; position: absolute; - padding: 15px; + // padding: 15px; border-radius: 3px; input { diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index df469c53b..c8be9069c 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,33 +1,21 @@ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Tooltip } from '@material-ui/core'; -import { action, observable, runInAction } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from "mobx-react"; -import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, StrCast } from '../../../fields/Types'; -import { WebField } from '../../../fields/URLField'; -import { emptyFunction, setupMoveUpEvents, returnFalse, returnTrue, returnEmptyDoclist, returnEmptyFilter } from '../../../Utils'; -import { DocumentType } from '../../documents/DocumentTypes'; -import { DocumentManager } from '../../util/DocumentManager'; -import { DragManager } from '../../util/DragManager'; -import { Hypothesis } from '../../util/HypothesisUtils'; -import { LinkManager } from '../../util/LinkManager'; -import { undoBatch } from '../../util/UndoManager'; -import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewSharedProps } from '../nodes/DocumentView'; -import { LinkDocPreview } from '../nodes/LinkDocPreview'; -import './LinkPopup.scss'; -import React = require("react"); +import { EditorView } from 'prosemirror-view'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { DocUtils } from '../../documents/Documents'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; -import { DefaultStyleProvider } from '../StyleProvider'; import { Transform } from '../../util/Transform'; -import { DocUtils } from '../../documents/Documents'; -import { SearchBox } from '../search/SearchBox'; -import { EditorView } from 'prosemirror-view'; +import { undoBatch } from '../../util/UndoManager'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; +import { SearchBox } from '../search/SearchBox'; +import { DefaultStyleProvider } from '../StyleProvider'; +import './LinkPopup.scss'; +import React = require("react"); +import { Doc, Opt } from '../../../fields/Doc'; interface LinkPopupProps { showPopup: boolean; + linkFrom?: () => Doc | undefined; // groupType: string; // linkDoc: Doc; // docView: DocumentView; @@ -62,9 +50,10 @@ export class LinkPopup extends React.Component<LinkPopupProps> { render() { const popupVisibility = this.props.showPopup ? "block" : "none"; + const linkDoc = this.props.linkFrom ? this.props.linkFrom : undefined; return ( <div className="linkPopup-container" style={{ display: popupVisibility }}> - <div className="linkPopup-url-container"> + {/* <div className="linkPopup-url-container"> <input autoComplete="off" type="text" value={this.linkURL} placeholder="Enter URL..." onChange={this.onLinkChange} /> <button onPointerDown={e => this.makeLinkToURL(this.linkURL, "add:right")} style={{ display: "block", margin: "10px auto", }}>Apply hyperlink</button> @@ -72,14 +61,17 @@ export class LinkPopup extends React.Component<LinkPopupProps> { <div className="divider"> <div className="line"></div> <p className="divider-text">or</p> - </div> + </div> */} <div className="linkPopup-document-search-container"> {/* <i></i> <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input" className="linkPopup-searchBox searchBox-input" /> */} - <SearchBox Document={CurrentUserUtils.MySearchPanelDoc} + <SearchBox + Document={CurrentUserUtils.MySearchPanelDoc} DataDoc={CurrentUserUtils.MySearchPanelDoc} + linkFrom={linkDoc} + linkSearch={true} fieldKey="data" dropAction="move" isSelected={returnTrue} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ebbc1138a..ee81e106a 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -2,11 +2,10 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; import { DateField } from "../../../fields/DateField"; -import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; +import { Doc, Field, FieldResult } from "../../../fields/Doc"; import { List } from "../../../fields/List"; -import { VideoField, WebField } from "../../../fields/URLField"; +import { WebField } from "../../../fields/URLField"; import { DocumentViewSharedProps } from "./DocumentView"; -import { VideoBox } from "./VideoBox"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 30b272a9a..b62a4dd56 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -54,7 +54,7 @@ export class LinkDescriptionPopup extends React.Component<{}> { }}> <input className="linkDescriptionPopup-input" onKeyPress={e => e.key === "Enter" && this.onDismiss(true)} - placeholder={"(optional) enter link label..."} + placeholder={"(Optional) Enter link description..."} onChange={(e) => this.descriptionChanged(e)}> </input> <div className="linkDescriptionPopup-btn"> @@ -65,4 +65,4 @@ export class LinkDescriptionPopup extends React.Component<{}> { </div> </div>; } -}
\ No newline at end of file +}
\ No newline at end of file diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b0b8ce75d..d1027dfd7 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -217,6 +217,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch); return undefined; }); + AnchorMenu.Instance.onMakeAnchor = this.getAnchor; /** * This function is used by the PDFmenu to create an anchor highlight and a new linked text annotation. * It also initiates a Drag/Drop interaction to place the text annotation. diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 55816ed52..75e3f81fb 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -45,6 +45,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { @observable public Highlighting: boolean = false; @observable public Status: "marquee" | "annotation" | "" = ""; + public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search + public OnClick: (e: PointerEvent) => void = unimplementedFunction; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined; @@ -65,7 +67,11 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { componentDidMount() { this._disposer = reaction(() => SelectionManager.Views(), - selected => AnchorMenu.Instance.fadeOut(true)); + selected => { + this._showLinkPopup = false; + console.log("unmount"); + AnchorMenu.Instance.fadeOut(true) + }); } pointerDown = (e: React.PointerEvent) => { @@ -145,14 +151,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { <FontAwesomeIcon icon="comment-alt" size="lg" /> </button> </Tooltip>, - - //NOTE: link popup is currently incomplete - // <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}> - // <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}> - // <FontAwesomeIcon icon="link" size="lg" /> - // </button> - // </Tooltip>, - // <LinkPopup showPopup={this._showLinkPopup} /> + //NOTE: link popup is currently in progress + <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document"}</div>}> + <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}> + <FontAwesomeIcon icon="link" size="lg" /> + </button> + </Tooltip>, + <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} /> ] : [ <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}> <button className="antimodeMenu-button" onPointerDown={this.Delete}> diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index b07879674..07186fe8d 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -7,23 +7,31 @@ import { Id } from '../../../fields/FieldSymbols'; import { createSchema, makeInterface } from '../../../fields/Schema'; import { StrCast } from '../../../fields/Types'; import { DocumentType } from "../../documents/DocumentTypes"; -import { DocumentManager } from "../../util/DocumentManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./SearchBox.scss"; +import { DocumentManager } from '../../util/DocumentManager'; +import { DocUtils } from '../../documents/Documents'; -export const searchSchema = createSchema({ Document: Doc }); +export const searchSchema = createSchema({ + Document: Doc +}); type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; const SearchBoxDocument = makeInterface(documentSchema, searchSchema); +export interface SearchBoxProps extends FieldViewProps { + linkSearch: boolean; + linkFrom?: (() => Doc | undefined) | undefined; +} + /** * This is the SearchBox component. It represents the search box input and results in * the search panel on the left side of the screen. */ @observer -export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDocument>(SearchBoxDocument) { +export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDocument>(SearchBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } public static Instance: SearchBox; @@ -100,6 +108,18 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc this._selectedResult = doc; }); + makeLink = action((linkTo: Doc) => { + console.log("[makeLink-1] got here!") + console.log(linkTo.title); + if (this.props.linkFrom){ + const linkFrom = this.props.linkFrom(); + if (linkFrom){ + console.log(linkFrom.title); + DocUtils.MakeLink({doc: linkFrom}, {doc:linkTo}); + } + } + }); + /** * @param {Doc[]} docs - docs to be searched through recursively * @param {number, Doc => void} func - function to be called on each doc @@ -275,6 +295,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc render() { var validResults = 0; + const isLinkSearch:boolean = this.props.linkSearch; + + const results = this._results.map(result => { var className = "searchBox-results-scroll-view-result"; @@ -285,7 +308,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc if (this._docTypeString == "all" || this._docTypeString == result[0].type) { validResults++; return ( - <div key={result[0][Id]} onClick={() => this.onResultClick(result[0])} className={className}> + <div key={result[0][Id]} onClick={isLinkSearch ? () => this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}> <div className="searchBox-result-title"> {result[0].title} </div> @@ -306,11 +329,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc return ( <div style={{ pointerEvents: "all" }} className="searchBox-container"> - <div className="searchBox-bar"> - <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}> + <div className="searchBox-bar" > + {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}> {this.selectOptions} - </select> - <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" ref={this._inputRef} /> + </select>} + <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined}} ref={this._inputRef} /> </div > <div className="searchBox-results-container"> <div className="searchBox-results-count"> diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss index 2ecbb536b..d04ae8a80 100644 --- a/src/client/views/topbar/TopBar.scss +++ b/src/client/views/topbar/TopBar.scss @@ -53,6 +53,7 @@ .topbar-dashboards { display: flex; flex-direction: row; + gap: 5px; } .topbar-lozenge-dashboard { |