aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/linking/LinkEditor.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/linking/LinkEditor.tsx')
-rw-r--r--src/client/views/linking/LinkEditor.tsx116
1 files changed, 100 insertions, 16 deletions
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 9d0938a6e..5b5c3cd01 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, NumListCast, 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 {
@@ -19,13 +21,15 @@ interface LinkEditorProps {
@observer
export class LinkEditor extends React.Component<LinkEditorProps> {
- @observable description = StrCast(LinkManager.currentLink?.description);
+ @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";
@@ -38,24 +42,74 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
@undoBatch
setRelationshipValue = action((value: string) => {
if (LinkManager.currentLink) {
+ const prevRelationship = LinkManager.currentLink.linkRelationship as string;
LinkManager.currentLink.linkRelationship = value;
+ Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
+ const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
+ const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes);
+ 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?.includes(value)) {
+ linkRelationshipList.push(value);
+ linkRelationshipSizes.push(1);
+ const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
+ linkColorList.push(randColor)
+ // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes
+ } else if (linkRelationshipList && value != prevRelationship) {
+ const index = linkRelationshipList.indexOf(value);
+ //increment size of new relationship size
+ if (index !== -1 && index < linkRelationshipSizes.length) {
+ const pvalue = linkRelationshipSizes[index];
+ linkRelationshipSizes[index] = (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1);
+ }
+ //decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation)
+ if (linkRelationshipList.includes(prevRelationship)) {
+ const pindex = linkRelationshipList.indexOf(prevRelationship);
+ if (pindex !== -1 && pindex < linkRelationshipSizes.length) {
+ const pvalue = linkRelationshipSizes[pindex];
+ linkRelationshipSizes[pindex] = Math.max(0, (pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue - 1));
+ }
+ }
+
+ }
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) {
- LinkManager.currentLink.description = value;
+ Doc.GetProto(LinkManager.currentLink).description = value;
this.buttonColor = "rgb(62, 133, 55)";
setTimeout(action(() => this.buttonColor = ""), 750);
return true;
}
});
- onKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
this.setDescripValue(this.description);
document.getElementById('input')?.blur();
@@ -69,16 +123,38 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
}
}
- onDown = () => this.setDescripValue(this.description);
+ 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
- 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.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 <div className="linkEditor-description">
<div className="linkEditor-description-label">Link Relationship:</div>
<div className="linkEditor-description-input">
@@ -87,11 +163,19 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
style={{ width: "100%" }}
id="input"
value={this.relationship}
- placeholder={"enter link label"}
- // color={"rgb(88, 88, 88)"}
+ autoComplete={"off"}
+ placeholder={"Enter link relationship"}
onKeyDown={this.onRelationshipKey}
onChange={this.handleRelationshipChange}
+ onFocus={this.onFocus}
+ onBlur={this.onBlur}
></input>
+ <LinkRelationshipSearch
+ results={this.getRelationshipResults()}
+ display={this.relationshipSearchVisibility}
+ handleRelationshipSearchChange={this.handleRelationshipSearchChange}
+ toggleSearch={this.toggleSearchIsActive}
+ />
</div>
<div className="linkEditor-description-add-button"
style={{ background: this.relationshipButtonColor }}
@@ -108,17 +192,17 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
<div className="linkEditor-description-editing">
<input
style={{ width: "100%" }}
+ autoComplete={"off"}
id="input"
value={this.description}
- placeholder={"enter link label"}
- // color={"rgb(88, 88, 88)"}
- onKeyDown={this.onKey}
- onChange={this.handleChange}
+ placeholder={"Enter link description"}
+ 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>;
}