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, StrListCast, Field } from "../../../fields/Doc"; import { DateCast, StrCast, Cast } from "../../../fields/Types"; import { LinkManager } from "../../util/LinkManager"; import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import { LinkRelationshipSearch } from "./LinkRelationshipSearch"; import React = require("react"); import { ToString } from "../../../fields/FieldSymbols"; interface LinkEditorProps { sourceDoc: Doc; linkDoc: Doc; showLinks: () => void; hideback?: boolean; } @observer export class LinkEditor extends React.Component { @observable description = Field.toString(LinkManager.currentLink?.description as any as Field); @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship); @observable openDropdown: boolean = false; @observable showInfo: boolean = false; @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; } @observable private buttonColor: string = ""; @observable private relationshipButtonColor: string = ""; @observable private relationshipSearchVisibility: string = "none"; @observable private searchIsActive: boolean = false; //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION"; @undoBatch deleteLink = (): void => { LinkManager.Instance.deleteLink(this.props.linkDoc); this.props.showLinks(); } @undoBatch setRelationshipValue = action((value: string) => { if (LinkManager.currentLink) { Doc.GetProto(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); } this.relationshipButtonColor = "rgb(62, 133, 55)"; setTimeout(action(() => this.relationshipButtonColor = ""), 750); return true; } }); /** * returns list of strings with possible existing relationships that contain what is currently in the input field */ @action getRelationshipResults = () => { const query = this.relationship; //current content in input box const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); if (linkRelationshipList) { return linkRelationshipList.filter(rel => rel.includes(query)); } } /** * toggles visibility of the relationship search results when the input field is focused on */ @action toggleRelationshipResults = () => { this.relationshipSearchVisibility = this.relationshipSearchVisibility === "none" ? "block" : "none"; } @undoBatch setDescripValue = action((value: string) => { if (LinkManager.currentLink) { Doc.GetProto(LinkManager.currentLink).description = value; this.buttonColor = "rgb(62, 133, 55)"; setTimeout(action(() => this.buttonColor = ""), 750); return true; } }); onDescriptionKey = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.setDescripValue(this.description); document.getElementById('input')?.blur(); } } onRelationshipKey = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.setRelationshipValue(this.relationship); document.getElementById('input')?.blur(); } } onDescriptionDown = () => this.setDescripValue(this.description); onRelationshipDown = () => this.setRelationshipValue(this.relationship); onBlur = () => { //only hide the search results if the user clicks out of the input AND not on any of the search results // i.e. if search is not active if (!this.searchIsActive) { this.toggleRelationshipResults(); } } onFocus = () => { this.toggleRelationshipResults(); } toggleSearchIsActive = () => { this.searchIsActive = !this.searchIsActive; } @action handleDescriptionChange = (e: React.ChangeEvent) => { this.description = e.target.value; } @action handleRelationshipChange = (e: React.ChangeEvent) => { this.relationship = e.target.value; } @action handleRelationshipSearchChange = (result: string) => { this.setRelationshipValue(result); this.toggleRelationshipResults(); this.relationship = result; } @computed get editRelationship() { //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS return
Link Relationship:
Set
; } @computed get editDescription() { return
Link Description:
Set
; } @action changeDropdown = () => { this.openDropdown = !this.openDropdown; } @undoBatch changeFollowBehavior = action((follow: string) => { this.openDropdown = false; Doc.GetProto(this.props.linkDoc).followLinkLocation = follow; }); @computed get followingDropdown() { return
Follow Behavior:
{StrCast(this.props.linkDoc.followLinkLocation, "default")}
this.changeFollowBehavior("default")}> Default
this.changeFollowBehavior("add:left")}> Always open in new left pane
this.changeFollowBehavior("add:right")}> Always open in new right pane
this.changeFollowBehavior("replace:right")}> Always replace right tab
this.changeFollowBehavior("replace:left")}> Always replace left tab
this.changeFollowBehavior("fullScreen")}> Always open full screen
this.changeFollowBehavior("add")}> Always open in a new tab
this.changeFollowBehavior("replace")}> Replace Tab
{this.props.linkDoc.linksToAnnotation ?
this.changeFollowBehavior("openExternal")}> Always open in external page
: null}
; } @action changeInfo = () => { this.showInfo = !this.showInfo; } render() { const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc); return !destination ? (null) : (
Return to link menu
} placement="top">

Editing Link to: { destination.proto?.title ?? destination.title ?? "untitled"}

Show more link information
} placement="top">
{this.showInfo ?
{this.props.linkDoc.author ?
Author: {this.props.linkDoc.author}
: null}
{this.props.linkDoc.creationDate ?
Creation Date: {DateCast(this.props.linkDoc.creationDate).toString()}
: null}
: null} {this.editDescription} {this.editRelationship} {this.followingDropdown}
); } }