From a4340dc70a52f45af18435e28d1a3f2a163d3379 Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Thu, 19 Aug 2021 21:35:26 -0400
Subject: added randomly colored link relationships

default color is black until link relationship is edited manually
---
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx         | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index a8f5e6dd2..ba67bbcef 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,14 @@ 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>;
+        const strokeColor = linkColorList[linkRelationshipList.indexOf(linkRelationship)]; //access stroke color using index of the relationship in the color list
+        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)}
-- 
cgit v1.2.3-70-g09d2


From 8f77323d6be4d4e3537d2bc2bbe815e9d578eccb Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Fri, 20 Aug 2021 00:12:42 -0400
Subject: fixed bug where link colors reset on reload

need to fix new mystery bug where any new links disappear after refreshing once but re-appear after a second refrsh
---
 src/client/util/LinkManager.ts                             | 14 +++++++-------
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx      |  3 ++-
 .../collectionFreeForm/CollectionFreeFormLinksView.tsx     |  1 +
 src/client/views/linking/LinkEditor.tsx                    | 11 ++++++-----
 src/client/views/nodes/LinkDescriptionPopup.tsx            |  4 ++--
 src/client/views/pdf/AnchorMenu.tsx                        |  4 ++--
 6 files changed, 20 insertions(+), 17 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 175de0fa5..1fc0a7593 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -99,13 +99,13 @@ export class LinkManager {
 
 
     public createLinkrelationshipLists = () => {
-        const linkRelationshipList = new List<string>();
-        const linkColorList = new List<string>();
-        Doc.UserDoc().linkRelationshipList = linkRelationshipList;
-        Doc.UserDoc().linkColorList = linkColorList;
-        console.log(Doc.UserDoc().linkRelationshipList);
-        console.log(Doc.UserDoc().linkColorList);
-        //
+        //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) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index ba67bbcef..0c44df64c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -180,7 +180,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         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>;
-        const strokeColor = linkColorList[linkRelationshipList.indexOf(linkRelationship)]; //access stroke color using index of the relationship in the color list
+        //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", stroke: strokeColor }}
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 22c3c5f56..7d6f4caf2 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -2,7 +2,7 @@ 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 { Doc, StrListCast } from "../../../fields/Doc";
 import { Cast, DateCast, StrCast } from "../../../fields/Types";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch } from "../../util/UndoManager";
@@ -41,8 +41,8 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     setRelationshipValue = action((value: string) => {
         if (LinkManager.currentLink) {
             LinkManager.currentLink.linkRelationship = value;
-            const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
-            const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+            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);
@@ -99,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"
@@ -122,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}
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/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 8d74b2ac4..75e3f81fb 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -152,12 +152,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     </button>
                 </Tooltip>,
                 //NOTE: link popup is currently in progress
-                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
+                <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}/>
+                <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}>
-- 
cgit v1.2.3-70-g09d2


From 9821be2b02306a6ba0e29e95e48c4bd4e99b93df Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Sun, 22 Aug 2021 17:20:03 -0400
Subject: added working relationship search + set

need to debug visibility toggle and refactor handlers
---
 .../CollectionFreeFormLinkView.tsx                 |  1 -
 src/client/views/linking/LinkEditor.scss           | 14 +++++
 src/client/views/linking/LinkEditor.tsx            | 61 +++++++++++++++++----
 .../views/linking/LinkRelationshipSearch.tsx       | 63 ++++++++++++++++++++++
 4 files changed, 128 insertions(+), 11 deletions(-)
 create mode 100644 src/client/views/linking/LinkRelationshipSearch.tsx

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 0c44df64c..59891b7a1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -182,7 +182,6 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         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", 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]}`} />
diff --git a/src/client/views/linking/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss
index e45a91d57..875e1672d 100644
--- a/src/client/views/linking/LinkEditor.scss
+++ b/src/client/views/linking/LinkEditor.scss
@@ -106,6 +106,20 @@
     }
 }
 
