diff options
Diffstat (limited to 'src/client/util')
| -rw-r--r-- | src/client/util/DocumentManager.ts | 26 | ||||
| -rw-r--r-- | src/client/util/DragManager.ts | 14 | ||||
| -rw-r--r-- | src/client/util/LinkManager.ts | 137 |
3 files changed, 153 insertions, 24 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ff0c1560b..fc78993b8 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -9,6 +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 './LinkManager'; export class DocumentManager { @@ -83,35 +84,24 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { - return DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => { - let linksList = DocListCast(dv.props.Document.linkedToDocs); + let linked = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => { + + let linksList = LinkManager.Instance.findAllRelatedLinks(dv.props.Document); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { if (link) { - let linkToDoc = FieldValue(Cast(link.linkedTo, Doc)); - if (linkToDoc) { - DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => + let destination = LinkManager.Instance.findOppositeAnchor(link, dv.props.Document); + if (destination) { + DocumentManager.Instance.getDocumentViews(destination).map(docView1 => pairs.push({ a: dv, b: docView1, l: link })); } } return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); } - linksList = DocListCast(dv.props.Document.linkedFromDocs); - if (linksList && linksList.length) { - pairs.push(...linksList.reduce((pairs, link) => { - if (link) { - let linkFromDoc = FieldValue(Cast(link.linkedFrom, Doc)); - if (linkFromDoc) { - DocumentManager.Instance.getDocumentViews(linkFromDoc).map(docView1 => - pairs.push({ a: dv, b: docView1, l: link })); - } - } - return pairs; - }, pairs)); - } return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); + return linked; } @undoBatch diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ab00fabe1..b32c25b0a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -4,6 +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 "./LinkManager"; import { URLField } from "../../new_fields/URLField"; import { SelectionManager } from "./SelectionManager"; @@ -45,14 +46,15 @@ export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; let draggedDocs: Doc[] = []; - let draggedFromDocs: Doc[] = []; if (srcTarg) { - let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); - let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); - if (linkToDocs) draggedDocs = linkToDocs.map(linkDoc => Cast(linkDoc.linkedTo, Doc) as Doc); - if (linkFromDocs) draggedFromDocs = linkFromDocs.map(linkDoc => Cast(linkDoc.linkedFrom, Doc) as Doc); + let linkDocs = LinkManager.Instance.findAllRelatedLinks(srcTarg); + if (linkDocs) { + draggedDocs = linkDocs.map(link => { + return LinkManager.Instance.findOppositeAnchor(link, sourceDoc); + }); + } } - draggedDocs.push(...draggedFromDocs); + // draggedDocs.push(...draggedFromDocs); if (draggedDocs.length) { let moddrag: Doc[] = []; for (const draggedDoc of draggedDocs) { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts new file mode 100644 index 000000000..23ba9d2e4 --- /dev/null +++ b/src/client/util/LinkManager.ts @@ -0,0 +1,137 @@ +import { observable } from "mobx"; +import { StrCast, Cast } from "../../new_fields/Types"; +import { Doc, DocListCast } from "../../new_fields/Doc"; +import { listSpec } from "../../new_fields/Schema"; +import { List } from "../../new_fields/List"; + + +/* + * link doc: + * - anchor1: doc + * - anchor1page: number + * - anchor1groups: list of group docs representing the groups anchor1 categorizes this link/anchor2 in + * - anchor2: doc + * - anchor2page: number + * - anchor2groups: list of group docs representing the groups anchor2 categorizes this link/anchor1 in + * + * group doc: + * - type: string representing the group type/name/category + * - metadata: doc representing the metadata kvps + * + * metadata doc: + * - user defined kvps + */ +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> = []; // list of link docs + @observable public groupMetadataKeys: Map<string, Array<string>> = new Map(); + // map of group type to list of its metadata keys; serves as a dictionary of groups to what kind of metadata it hodls + + // finds all links that contain the given anchor + public findAllRelatedLinks(anchor: Doc): Array<Doc> { + return LinkManager.Instance.allLinks.filter( + link => Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc)) || Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, new Doc))); + } + + // returns map of group type to anchor's links in that group type + public findRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> { + let related = this.findAllRelatedLinks(anchor); + let anchorGroups = new Map<string, Array<Doc>>(); + related.forEach(link => { + let groups = LinkManager.Instance.getAnchorGroups(link, anchor); + + if (groups.length > 0) { + groups.forEach(groupDoc => { + let groupType = StrCast(groupDoc.type); + let group = anchorGroups.get(groupType); + if (group) group.push(link); + else group = [link]; + anchorGroups.set(groupType, group); + }); + } else { + // if link is in no groups then put it in default group + let group = anchorGroups.get("*"); + if (group) group.push(link); + else group = [link]; + anchorGroups.set("*", group); + } + + }); + return anchorGroups; + } + + // returns a list of all metadata docs associated with the given group type + public findAllMetadataDocsInGroup(groupType: string): Array<Doc> { + let md: Doc[] = []; + let allLinks = LinkManager.Instance.allLinks; + allLinks.forEach(linkDoc => { + let anchor1Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc)); + let anchor2Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc)); + anchor1Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); }); + anchor2Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); }); + }); + return md; + } + + // removes all group docs from all links with the given group type + public deleteGroup(groupType: string): void { + let deleted = LinkManager.Instance.groupMetadataKeys.delete(groupType); + if (deleted) { + LinkManager.Instance.allLinks.forEach(linkDoc => { + LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc), groupType); + LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc), groupType); + }); + } + } + + // removes group doc of given group type only from given anchor on given link + public removeGroupFromAnchor(linkDoc: Doc, anchor: Doc, groupType: string) { + let groups = LinkManager.Instance.getAnchorGroups(linkDoc, anchor); + let newGroups = groups.filter(groupDoc => StrCast(groupDoc.type).toUpperCase() !== groupType.toUpperCase()); + LinkManager.Instance.setAnchorGroups(linkDoc, anchor, newGroups); + } + + // checks if a link with the given anchors exists + public doesLinkExist(anchor1: Doc, anchor2: Doc) { + let allLinks = LinkManager.Instance.allLinks; + let index = allLinks.findIndex(linkDoc => { + return (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, new Doc), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, new Doc), anchor2)) || + (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, new Doc), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, new Doc), anchor1)); + }); + return index !== -1; + } + + // finds the opposite anchor of a given anchor in a link + public findOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc { + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { + return Cast(linkDoc.anchor2, Doc, new Doc); + } else { + return Cast(linkDoc.anchor1, Doc, new Doc); + } + } + + // gets the groups associates with an anchor in a link + public getAnchorGroups(linkDoc: Doc, anchor: Doc): Array<Doc> { + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { + return DocListCast(linkDoc.anchor1Groups); + } else { + return DocListCast(linkDoc.anchor2Groups); + } + } + + // sets the groups of the given anchor in the given link + public setAnchorGroups(linkDoc: Doc, anchor: Doc, groups: Doc[]) { + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { + linkDoc.anchor1Groups = new List<Doc>(groups); + } else { + linkDoc.anchor2Groups = new List<Doc>(groups); + } + } + +}
\ No newline at end of file |
