aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts40
-rw-r--r--src/client/util/DocumentManager.ts5
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/LinkManager.ts84
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/LinkEditor.tsx103
-rw-r--r--src/client/views/nodes/LinkManager.tsx51
-rw-r--r--src/client/views/nodes/LinkMenu.tsx33
9 files changed, 227 insertions, 95 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 87b831663..5ec19f987 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -35,7 +35,7 @@ import { dropActionType } from "../util/DragManager";
import { DateField } from "../../new_fields/DateField";
import { UndoManager } from "../util/UndoManager";
import { RouteStore } from "../../server/RouteStore";
-import { LinkManager } from "../views/nodes/LinkManager";
+import { LinkManager } from "../util/LinkManager";
var requestImageSize = require('request-image-size');
var path = require('path');
@@ -69,21 +69,45 @@ export interface DocumentOptions {
}
const delegateKeys = ["x", "y", "width", "height", "panX", "panY"];
+// export interface LinkData {
+// anchor1: Doc;
+// anchor1Page: number;
+// anchor1Tags: Array<{ tag: string, name: string, description: string }>;
+// anchor2: Doc;
+// anchor2Page: number;
+// anchor2Tags: Array<{ tag: string, name: string, description: string }>;
+// }
+
+// export interface TagData {
+// tag: string;
+// name: string;
+// description: string;
+// }
+
export namespace DocUtils {
export function MakeLink(source: Doc, target: Doc) {
// let protoSrc = source.proto ? source.proto : source;
// let protoTarg = target.proto ? target.proto : target;
UndoManager.RunInBatch(() => {
+ let groupDoc = Docs.TextDocument();
+ groupDoc.proto!.type = "*";
+
let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 });
//let linkDoc = new Doc;
- linkDoc.proto!.title = source.proto!.title + " and " + target.proto!.title;
- linkDoc.proto!.linkDescription = "";
- linkDoc.proto!.linkTags = "Default";
+ // linkDoc.proto!.title = source.proto!.title + " and " + target.proto!.title;
+ // linkDoc.proto!.linkDescription = "";
+ linkDoc.proto!.anchor1 = source;
+ linkDoc.proto!.anchor1Page = source.curPage;
+ linkDoc.proto!.anchor1Groups = new List<Doc>([groupDoc]);
+
+ linkDoc.proto!.anchor2 = target;
+ linkDoc.proto!.anchor2Page = target.curPage;
+ linkDoc.proto!.anchor2Groups = new List<Doc>([groupDoc]);
- linkDoc.proto!.linkedTo = target;
- linkDoc.proto!.linkedToPage = target.curPage;
- linkDoc.proto!.linkedFrom = source;
- linkDoc.proto!.linkedFromPage = source.curPage;
+ // linkDoc.proto!.linkedTo = target;
+ // linkDoc.proto!.linkedToPage = target.curPage;
+ // linkDoc.proto!.linkedFrom = source;
+ // linkDoc.proto!.linkedFromPage = source.curPage;
// let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc));
// if (!linkedFrom) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 712529745..52f0fe3f6 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -9,7 +9,7 @@ import { CollectionView } from '../views/collections/CollectionView';
import { CollectionPDFView } from '../views/collections/CollectionPDFView';
import { CollectionVideoView } from '../views/collections/CollectionVideoView';
import { Id } from '../../new_fields/FieldSymbols';
-import { LinkManager } from '../views/nodes/LinkManager';
+import { LinkManager } from './LinkManager';
export class DocumentManager {
@@ -91,7 +91,8 @@ export class DocumentManager {
if (linksList && linksList.length) {
pairs.push(...linksList.reduce((pairs, link) => {
if (link) {
- let destination = (link["linkedTo"] === dv.props.Document) ? link["linkedFrom"] : link["linkedTo"];
+ // let destination = (link["linkedTo"] === dv.props.Document) ? link["linkedFrom"] : link["linkedTo"];
+ let destination = LinkManager.Instance.findOppositeAnchor(link, dv.props.Document);
let linkToDoc = FieldValue(Cast(destination, Doc));
// let linkToDoc = FieldValue(Cast(link.linkedTo, Doc));
if (linkToDoc) {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7854cc080..809368aff 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -4,7 +4,7 @@ import { Cast } from "../../new_fields/Types";
import { emptyFunction } from "../../Utils";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import * as globalCssVariables from "../views/globalCssVariables.scss";
-import { LinkManager } from "../views/nodes/LinkManager";
+import { LinkManager } from "./LinkManager";
export type dropActionType = "alias" | "copy" | undefined;
export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () => Doc | Promise<Doc>, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType) {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
new file mode 100644
index 000000000..a6d649395
--- /dev/null
+++ b/src/client/util/LinkManager.ts
@@ -0,0 +1,84 @@
+import { observable, computed, action } from "mobx";
+import React = require("react");
+import { SelectionManager } from "./SelectionManager";
+import { observer } from "mobx-react";
+import { props } from "bluebird";
+import { DocumentView } from "../views/nodes/DocumentView";
+import { link } from "fs";
+import { StrCast, Cast } from "../../new_fields/Types";
+import { Doc } from "../../new_fields/Doc";
+import { listSpec } from "../../new_fields/Schema";
+import { List } from "../../new_fields/List";
+
+
+export class LinkManager {
+ private static _instance: LinkManager;
+ public static get Instance(): LinkManager {
+ return this._instance || (this._instance = new this());
+ }
+ private constructor() {
+ }
+
+ @observable
+ public allLinks: Array<Doc> = [];
+
+ public findAllRelatedLinks(source: Doc): Array<Doc> {
+ let related = LinkManager.Instance.allLinks.filter(
+ link => Doc.AreProtosEqual(source, Cast(link.anchor1, Doc, new Doc)) || Doc.AreProtosEqual(source, Cast(link.anchor2, Doc, new Doc)));
+ return related;
+ }
+
+ public findRelatedGroupedLinks(source: Doc): Map<string, Array<Doc>> {
+ let related = this.findAllRelatedLinks(source);
+
+ let categories = new Map();
+ related.forEach(link => {
+ // get groups of given doc
+ let groups = (Doc.AreProtosEqual(source, Cast(link.anchor1, Doc, new Doc))) ? Cast(link.anchor1Groups, listSpec(Doc), []) : Cast(link.anchor2Groups, listSpec(Doc), []);
+ if (groups) {
+ if (groups.length > 0) {
+ groups.forEach(groupDoc => {
+ if (groupDoc instanceof Doc) {
+ let groupType = StrCast(groupDoc.proto!.type);
+ let group = categories.get(groupType); // TODO: clean this up lol
+ if (group) group.push(link);
+ else group = [link];
+ categories.set(groupType, group);
+ } else {
+ // promise doc
+ }
+
+ })
+ }
+ else {
+ // if link is in no groups then put it in default group
+ let group = categories.get("*");
+ if (group) group.push(link);
+ else group = [link];
+ categories.set("*", group);
+ }
+ }
+
+
+ // let anchor = this.findOppositeAnchor(link, source);
+ // let group = categories.get(link.linkTags);
+ // if (group) group.push(link);
+ // else group = [link];
+ // categories.set(link.linkTags, group);
+ })
+ return categories;
+ }
+
+ public findOppositeAnchor(link: Doc, source: Doc): Doc {
+ if (Doc.AreProtosEqual(source, Cast(link.anchor1, Doc, new Doc))) {
+ return Cast(link.anchor2, Doc, new Doc);
+ } else {
+ return Cast(link.anchor1, Doc, new Doc);
+ }
+ }
+
+ // public findAnchorTags(link: Doc, source: Doc): Doc[] {
+ // if (source)
+ // }
+
+} \ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2aae9bce6..eb45c770e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -28,7 +28,7 @@ import { CollectionView } from "./collections/CollectionView";
import { DocumentManager } from "../util/DocumentManager";
import { FormattedTextBox } from "./nodes/FormattedTextBox";
import { FieldView } from "./nodes/FieldView";
-import { LinkManager } from "./nodes/LinkManager";
+import { LinkManager } from "../util/LinkManager";
library.add(faLink);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0baa061ab..fc6974e6c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -52,7 +52,7 @@ library.add(faDesktop);
const linkSchema = createSchema({
title: "string",
linkDescription: "string",
- linkTags: listSpec("string"),
+ linkTags: "string",
linkedTo: Doc,
linkedFrom: Doc
});
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
index 71a423338..2ab8c3460 100644
--- a/src/client/views/nodes/LinkEditor.tsx
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -6,52 +6,115 @@ import './LinkEditor.scss';
import { props } from "bluebird";
import { DocumentView } from "./DocumentView";
import { link } from "fs";
-import { StrCast } from "../../../new_fields/Types";
+import { StrCast, Cast } from "../../../new_fields/Types";
import { Doc } from "../../../new_fields/Doc";
+import { List } from "../../../new_fields/List";
+import { listSpec } from "../../../new_fields/Schema";
+import { LinkManager } from "../../util/LinkManager";
interface Props {
+ sourceDoc: Doc;
linkDoc: Doc;
+ groups: Map<number, Doc>;
showLinks: () => void;
}
@observer
export class LinkEditor extends React.Component<Props> {
- @observable private _nameInput: string = StrCast(this.props.linkDoc.title);
- @observable private _descriptionInput: string = StrCast(this.props.linkDoc.linkDescription);
+ // @observable private _title: string = StrCast(this.props.linkDoc.title);
+ // @observable private _description: string = StrCast(this.props.linkDoc.linkDescription);
+ // @observable private _tags: Array<string> = Cast(this.props.linkDoc.linkTags, List);
+ // @action
+ // onTitleChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+ // this._title = e.target.value;
+ // }
- onSaveButtonPressed = (e: React.PointerEvent): void => {
- e.stopPropagation();
+ // @action
+ // onDescriptionChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+ // this._description = e.target.value;
+ // }
+
+ // renderTags() {
+ // return this._tags.map(tag => {
+ // if (tag === "") {
+ // return <input type="text" placeholder="Tag"></input>;
+ // } else {
+ // return <input type="text" value={tag}></input>;
+ // }
+ // })
+ // }
+
+ // addTag = (): void => {
+ // this._tags.push("");
+ // }
+ @action
+ editGroup(groupId: number, value: string) {
let linkDoc = this.props.linkDoc.proto ? this.props.linkDoc.proto : this.props.linkDoc;
- linkDoc.title = this._nameInput;
- linkDoc.linkDescription = this._descriptionInput;
+ let groupDoc = this.props.groups.get(groupId);
+ if (groupDoc) {
+ groupDoc.proto!.type = value;
+ if (Doc.AreProtosEqual(this.props.sourceDoc, Cast(linkDoc.anchor1, Doc, new Doc))) {
+ // let groups = Cast(linkDoc.anchor1Groups, listSpec(Doc), []);
+ // groups.push(groupDoc);
+ linkDoc.anchor1Groups = new List<Doc>([groupDoc]);
+
+ } else {
+ linkDoc.anchor2Groups = new List<Doc>([groupDoc]);
+ }
+ }
- this.props.showLinks();
}
+ renderGroup(groupId: number, groupDoc: Doc) {
+ return (
+ <div>
+ <p>type:</p>
+ <input type="text" value={StrCast(groupDoc.proto!.type)} onChange={e => this.editGroup(groupId, e.target.value)}></input>
+ </div>
+ )
+ }
+ renderGroups() {
+ let groups: Array<JSX.Element> = [];
+ this.props.groups.forEach((groupDoc, groupId) => {
+ groups.push(
+ <div>
+ {this.renderGroup(groupId, groupDoc)}
+ </div>
+ )
+ });
+ return groups;
+ }
+
+ onSaveButtonPressed = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+
+ // let linkDoc = this.props.linkDoc.proto ? this.props.linkDoc.proto : this.props.linkDoc;
+ // // linkDoc.title = this._title;
+ // // linkDoc.linkDescription = this._description;
+
+ this.props.showLinks();
+ }
render() {
+ let destination = LinkManager.Instance.findOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
return (
<div className="edit-container">
- <input onChange={this.onNameChanged} className="name-input" type="text" value={this._nameInput} placeholder="Name . . ."></input>
- <textarea onChange={this.onDescriptionChanged} className="description-input" value={this._descriptionInput} placeholder="Description . . ."></textarea>
+ <p>linked to: {destination.proto!.title}</p>
+ <b>Groups:</b>
+ {this.renderGroups()}
+
+ {/* <input onChange={this.onTitleChanged} className="name-input" type="text" value={this._title} placeholder="Name . . ."></input>
+ <textarea onChange={this.onDescriptionChanged} className="description-input" value={this._description} placeholder="Description . . ."></textarea> */}
+ {/* {this.renderTags()}
+ <button onClick={this.addTag}>+</button> */}
<div className="save-button" onPointerDown={this.onSaveButtonPressed}>SAVE</div>
</div>
);
}
-
- @action
- onNameChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._nameInput = e.target.value;
- }
-
- @action
- onDescriptionChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
- this._descriptionInput = e.target.value;
- }
} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkManager.tsx b/src/client/views/nodes/LinkManager.tsx
deleted file mode 100644
index 1064eaa22..000000000
--- a/src/client/views/nodes/LinkManager.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { observable, computed, action } from "mobx";
-import React = require("react");
-import { SelectionManager } from "../../util/SelectionManager";
-import { observer } from "mobx-react";
-import './LinkEditor.scss';
-import { props } from "bluebird";
-import { DocumentView } from "./DocumentView";
-import { link } from "fs";
-import { StrCast, Cast } from "../../../new_fields/Types";
-import { Doc } from "../../../new_fields/Doc";
-import { listSpec } from "../../../new_fields/Schema";
-
-
-export class LinkManager {
- private static _instance: LinkManager;
- public static get Instance(): LinkManager {
- return this._instance || (this._instance = new this());
- }
- private constructor() {
- }
-
- @observable
- public allLinks: Array<Doc> = [];
-
- public findAllRelatedLinks(source: Doc): Array<Doc> {
- let related = LinkManager.Instance.allLinks.filter(
- link => Doc.AreProtosEqual(source, Cast(link.linkedFrom, Doc, new Doc)) || Doc.AreProtosEqual(source, Cast(link.linkedTo, Doc, new Doc)));
- return related;
- }
-
- public findRelatedGroupedLinks(source: Doc): Map<string, Array<Doc>> {
- let related = this.findAllRelatedLinks(source);
- let categories = new Map();
- related.forEach(link => {
- let group = categories.get(link.linkTags);
- if (group) group.push(link);
- else group = [link];
- categories.set(link.linkTags, group);
- })
- return categories;
- }
-
- public findOppositeAnchor(link: Doc, source: Doc): Doc {
- if (Doc.AreProtosEqual(source, Cast(link.linkedFrom, Doc, new Doc))) {
- return Cast(link.linkedTo, Doc, new Doc);
- } else {
- return Cast(link.linkedFrom, Doc, new Doc);
- }
- }
-
-} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 6dc5623d1..affe35e2a 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -8,7 +8,9 @@ import React = require("react");
import { Doc, DocListCast } from "../../../new_fields/Doc";
import { Cast, FieldValue, StrCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
-import { LinkManager } from "./LinkManager";
+import { LinkManager } from "../../util/LinkManager";
+import { number } from "prop-types";
+import { listSpec } from "../../../new_fields/Schema";
interface Props {
docView: DocumentView;
@@ -29,23 +31,20 @@ export class LinkMenu extends React.Component<Props> {
// });
// }
- renderLinkGroup(links: Doc[]) {
- console.log("render link group");
+ renderLinkGroupItems(links: Doc[]) {
let source = this.props.docView.Document;
- console.log("num links", links.length, typeof links);
return links.map(link => {
- let destination = (link["linkedTo"] === source) ? link["linkedFrom"] : link["linkedTo"];
+ // let destination = (link["linkedTo"] === source) ? link["linkedFrom"] : link["linkedTo"];
+ let destination = LinkManager.Instance.findOppositeAnchor(link, source);
let doc = FieldValue(Cast(destination, Doc));
if (doc) {
console.log(doc[Id] + source[Id], "source is", source[Id]);
- return <LinkBox key={doc[Id] + source[Id]} linkDoc={link} linkName={StrCast(link.title)} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={""} />;
+ return <LinkBox key={doc[Id] + source[Id]} linkDoc={link} linkName={"link"} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={""} />;
}
});
}
- renderLinkItems(links: Map<string, Array<Doc>>) {
- console.log("render link items");
-
+ renderLinkItems = (links: Map<string, Array<Doc>>): Array<JSX.Element> => {
let linkItems: Array<JSX.Element> = [];
links.forEach((links, group) => {
@@ -54,7 +53,7 @@ export class LinkMenu extends React.Component<Props> {
<div key={group} className="link-menu-group">
<p className="link-menu-group-name">{group}:</p>
<div className="link-menu-group-wrapper">
- {this.renderLinkGroup(links)}
+ {this.renderLinkGroupItems(links)}
</div>
</div>
)
@@ -80,8 +79,20 @@ export class LinkMenu extends React.Component<Props> {
</div>
);
} else {
+ let counter = 0;
+ let groups = new Map<number, Doc>();
+ let groupList = (Doc.AreProtosEqual(this.props.docView.props.Document, Cast(this._editingLink.anchor1, Doc, new Doc))) ?
+ Cast(this._editingLink.anchor1Groups, listSpec(Doc), []) : Cast(this._editingLink.anchor2Groups, listSpec(Doc), []);
+ groupList.forEach(group => {
+ if (group instanceof Doc) {
+ console.log(counter);
+ groups.set(counter, group);
+ counter++;
+ }
+ })
+
return (
- <LinkEditor linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)}></LinkEditor>
+ <LinkEditor groups={groups} sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)}></LinkEditor>
);
}