+.linkEditor-relationship-dropdown {
+    position: absolute;
+    width: 154px;
+    max-height: 90px;
+    overflow: auto;
+    background: white;
+
+    p {
+        padding: 3px;
+        cursor: pointer;
+        border: 1px solid $medium-gray;
+    }
+}
+
 .linkEditor-followingDropdown {
     padding-left: 26px;
     padding-right: 6.5px;
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 7d6f4caf2..4e104549d 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -10,6 +10,7 @@ import './LinkEditor.scss';
 import React = require("react");
 import { listSpec } from "../../../fields/Schema";
 import { List } from "../../../fields/List";
+import { LinkRelationshipSearch } from "./LinkRelationshipSearch";
 
 
 interface LinkEditorProps {
@@ -28,6 +29,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @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 description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
 
@@ -48,8 +50,6 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                 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);
@@ -57,6 +57,26 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         }
     });
 
+    /**
+     * 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) {
@@ -67,7 +87,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         }
     });
 
-    onKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+    onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Enter") {
             this.setDescripValue(this.description);
             document.getElementById('input')?.blur();
@@ -81,14 +101,27 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         }
     }
 
-    onDown = () => this.setDescripValue(this.description);
+    onDescriptionDown = () => this.setDescripValue(this.description);
     onRelationshipDown = () => this.setRelationshipValue(this.relationship);
 
+    onBlur = () => {
+        // this.toggleRelationshipResults();
+    }
+    onFocus = () => {
+        this.toggleRelationshipResults();
+    }
+
     @action
-    handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
+    handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
     @action
-    handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; }
+    handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 
+        this.relationship = e.target.value;
+    }
+    @action
+    handleRelationshipSearchChange = (result: string) => {
+        this.relationship = result;
+    }
     @computed
     get editRelationship() {
         return <div className="linkEditor-description">
@@ -103,8 +136,16 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         // color={"rgb(88, 88, 88)"}
                         onKeyDown={this.onRelationshipKey}
                         onChange={this.handleRelationshipChange}
-                        onBlur={this.onRelationshipDown}
+                        onClick={this.toggleRelationshipResults}
+                        onBlur={this.onBlur}
                     ></input>
+                    <LinkRelationshipSearch
+                        results={this.getRelationshipResults()}
+                        display={this.relationshipSearchVisibility}
+                        setRelationshipValue={this.setRelationshipValue}
+                        toggleRelationshipResults={this.toggleRelationshipResults}
+                        handleRelationshipSearchChange={this.handleRelationshipSearchChange}
+                    />
                 </div>
                 <div className="linkEditor-description-add-button"
                     style={{ background: this.relationshipButtonColor }}
@@ -125,13 +166,13 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         value={this.description}
                         placeholder={"Enter link description"}
                         // color={"rgb(88, 88, 88)"}
-                        onKeyDown={this.onKey}
-                        onChange={this.handleChange}
+                        onKeyDown={this.onDescriptionKey}
+                        onChange={this.handleDescriptionChange}
                     ></input>
                 </div>
                 <div className="linkEditor-description-add-button"
                     style={{ background: this.buttonColor }}
-                    onPointerDown={this.onDown}>Set</div>
+                    onPointerDown={this.onDescriptionDown}>Set</div>
             </div>
         </div>;
     }
diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx
new file mode 100644
index 000000000..f8afa22e1
--- /dev/null
+++ b/src/client/views/linking/LinkRelationshipSearch.tsx
@@ -0,0 +1,63 @@
+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 } from "../../../fields/Doc";
+import { LinkManager } from "../../util/LinkManager";
+import './LinkEditor.scss';
+import React = require("react");
+import { List } from "../../../fields/List";
+
+interface LinkRelationshipSearchProps {
+    results: string[] | undefined;
+    display: string;
+    //callback fns to set rel + hide dropdown upon setting
+    setRelationshipValue: (value: string) => void;
+    toggleRelationshipResults: () => void;
+    handleRelationshipSearchChange: (result: string) => void;
+}
+@observer
+export class LinkRelationshipSearch extends React.Component<LinkRelationshipSearchProps> {
+    handleResultClick = (e: React.MouseEvent) => {
+        console.log("click");
+        const relationship = (e.target as HTMLParagraphElement).textContent;
+        if (relationship) {
+            console.log("new rel " + relationship);
+            this.props.setRelationshipValue(relationship);
+            this.props.toggleRelationshipResults();
+            this.props.handleRelationshipSearchChange(relationship)
+        }
+    }
+
+    /**
+     * 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" }}></div>
+        }
+    }
+
+    render() {
+        return (
+            <div className="linkEditor-relationship-dropdown-container">
+                <div className="linkEditor-relationship-dropdown" style={{ display: this.props.display }}>
+                    {   // 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>
+
+        )
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

