aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/linking
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/linking')
-rw-r--r--src/client/views/linking/LinkEditor.tsx82
-rw-r--r--src/client/views/linking/LinkFollowBox.tsx48
-rw-r--r--src/client/views/linking/LinkMenu.scss85
-rw-r--r--src/client/views/linking/LinkMenu.tsx6
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx44
-rw-r--r--src/client/views/linking/LinkMenuItem.scss87
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx39
7 files changed, 192 insertions, 199 deletions
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index ecb3e9db4..bb8a8b47b 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -43,12 +43,12 @@ class GroupTypesDropdown extends React.Component<GroupTypesDropdownProps> {
@action
onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === "Enter") {
- let allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes());
- let groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
- let exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase());
+ const allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes());
+ const groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ const exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase());
if (exactFound > -1) {
- let groupType = groupOptions[exactFound];
+ const groupType = groupOptions[exactFound];
this.props.setGroupType(groupType);
this._groupType = groupType;
} else {
@@ -84,19 +84,19 @@ class GroupTypesDropdown extends React.Component<GroupTypesDropdownProps> {
renderOptions = (): JSX.Element[] | JSX.Element => {
if (this._searchTerm === "") return <></>;
- let allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes());
- let groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
- let exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
+ const allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes());
+ const groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ const exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
- let options = groupOptions.map(groupType => {
- let ref = React.createRef<HTMLDivElement>();
+ const options = groupOptions.map(groupType => {
+ const ref = React.createRef<HTMLDivElement>();
return <div key={groupType} ref={ref} className="linkEditor-option"
onClick={() => this.onOptionClick(groupType, false)}>{groupType}</div>;
});
// if search term does not already exist as a group type, give option to create new group type
if (!exactFound && this._searchTerm !== "") {
- let ref = React.createRef<HTMLDivElement>();
+ const ref = React.createRef<HTMLDivElement>();
options.push(<div key={""} ref={ref} className="linkEditor-option"
onClick={() => this.onOptionClick(this._searchTerm, true)}>Define new "{this._searchTerm}" relationship</div>);
}
@@ -138,10 +138,10 @@ class LinkMetadataEditor extends React.Component<LinkMetadataEditorProps> {
@action
setMetadataKey = (value: string): void => {
- let groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);
+ const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);
// don't allow user to create existing key
- let newIndex = groupMdKeys.findIndex(key => key.toUpperCase() === value.toUpperCase());
+ const newIndex = groupMdKeys.findIndex(key => key.toUpperCase() === value.toUpperCase());
if (newIndex > -1) {
this._keyError = true;
this._key = value;
@@ -151,7 +151,7 @@ class LinkMetadataEditor extends React.Component<LinkMetadataEditorProps> {
}
// set new value for key
- let currIndex = groupMdKeys.findIndex(key => {
+ const currIndex = groupMdKeys.findIndex(key => {
return StrCast(key).toUpperCase() === this._key.toUpperCase();
});
if (currIndex === -1) console.error("LinkMetadataEditor: key was not found");
@@ -172,9 +172,9 @@ class LinkMetadataEditor extends React.Component<LinkMetadataEditorProps> {
@action
removeMetadata = (): void => {
- let groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);
+ const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);
- let index = groupMdKeys.findIndex(key => key.toUpperCase() === this._key.toUpperCase());
+ const index = groupMdKeys.findIndex(key => key.toUpperCase() === this._key.toUpperCase());
if (index === -1) console.error("LinkMetadataEditor: key was not found");
groupMdKeys.splice(index, 1);
@@ -206,7 +206,7 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
constructor(props: LinkGroupEditorProps) {
super(props);
- let groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(StrCast(props.groupDoc.type));
+ const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(StrCast(props.groupDoc.type));
groupMdKeys.forEach(key => {
this._metadataIds.set(key, Utils.GenerateGuid());
});
@@ -226,25 +226,25 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
}
copyGroup = async (groupType: string): Promise<void> => {
- let sourceGroupDoc = this.props.groupDoc;
+ const sourceGroupDoc = this.props.groupDoc;
const sourceMdDoc = await Cast(sourceGroupDoc.metadata, Doc);
if (!sourceMdDoc) return;
- let destDoc = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+ const destDoc = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
// let destGroupList = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, destDoc);
- let keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
+ const keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
// create new metadata doc with copied kvp
- let destMdDoc = new Doc();
+ const destMdDoc = new Doc();
destMdDoc.anchor1 = StrCast(sourceMdDoc.anchor2);
destMdDoc.anchor2 = StrCast(sourceMdDoc.anchor1);
keys.forEach(key => {
- let val = sourceMdDoc[key] === undefined ? "" : StrCast(sourceMdDoc[key]);
+ const val = sourceMdDoc[key] === undefined ? "" : StrCast(sourceMdDoc[key]);
destMdDoc[key] = val;
});
// create new group doc with new metadata doc
- let destGroupDoc = new Doc();
+ const destGroupDoc = new Doc();
destGroupDoc.type = groupType;
destGroupDoc.metadata = destMdDoc;
@@ -256,7 +256,7 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
@action
addMetadata = (groupType: string): void => {
this._metadataIds.set("new key", Utils.GenerateGuid());
- let mdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
+ const mdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
// only add "new key" if there is no other key with value "new key"; prevents spamming
if (mdKeys.indexOf("new key") === -1) mdKeys.push("new key");
LinkManager.Instance.setMetadataKeysForGroup(groupType, mdKeys);
@@ -268,17 +268,17 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
}
renderMetadata = (): JSX.Element[] => {
- let metadata: Array<JSX.Element> = [];
- let groupDoc = this.props.groupDoc;
+ const metadata: Array<JSX.Element> = [];
+ const groupDoc = this.props.groupDoc;
const mdDoc = FieldValue(Cast(groupDoc.metadata, Doc));
if (!mdDoc) {
return [];
}
- let groupType = StrCast(groupDoc.type);
- let groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
+ const groupType = StrCast(groupDoc.type);
+ const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
groupMdKeys.forEach((key) => {
- let val = StrCast(mdDoc[key]);
+ const val = StrCast(mdDoc[key]);
metadata.push(
<LinkMetadataEditor key={"mded-" + this._metadataIds.get(key)} id={this._metadataIds.get(key)!} groupType={groupType} mdDoc={mdDoc} mdKey={key} mdValue={val} changeMdIdKey={this.changeMdIdKey} />
);
@@ -287,18 +287,18 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
}
viewGroupAsTable = (groupType: string): JSX.Element => {
- let keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
- let index = keys.indexOf("");
+ const keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
+ const index = keys.indexOf("");
if (index > -1) keys.splice(index, 1);
- let cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c, "#f1efeb"));
- let docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType);
- let createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" }));
- let ref = React.createRef<HTMLDivElement>();
+ const cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c, "#f1efeb"));
+ const docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType);
+ const createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" }));
+ const ref = React.createRef<HTMLDivElement>();
return <div ref={ref}><button className="linkEditor-button" onPointerDown={SetupDrag(ref, createTable)} title="Drag to view relationship table"><FontAwesomeIcon icon="table" size="sm" /></button></div>;
}
render() {
- let groupType = StrCast(this.props.groupDoc.type);
+ const groupType = StrCast(this.props.groupDoc.type);
// if ((groupType && LinkManager.Instance.getMetadataKeysInGroup(groupType).length > 0) || groupType === "") {
let buttons;
if (groupType === "") {
@@ -356,15 +356,15 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
@action
addGroup = (): void => {
// create new metadata document for group
- let mdDoc = new Doc();
+ const mdDoc = new Doc();
mdDoc.anchor1 = this.props.sourceDoc.title;
- let opp = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+ const opp = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
if (opp) {
mdDoc.anchor2 = opp.title;
}
// create new group document
- let groupDoc = new Doc();
+ const groupDoc = new Doc();
groupDoc.type = "";
groupDoc.metadata = mdDoc;
@@ -372,10 +372,10 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
}
render() {
- let destination = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+ const destination = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
- let groupList = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, this.props.sourceDoc);
- let groups = groupList.map(groupDoc => {
+ const groupList = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, this.props.sourceDoc);
+ const groups = groupList.map(groupDoc => {
return <LinkGroupEditor key={"gred-" + StrCast(groupDoc.type)} linkDoc={this.props.linkDoc} sourceDoc={this.props.sourceDoc} groupDoc={groupDoc} />;
});
diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx
index efe2c7f2a..29e167ff7 100644
--- a/src/client/views/linking/LinkFollowBox.tsx
+++ b/src/client/views/linking/LinkFollowBox.tsx
@@ -68,14 +68,14 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
this._contextDisposer = reaction(
() => this.selectedContextString,
async () => {
- let ref = await DocServer.GetRefField(this.selectedContextString);
+ const ref = await DocServer.GetRefField(this.selectedContextString);
runInAction(() => {
if (ref instanceof Doc) {
this.selectedContext = ref;
}
});
if (this.selectedContext instanceof Doc) {
- let aliases = await SearchUtil.GetViewsOfDocument(this.selectedContext);
+ const aliases = await SearchUtil.GetViewsOfDocument(this.selectedContext);
runInAction(() => { this.selectedContextAliases = aliases; });
}
}
@@ -90,8 +90,8 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
if (LinkFollowBox.destinationDoc && this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
runInAction(() => this.canPan = false);
if (this.sourceView.props.ContainingCollectionDoc.viewType === CollectionViewType.Freeform) {
- let docs = Cast(this.sourceView.props.ContainingCollectionDoc.data, listSpec(Doc), []);
- let aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(LinkFollowBox.destinationDoc));
+ const docs = Cast(this.sourceView.props.ContainingCollectionDoc.data, listSpec(Doc), []);
+ const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(LinkFollowBox.destinationDoc));
aliases.forEach(alias => {
if (docs.filter(doc => doc === alias).length > 0) {
@@ -118,8 +118,8 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
async fetchDocuments() {
if (LinkFollowBox.destinationDoc) {
- let dest: Doc = LinkFollowBox.destinationDoc;
- let aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(dest));
+ const dest: Doc = LinkFollowBox.destinationDoc;
+ const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(dest));
const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${dest[Id]}"` });
const map: Map<Doc, Doc> = new Map;
const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs)));
@@ -128,7 +128,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
runInAction(async () => {
this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: dest }));
this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target }));
- let tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.anchor2Context, Doc)) as Doc;
+ const tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.anchor2Context, Doc)) as Doc;
runInAction(() => tcontext && this._docs.splice(0, 0, { col: tcontext, target: dest }));
});
}
@@ -157,7 +157,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@undoBatch
openFullScreen = () => {
if (LinkFollowBox.destinationDoc) {
- let view = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc);
+ const view = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc);
view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view);
}
}
@@ -171,7 +171,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
options.context.panX = newPanX;
options.context.panY = newPanY;
}
- let view = DocumentManager.Instance.getDocumentView(options.context);
+ const view = DocumentManager.Instance.getDocumentView(options.context);
view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view);
this.highlightDoc();
}
@@ -211,7 +211,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@undoBatch
openLinkRight = () => {
if (LinkFollowBox.destinationDoc) {
- let alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
+ const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
(LinkFollowBox._addDocTab || this.props.addDocTab)(alias, undefined, "onRight");
this.highlightDoc();
SelectionManager.DeselectAll();
@@ -222,7 +222,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@undoBatch
jumpToLink = async (options: { shouldZoom: boolean }) => {
if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) {
- let focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
+ const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
//let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation));
DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined);
@@ -232,7 +232,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@undoBatch
openLinkTab = () => {
if (LinkFollowBox.destinationDoc) {
- let fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
+ const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
// this.prosp.addDocTab is empty -- use the link source's addDocTab
(LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, undefined, "inTab");
@@ -264,14 +264,14 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
if (LinkFollowBox.destinationDoc && LinkFollowBox.sourceDoc) {
if (this.sourceView && this.sourceView.props.addDocument) {
- let destViews = DocumentManager.Instance.getDocumentViews(LinkFollowBox.destinationDoc);
+ const destViews = DocumentManager.Instance.getDocumentViews(LinkFollowBox.destinationDoc);
if (!destViews.find(dv => dv.props.ContainingCollectionView === this.sourceView!.props.ContainingCollectionView)) {
- let alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
- let y = NumCast(LinkFollowBox.sourceDoc.y);
- let x = NumCast(LinkFollowBox.sourceDoc.x);
+ const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
+ const y = NumCast(LinkFollowBox.sourceDoc.y);
+ const x = NumCast(LinkFollowBox.sourceDoc.x);
- let width = NumCast(LinkFollowBox.sourceDoc.width);
- let height = NumCast(LinkFollowBox.sourceDoc.height);
+ const width = NumCast(LinkFollowBox.sourceDoc.width);
+ const height = NumCast(LinkFollowBox.sourceDoc.height);
alias.x = x + width + 30;
alias.y = y;
@@ -301,8 +301,8 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
this.selectedContext = LinkFollowBox.destinationDoc;
}
if (this.selectedOption === "") this.selectedOption = FollowOptions.NOZOOM;
- let shouldZoom: boolean = this.selectedOption === FollowOptions.NOZOOM ? false : true;
- let notOpenInContext: boolean = this.selectedContextString === "self" || this.selectedContextString === LinkFollowBox.destinationDoc[Id];
+ const shouldZoom: boolean = this.selectedOption === FollowOptions.NOZOOM ? false : true;
+ const notOpenInContext: boolean = this.selectedContextString === "self" || this.selectedContextString === LinkFollowBox.destinationDoc[Id];
if (this.selectedMode === FollowModes.INPLACE) {
if (shouldZoom !== undefined) this.openLinkInPlace({ shouldZoom: shouldZoom });
@@ -328,7 +328,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@action
handleModeChange = (e: React.ChangeEvent) => {
- let target = e.target as HTMLInputElement;
+ const target = e.target as HTMLInputElement;
this.selectedMode = target.value;
this.selectedContext = undefined;
this.selectedContextString = "";
@@ -345,13 +345,13 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@action
handleOptionChange = (e: React.ChangeEvent) => {
- let target = e.target as HTMLInputElement;
+ const target = e.target as HTMLInputElement;
this.selectedOption = target.value;
}
@action
handleContextChange = (e: React.ChangeEvent) => {
- let target = e.target as HTMLInputElement;
+ const target = e.target as HTMLInputElement;
this.selectedContextString = target.value;
// selectedContext is updated in reaction
this.selectedOption = "";
@@ -360,7 +360,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
@computed
get canOpenInPlace() {
if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) {
- let colDoc = this.sourceView.props.ContainingCollectionDoc;
+ const colDoc = this.sourceView.props.ContainingCollectionDoc;
if (colDoc.viewType && colDoc.viewType === CollectionViewType.Freeform) return true;
}
return false;
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss
index a4018bd2d..7dee22f66 100644
--- a/src/client/views/linking/LinkMenu.scss
+++ b/src/client/views/linking/LinkMenu.scss
@@ -48,90 +48,5 @@
}
}
-.linkMenu-item {
- // border-top: 0.5px solid $main-accent;
- position: relative;
- display: flex;
- font-size: 12px;
-
-
- .link-name {
- position: relative;
-
- p {
- padding: 4px 6px;
- line-height: 12px;
- border-radius: 5px;
- overflow-wrap: break-word;
- }
- }
-
- .linkMenu-item-content {
- width: 100%;
- }
-
- .link-metadata {
- padding: 0 10px 0 16px;
- margin-bottom: 4px;
- color: $main-accent;
- font-style: italic;
- font-size: 10.5px;
- }
-
- &:hover {
- .linkMenu-item-buttons {
- display: flex;
- }
- .linkMenu-item-content {
- &.expand-two p {
- width: calc(100% - 52px);
- background-color: lightgray;
- }
- &.expand-three p {
- width: calc(100% - 84px);
- background-color: lightgray;
- }
- }
- }
-}
-
-.linkMenu-item-buttons {
- display: none;
- position: absolute;
- top: 50%;
- right: 0;
- transform: translateY(-50%);
-
- .button {
- width: 20px;
- height: 20px;
- margin: 0;
- margin-right: 6px;
- border-radius: 50%;
- cursor: pointer;
- pointer-events: auto;
- background-color: $dark-color;
- color: $light-color;
- font-size: 65%;
- transition: transform 0.2s;
- text-align: center;
- position: relative;
-
- .fa-icon {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
-
- &:last-child {
- margin-right: 0;
- }
- &:hover {
- background: $main-accent;
- }
- }
-}
-
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 27af873b5..52628ba4c 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -34,7 +34,7 @@ export class LinkMenu extends React.Component<Props> {
}
renderAllGroups = (groups: Map<string, Array<Doc>>): Array<JSX.Element> => {
- let linkItems: Array<JSX.Element> = [];
+ const linkItems: Array<JSX.Element> = [];
groups.forEach((group, groupType) => {
linkItems.push(
<LinkMenuGroup
@@ -55,8 +55,8 @@ export class LinkMenu extends React.Component<Props> {
}
render() {
- let sourceDoc = this.props.docView.props.Document;
- let groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc);
+ const sourceDoc = this.props.docView.props.Document;
+ const groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc);
if (this._editingLink === undefined) {
return (
<div className="linkMenu">
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 1891919ce..ace9a9e4c 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -4,11 +4,9 @@ import { observer } from "mobx-react";
import { Doc } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { emptyFunction } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DragManager, SetupDrag } from "../../util/DragManager";
import { LinkManager } from "../../util/LinkManager";
-import { UndoManager } from "../../util/UndoManager";
import { DocumentView } from "../nodes/DocumentView";
import './LinkMenu.scss';
import { LinkMenuItem } from "./LinkMenuItem";
@@ -21,7 +19,6 @@ interface LinkMenuGroupProps {
showEditor: (linkDoc: Doc) => void;
addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
docView: DocumentView;
-
}
@observer
@@ -44,44 +41,31 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
e.stopPropagation();
}
-
onLinkButtonMoved = async (e: PointerEvent) => {
- UndoManager.RunInBatch(() => {
- if (this._drag.current !== null && (e.movementX > 1 || e.movementY > 1)) {
- document.removeEventListener("pointermove", this.onLinkButtonMoved);
- document.removeEventListener("pointerup", this.onLinkButtonUp);
+ if (this._drag.current && (e.movementX > 1 || e.movementY > 1)) {
+ document.removeEventListener("pointermove", this.onLinkButtonMoved);
+ document.removeEventListener("pointerup", this.onLinkButtonUp);
- let draggedDocs = this.props.group.map(linkDoc => {
- let opp = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
- if (opp) return opp;
- }) as Doc[];
- let dragData = new DragManager.DocumentDragData(draggedDocs);
-
- DragManager.StartLinkedDocumentDrag([this._drag.current], dragData, e.x, e.y, {
- handlers: {
- dragComplete: action(emptyFunction),
- },
- hideSource: false
- });
- }
- }, "drag links");
+ const targets = this.props.group.map(l => LinkManager.Instance.getOppositeAnchor(l, this.props.sourceDoc)).filter(d => d) as Doc[];
+ DragManager.StartLinkTargetsDrag(this._drag.current, e.x, e.y, this.props.sourceDoc, targets);
+ }
e.stopPropagation();
}
viewGroupAsTable = (groupType: string): JSX.Element => {
- let keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
- let index = keys.indexOf("");
+ const keys = LinkManager.Instance.getMetadataKeysInGroup(groupType);
+ const index = keys.indexOf("");
if (index > -1) keys.splice(index, 1);
- let cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c, "#f1efeb"));
- let docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType);
- let createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" }));
- let ref = React.createRef<HTMLDivElement>();
+ const cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c, "#f1efeb"));
+ const docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType);
+ const createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" }));
+ const ref = React.createRef<HTMLDivElement>();
return <div ref={ref}><button className="linkEditor-button linkEditor-tableButton" onPointerDown={SetupDrag(ref, createTable)} title="Drag to view relationship table"><FontAwesomeIcon icon="table" size="sm" /></button></div>;
}
render() {
- let groupItems = this.props.group.map(linkDoc => {
- let destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
+ const groupItems = this.props.group.map(linkDoc => {
+ const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
if (destination && this.props.sourceDoc) {
return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]}
groupType={this.props.groupType}
diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss
new file mode 100644
index 000000000..fd0954f65
--- /dev/null
+++ b/src/client/views/linking/LinkMenuItem.scss
@@ -0,0 +1,87 @@
+@import "../globalCssVariables";
+
+.linkMenu-item {
+ // border-top: 0.5px solid $main-accent;
+ position: relative;
+ display: flex;
+ font-size: 12px;
+
+
+ .linkMenu-name {
+ position: relative;
+
+ p {
+ padding: 4px 6px;
+ line-height: 12px;
+ border-radius: 5px;
+ overflow-wrap: break-word;
+ user-select: none;
+ }
+ }
+
+ .linkMenu-item-content {
+ width: 100%;
+ }
+
+ .link-metadata {
+ padding: 0 10px 0 16px;
+ margin-bottom: 4px;
+ color: $main-accent;
+ font-style: italic;
+ font-size: 10.5px;
+ }
+
+ &:hover {
+ .linkMenu-item-buttons {
+ display: flex;
+ }
+ .linkMenu-item-content {
+ &.expand-two p {
+ width: calc(100% - 52px);
+ background-color: lightgray;
+ }
+ &.expand-three p {
+ width: calc(100% - 84px);
+ background-color: lightgray;
+ }
+ }
+ }
+}
+
+.linkMenu-item-buttons {
+ display: none;
+ position: absolute;
+ top: 50%;
+ right: 0;
+ transform: translateY(-50%);
+
+ .button {
+ width: 20px;
+ height: 20px;
+ margin: 0;
+ margin-right: 6px;
+ border-radius: 50%;
+ cursor: pointer;
+ pointer-events: auto;
+ background-color: $dark-color;
+ color: $light-color;
+ font-size: 65%;
+ transition: transform 0.2s;
+ text-align: center;
+ position: relative;
+
+ .fa-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ &:hover {
+ background: $main-accent;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index a6ee9c2c6..b7d27ee30 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -5,12 +5,11 @@ import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import { Doc } from '../../../new_fields/Doc';
import { Cast, StrCast } from '../../../new_fields/Types';
-import { DragLinkAsDocument } from '../../util/DragManager';
+import { DragManager } from '../../util/DragManager';
import { LinkManager } from '../../util/LinkManager';
import { ContextMenu } from '../ContextMenu';
-import { MainView } from '../MainView';
import { LinkFollowBox } from './LinkFollowBox';
-import './LinkMenu.scss';
+import './LinkMenuItem.scss';
import React = require("react");
library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp);
@@ -27,6 +26,9 @@ interface LinkMenuItemProps {
@observer
export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
private _drag = React.createRef<HTMLDivElement>();
+ private _downX = 0;
+ private _downY = 0;
+ private _eleClone: any;
@observable private _showMore: boolean = false;
@action toggleShowMore() { this._showMore = !this._showMore; }
@@ -37,15 +39,15 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
}
renderMetadata = (): JSX.Element => {
- let groups = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, this.props.sourceDoc);
- let index = groups.findIndex(groupDoc => StrCast(groupDoc.type).toUpperCase() === this.props.groupType.toUpperCase());
- let groupDoc = index > -1 ? groups[index] : undefined;
+ const groups = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, this.props.sourceDoc);
+ const index = groups.findIndex(groupDoc => StrCast(groupDoc.type).toUpperCase() === this.props.groupType.toUpperCase());
+ const groupDoc = index > -1 ? groups[index] : undefined;
let mdRows: Array<JSX.Element> = [];
if (groupDoc) {
- let mdDoc = Cast(groupDoc.metadata, Doc, null);
+ const mdDoc = Cast(groupDoc.metadata, Doc, null);
if (mdDoc) {
- let keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
+ const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
mdRows = keys.map(key => {
return (<div key={key} className="link-metadata-row"><b>{key}</b>: {StrCast(mdDoc[key])}</div>);
});
@@ -56,6 +58,9 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
}
onLinkButtonDown = (e: React.PointerEvent): void => {
+ this._downX = e.clientX;
+ this._downY = e.clientY;
+ this._eleClone = this._drag.current!.cloneNode(true);
e.stopPropagation();
document.removeEventListener("pointermove", this.onLinkButtonMoved);
document.addEventListener("pointermove", this.onLinkButtonMoved);
@@ -76,11 +81,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
}
onLinkButtonMoved = async (e: PointerEvent) => {
- if (this._drag.current !== null && (e.movementX > 1 || e.movementY > 1)) {
+ if (this._drag.current !== null && Math.abs((e.clientX - this._downX) * (e.clientX - this._downX) + (e.clientY - this._downY) * (e.clientY - this._downY)) > 5) {
document.removeEventListener("pointermove", this.onLinkButtonMoved);
document.removeEventListener("pointerup", this.onLinkButtonUp);
- DragLinkAsDocument(this._drag.current, e.x, e.y, this.props.linkDoc, this.props.sourceDoc);
+ this._eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`;
+ DragManager.StartLinkTargetsDrag(this._eleClone, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]);
}
e.stopPropagation();
}
@@ -110,20 +116,21 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
}
render() {
-
- let keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
- let canExpand = keys ? keys.length > 0 : false;
+ const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
+ const canExpand = keys ? keys.length > 0 : false;
return (
<div className="linkMenu-item">
<div className={canExpand ? "linkMenu-item-content expand-three" : "linkMenu-item-content expand-two"}>
- <div className="link-name">
- <p ref={this._drag} onPointerDown={this.onLinkButtonDown}>{StrCast(this.props.destinationDoc.title)}</p>
+ <div ref={this._drag} className="linkMenu-name" title="drag to view target. click to customize." onPointerDown={this.onLinkButtonDown}>
+ <p >{StrCast(this.props.destinationDoc.title)}</p>
<div className="linkMenu-item-buttons">
{canExpand ? <div title="Show more" className="button" onPointerDown={() => this.toggleShowMore()}>
<FontAwesomeIcon className="fa-icon" icon={this._showMore ? "chevron-up" : "chevron-down"} size="sm" /></div> : <></>}
<div title="Edit link" className="button" onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
- <div title="Follow link" className="button" onClick={this.followDefault} onContextMenu={this.onContextMenu}><FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div>
+ <div title="Follow link" className="button" onClick={this.followDefault} onContextMenu={this.onContextMenu}>
+ <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" />
+ </div>
</div>
</div>
{this._showMore ? this.renderMetadata() : <></>}