From 8a3cfa8d6e72c9bfea4b38760e0b138b6525574c Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 16 Oct 2019 16:42:37 -0400 Subject: a bunch of fixes to layouts to support templates in paticular. --- src/client/util/DocumentManager.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 00de39671..e23ac55c2 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -72,6 +72,8 @@ export class DocumentManager { toReturn = view; } }); + } else { + break; } } -- cgit v1.2.3-70-g09d2 From 73cb8628d13cc71e58717e97ca073c8b3316dd63 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 17 Oct 2019 23:40:29 -0400 Subject: working version of link lines between anchors --- src/client/documents/Documents.ts | 1 + src/client/util/DocumentManager.ts | 7 ++- src/client/util/LinkManager.ts | 6 ++- src/client/views/OverlayView.tsx | 2 + .../CollectionFreeFormLinkView.scss | 3 -- .../CollectionFreeFormLinkView.tsx | 63 ++++++---------------- .../CollectionFreeFormLinksView.scss | 5 +- .../CollectionFreeFormLinksView.tsx | 44 +++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 ++- src/client/views/nodes/DocuLinkBox.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/new_fields/Doc.ts | 2 +- 12 files changed, 50 insertions(+), 97 deletions(-) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index edc2ac653..d979e0a3f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -724,6 +724,7 @@ export namespace DocUtils { linkDocProto.layoutKey2 = DocuLinkBox.LayoutString("anchor2"); linkDocProto.width = linkDocProto.height = 0; linkDocProto.isBackground = true; + linkDocProto.isButton = true; LinkManager.Instance.addLink(linkDocProto); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e23ac55c2..fc406c6ab 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -9,6 +9,7 @@ import { DocumentView } from '../views/nodes/DocumentView'; import { LinkManager } from './LinkManager'; import { Scripting } from './Scripting'; import { SelectionManager } from './SelectionManager'; +import { DocumentType } from '../documents/DocumentTypes'; export class DocumentManager { @@ -110,14 +111,18 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { + console.log("START"); let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || Doc.IsBrushed(dv.props.Document)).reduce((pairs, dv) => { + console.log("DOC = " + dv.props.Document.title + " " + dv.props.Document.layout); let linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); pairs.push(...linksList.reduce((pairs, link) => { if (link) { let linkToDoc = LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); if (linkToDoc) { DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - pairs.push({ a: dv, b: docView1, l: link }); + if (dv.props.Document.type !== DocumentType.LINK || dv.props.layoutKey !== docView1.props.layoutKey) { + pairs.push({ a: dv, b: docView1, l: link }); + } }); } } diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 8a668e8d8..35c0f023f 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -79,7 +79,7 @@ export class LinkManager { let related = LinkManager.Instance.getAllLinks().filter(link => { let protomatch1 = Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, null)); let protomatch2 = Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, null)); - return protomatch1 || protomatch2; + return protomatch1 || protomatch2 || Doc.AreProtosEqual(link, anchor); }); return related; } @@ -244,8 +244,10 @@ export class LinkManager { public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { return Cast(linkDoc.anchor2, Doc, null); - } else { + } else if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor2, Doc, null))) { return Cast(linkDoc.anchor1, Doc, null); + } else if (Doc.AreProtosEqual(anchor, linkDoc)) { + return linkDoc; } } } diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 95c7b2683..9869e24d1 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -12,6 +12,7 @@ import { Transform } from "../util/Transform"; import { CollectionFreeFormDocumentView } from "./nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "./nodes/DocumentContentsView"; import { NumCast } from "../../new_fields/Types"; +import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; export type OverlayDisposer = () => void; @@ -206,6 +207,7 @@ export class OverlayView extends React.Component {
{this._elements}
+ {this.overlayDocs} ); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss index cfd18ad35..1f1bca2f2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss @@ -1,6 +1,5 @@ .collectionfreeformlinkview-linkLine { stroke: black; - transform: translate(10000px,10000px); opacity: 0.8; pointer-events: all; stroke-width: 3px; @@ -8,13 +7,11 @@ .collectionfreeformlinkview-linkCircle { stroke: rgb(0,0,0); opacity: 0.5; - transform: translate(10000px,10000px); pointer-events: all; cursor: pointer; } .collectionfreeformlinkview-linkText { stroke: rgb(0,0,0); opacity: 0.5; - transform: translate(10000px,10000px); pointer-events: all; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index a59fda6d9..4e1faccd7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,63 +1,30 @@ import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../../new_fields/Doc"; -import { BoolCast, NumCast, StrCast } from "../../../../new_fields/Types"; -import { InkingControl } from "../../InkingControl"; +import { Doc } from "../../../../new_fields/Doc"; +import { Utils } from '../../../../Utils'; +import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); +import { DocumentType } from "../../../documents/DocumentTypes"; export interface CollectionFreeFormLinkViewProps { - A: Doc; - B: Doc; + A: DocumentView; + B: DocumentView; LinkDocs: Doc[]; - addDocument: (document: Doc) => boolean; - removeDocument: (document: Doc) => boolean; } @observer export class CollectionFreeFormLinkView extends React.Component { - onPointerDown = (e: React.PointerEvent) => { - if (e.button === 0 && !InkingControl.Instance.selectedTool) { - let a = this.props.A; - let b = this.props.B; - let x1 = NumCast(a.x) + (BoolCast(a.isMinimized) ? 5 : a[WidthSym]() / 2); - let y1 = NumCast(a.y) + (BoolCast(a.isMinimized) ? 5 : a[HeightSym]() / 2); - let x2 = NumCast(b.x) + (BoolCast(b.isMinimized) ? 5 : b[WidthSym]() / 2); - let y2 = NumCast(b.y) + (BoolCast(b.isMinimized) ? 5 : b[HeightSym]() / 2); - // this.props.LinkDocs.map(l => { - // let width = l[WidthSym](); - // l.x = (x1 + x2) / 2 - width / 2; - // l.y = (y1 + y2) / 2 + 10; - // if (!this.props.removeDocument(l)) this.props.addDocument(l, false); - // }); - e.stopPropagation(); - e.preventDefault(); - } - } render() { - // let l = this.props.LinkDocs; - let a = this.props.A.layout instanceof Doc ? this.props.A.layout : this.props.A; - let b = this.props.B.layout instanceof Doc ? this.props.B.layout : this.props.B; - let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.width) / 2); - let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.height) / 2); - let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.width) / 2); - let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / 2); - let text = ""; - // let first = this.props.LinkDocs[0]; - // if (this.props.LinkDocs.length === 1) text += first.title + (first.linkDescription ? "(" + StrCast(first.linkDescription) + ")" : ""); - // else text = "-multiple-"; - return ( - <> - - {/* */} - - {text} - - - ); + let acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : []; + let bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : []; + let a = (acont.length ? acont[0] : this.props.A.ContentDiv!).getBoundingClientRect(); + let b = (bcont.length ? bcont[0] : this.props.B.ContentDiv!).getBoundingClientRect(); + let pt1 = Utils.getNearestPointInPerimeter(a.left, a.top, a.width, a.height, b.left + b.width / 2, b.top + b.height / 2); + let pt2 = Utils.getNearestPointInPerimeter(b.left, b.top, b.width, b.height, a.left + a.width / 2, a.top + a.height / 2); + return (); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss index 30e158603..cb5cef29c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss @@ -1,10 +1,9 @@ .collectionfreeformlinksview-svgCanvas{ - transform: translate(-10000px,-10000px); position: absolute; top: 0; left: 0; - width: 20000px; - height: 20000px; + width: 100%; + height: 100%; pointer-events: none; } .collectionfreeformlinksview-container { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 189981e35..cf0e55ccf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,17 +1,17 @@ import { computed, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; -import { Cast, FieldValue } from "../../../../new_fields/Types"; import { DocumentManager } from "../../../util/DocumentManager"; import { DocumentView } from "../../nodes/DocumentView"; -import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); +import { Utils } from "../../../../Utils"; +import { SelectionManager } from "../../../util/SelectionManager"; @observer -export class CollectionFreeFormLinksView extends React.Component { +export class CollectionFreeFormLinksView extends React.Component { _brushReactionDisposer?: IReactionDisposer; componentDidMount() { @@ -71,35 +71,18 @@ export class CollectionFreeFormLinksView extends React.Component - child[Id] === collid).map(view => - DocumentManager.Instance.getDocumentViews(view).map(view => - equalViews.push(view))); - } - return equalViews.filter(sv => sv.props.ContainingCollectionDoc === this.props.Document); - } - @computed get uniqueConnections() { let connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => { - let srcViews = this.documentAnchors(connection.a); - let targetViews = this.documentAnchors(connection.b); + let srcViews = [connection.a]; + let targetViews = [connection.b]; - let possiblePairs: { a: Doc, b: Doc, }[] = []; - srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); + let possiblePairs: { a: DocumentView, b: DocumentView, }[] = []; + srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv, b: tv }))); possiblePairs.map(possiblePair => { if (!drawnPairs.reduce((found, drawnPair) => { - let match1 = (Doc.AreProtosEqual(possiblePair.a, drawnPair.a) && Doc.AreProtosEqual(possiblePair.b, drawnPair.b)); - let match2 = (Doc.AreProtosEqual(possiblePair.a, drawnPair.b) && Doc.AreProtosEqual(possiblePair.b, drawnPair.a)); + let match1 = (Doc.AreProtosEqual(possiblePair.a.props.Document, drawnPair.a.props.Document) && Doc.AreProtosEqual(possiblePair.b.props.Document, drawnPair.b.props.Document)); + let match2 = (Doc.AreProtosEqual(possiblePair.a.props.Document, drawnPair.b.props.Document) && Doc.AreProtosEqual(possiblePair.b.props.Document, drawnPair.a.props.Document)); let match = match1 || match2; if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { drawnPair.l.push(connection.l); @@ -110,16 +93,15 @@ export class CollectionFreeFormLinksView extends React.Component p + l[Id], "")} A={c.a} B={c.b} LinkDocs={c.l} - removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />); + }, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]); + return connections.map(c => ); } render() { return (
- {this.uniqueConnections} + {SelectionManager.GetIsDragging() ? (null) : this.uniqueConnections} {this.props.children}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5dccb5bf0..b3270d507 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -705,11 +705,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}> - - - {this.childViews} - - + + {this.childViews} + diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx index 8c41b9d4f..f56bf4ad3 100644 --- a/src/client/views/nodes/DocuLinkBox.tsx +++ b/src/client/views/nodes/DocuLinkBox.tsx @@ -54,12 +54,12 @@ export class DocuLinkBox extends DocComponent(Doc onPointerUp = (e: PointerEvent) => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button === 2 || e.ctrlKey)) { + if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button === 2 || e.ctrlKey || !this.props.Document.isButton)) { this.props.select(false); } } onClick = (e: React.MouseEvent) => { - if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button !== 2 && !e.ctrlKey)) { + if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button !== 2 && !e.ctrlKey && this.props.Document.isButton)) { DocumentManager.Instance.FollowLink(this.props.Document, this.props.Document[this.props.fieldKey] as Doc, document => this.props.addDocTab(document, undefined, "inTab"), false); } e.stopPropagation(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6775655eb..0bcaa99aa 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -697,7 +697,7 @@ export class DocumentView extends DocComponent(Docu opacity: this.Document.opacity }} onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} + onPointerEnter={() => { Doc.UnBrushAllDocs(); Doc.BrushDoc(this.props.Document); }} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} > {this.props.Document.links && DocListCast(this.props.Document.links).map((d, i) =>
)} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 04f310785..26355d0e7 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -734,7 +734,7 @@ export namespace Doc { } export function UnBrushAllDocs() { - manager.BrushedDoc.clear(); + brushManager.BrushedDoc.clear(); } export function setChildLayout(target: Doc, source?: Doc) { -- cgit v1.2.3-70-g09d2 From f0e8502be6488418370d4cd3dbb6c60ffd30f658 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 00:25:39 -0400 Subject: better version of link lines between anchors --- src/client/util/DocumentManager.ts | 37 ++++++---------------- .../CollectionFreeFormLinksView.tsx | 31 ++++++++---------- src/client/views/nodes/DocumentView.tsx | 10 ++++-- 3 files changed, 30 insertions(+), 48 deletions(-) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index fc406c6ab..aed7aafd1 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -42,8 +42,8 @@ export class DocumentManager { if (toReturn.length === 0) { DocumentManager.Instance.DocumentViews.map(view => { let doc = view.props.Document.proto; - if (doc && doc[Id]) { - if (doc[Id] === id) { toReturn.push(view); } + if (doc && doc[Id] && doc[Id] === id) { + toReturn.push(view); } }); } @@ -90,42 +90,25 @@ export class DocumentManager { return views.length ? views[0] : undefined; } public getDocumentViews(toFind: Doc): DocumentView[] { - let toReturn: DocumentView[] = []; - //gets document view that is in a freeform canvas collection - DocumentManager.Instance.DocumentViews.map(view => { - let doc = view.props.Document; - - if (doc === toFind) { - toReturn.push(view); - } else { - if (Doc.AreProtosEqual(doc, toFind)) { - toReturn.push(view); - } - } - }); + DocumentManager.Instance.DocumentViews.map(view => + Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); return toReturn; } @computed public get LinkedDocumentViews() { - console.log("START"); let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || Doc.IsBrushed(dv.props.Document)).reduce((pairs, dv) => { - console.log("DOC = " + dv.props.Document.title + " " + dv.props.Document.layout); let linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); pairs.push(...linksList.reduce((pairs, link) => { - if (link) { - let linkToDoc = LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); - if (linkToDoc) { - DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - if (dv.props.Document.type !== DocumentType.LINK || dv.props.layoutKey !== docView1.props.layoutKey) { - pairs.push({ a: dv, b: docView1, l: link }); - } - }); + let linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); + linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { + if (dv.props.Document.type !== DocumentType.LINK || dv.props.layoutKey !== docView1.props.layoutKey) { + pairs.push({ a: dv, b: docView1, l: link }); } - } + }); return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); // } @@ -135,8 +118,6 @@ export class DocumentManager { return pairs; } - - public jumpToDocument = async (targetDoc: Doc, willZoom: boolean, dockFunc?: (doc: Doc) => void, docContext?: Doc, linkId?: string, closeContextIfNotFound: boolean = false): Promise => { let highlight = () => { const finalDocView = DocumentManager.Instance.getFirstDocumentView(targetDoc); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index cf0e55ccf..a26febda4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -9,6 +9,7 @@ import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); import { Utils } from "../../../../Utils"; import { SelectionManager } from "../../../util/SelectionManager"; +import { DocumentType } from "../../../documents/DocumentTypes"; @observer export class CollectionFreeFormLinksView extends React.Component { @@ -74,27 +75,21 @@ export class CollectionFreeFormLinksView extends React.Component { @computed get uniqueConnections() { let connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => { - let srcViews = [connection.a]; - let targetViews = [connection.b]; - - let possiblePairs: { a: DocumentView, b: DocumentView, }[] = []; - srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv, b: tv }))); - possiblePairs.map(possiblePair => { - if (!drawnPairs.reduce((found, drawnPair) => { - let match1 = (Doc.AreProtosEqual(possiblePair.a.props.Document, drawnPair.a.props.Document) && Doc.AreProtosEqual(possiblePair.b.props.Document, drawnPair.b.props.Document)); - let match2 = (Doc.AreProtosEqual(possiblePair.a.props.Document, drawnPair.b.props.Document) && Doc.AreProtosEqual(possiblePair.b.props.Document, drawnPair.a.props.Document)); - let match = match1 || match2; - if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { - drawnPair.l.push(connection.l); - } - return match || found; - }, false)) { - drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); + if (!drawnPairs.reduce((found, drawnPair) => { + let match1 = (connection.a === drawnPair.a && connection.b === drawnPair.b); + let match2 = (connection.a === drawnPair.b && connection.b === drawnPair.a); + let match = match1 || match2; + if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { + drawnPair.l.push(connection.l); } - }); + return match || found; + }, false)) { + drawnPairs.push({ a: connection.a, b: connection.b, l: [connection.l] }); + } return drawnPairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]); - return connections.map(c => ); + return connections.filter(c => c.a.props.Document.type === DocumentType.LINK) // get rid of the filter to show links to documents in addition to document anchors + .map(c => ); } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0bcaa99aa..d4c2c512c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -697,10 +697,16 @@ export class DocumentView extends DocComponent(Docu opacity: this.Document.opacity }} onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - onPointerEnter={() => { Doc.UnBrushAllDocs(); Doc.BrushDoc(this.props.Document); }} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} + onPointerEnter={() => { + Doc.UnBrushAllDocs(); + DocListCast(this.props.Document.links).map(Doc.BrushDoc); + Doc.BrushDoc(this.props.Document); + }} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} > {this.props.Document.links && DocListCast(this.props.Document.links).map((d, i) => -
)} +
+ +
)} {!showTitle && !showCaption ? this.Document.searchFields ? (
-- cgit v1.2.3-70-g09d2 From c9a84a7d74efa820d1dc55d8ef93bec40315be4a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 01:29:33 -0400 Subject: link lines are working properly except when things get panned/moved ... need to turn off or get updates somehow. --- src/client/documents/Documents.ts | 15 ++-------- src/client/util/DocumentManager.ts | 11 +++++-- src/client/views/DocumentDecorations.tsx | 3 +- .../CollectionFreeFormLinksView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 35 ---------------------- src/client/views/nodes/DocumentContentsView.tsx | 32 ++++++++------------ src/client/views/nodes/DocumentView.tsx | 9 ++---- src/new_fields/Doc.ts | 6 ---- 8 files changed, 28 insertions(+), 87 deletions(-) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d979e0a3f..b53549f7a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -80,7 +80,6 @@ export interface DocumentOptions { opacity?: number; defaultBackgroundColor?: string; dropAction?: dropActionType; - backgroundLayout?: string; chromeStatus?: string; columnWidth?: number; fontSize?: number; @@ -127,7 +126,6 @@ export namespace Docs { layout: { view: LayoutSource, ext?: string, // optional extension field for layout source - collectionView?: CollectionViewType }, options?: Partial }; @@ -142,7 +140,7 @@ export namespace Docs { options: { height: 150, backgroundColor: "#f1efeb", defaultBackgroundColor: "#f1efeb" } }], [DocumentType.HIST, { - layout: { view: HistogramBox, collectionView: [CollectionView, data] as CollectionViewType }, + layout: { view: HistogramBox }, options: { height: 300, backgroundColor: "black" } }], [DocumentType.QUERY, { @@ -290,15 +288,8 @@ export namespace Docs { // synthesize the default options, the type and title from computed values and // whatever options pertain to this specific prototype let options = { title, type, baseProto: true, ...defaultOptions, ...(template.options || {}) }; - let primary = layout.view.LayoutString(layout.ext); - let collectionView = layout.collectionView; - if (collectionView) { - options.layout = collectionView[0].LayoutString(collectionView[1], collectionView[2]); - options.backgroundLayout = primary; - } else { - options.layout = primary; - } - return Doc.assign(new Doc(prototypeId, true), { ...options, baseLayout: primary }); + options.layout = layout.view.LayoutString(layout.ext); + return Doc.assign(new Doc(prototypeId, true), { ...options, baseLayout: options.layout }); } } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index aed7aafd1..ee6772f8f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,5 +1,5 @@ import { action, computed, observable } from 'mobx'; -import { Doc, DocListCastAsync } from '../../new_fields/Doc'; +import { Doc, DocListCastAsync, DocListCast } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; import { List } from '../../new_fields/List'; import { Cast, NumCast, StrCast } from '../../new_fields/Types'; @@ -100,7 +100,13 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { - let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || Doc.IsBrushed(dv.props.Document)).reduce((pairs, dv) => { + let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || Doc.IsBrushed(dv.props.Document) + || DocumentManager.Instance.DocumentViews.some(dv2 => { + let init = dv2.isSelected() || Doc.IsBrushed(dv2.props.Document); + let rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document)); + return init && rest; + }) + ).reduce((pairs, dv) => { let linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); pairs.push(...linksList.reduce((pairs, link) => { let linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); @@ -111,7 +117,6 @@ export class DocumentManager { }); return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); - // } return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6e8ba2d3d..8409a34da 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -111,7 +111,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> Doc.GetProto(docTemplate).layoutNative = layoutNative; swapViews(fieldTemplate, "", "layoutNative", layoutNative); layoutNative.layout = StrCast(fieldTemplateView.props.Document.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`); - layoutNative.backgroundLayout = StrCast(fieldTemplateView.props.Document.backgroundLayout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`); } } } @@ -343,7 +342,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let iconDoc: Doc | undefined = await Cast(doc.minimizedDoc, Doc); if (!iconDoc || !DocumentManager.Instance.getDocumentView(iconDoc)) { - const layout = StrCast(doc.backgroundLayout, StrCast(doc.layout, FieldView.LayoutString(DocumentView))); + const layout = StrCast(doc.layout, FieldView.LayoutString(DocumentView)); iconDoc = this.createIcon([docView], layout); } return iconDoc; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index a26febda4..e9191c176 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -68,9 +68,7 @@ export class CollectionFreeFormLinksView extends React.Component { // }); } componentWillUnmount() { - if (this._brushReactionDisposer) { - this._brushReactionDisposer(); - } + this._brushReactionDisposer && this._brushReactionDisposer(); } @computed get uniqueConnections() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b3270d507..932b6722b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -467,22 +467,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getScale: this.getScale }; } - getDocumentViewProps(layoutDoc: Doc): DocumentViewProps { - return { - ...this.props, - ScreenToLocalTransform: this.getTransform, - PanelWidth: layoutDoc[WidthSym], - PanelHeight: layoutDoc[HeightSym], - ContentScaling: returnOne, - ContainingCollectionView: this.props.ContainingCollectionView, - focus: this.focusDocument, - backgroundColor: returnEmptyString, - parentActive: this.props.active, - bringToFront: this.bringToFront, - zoomToScale: this.zoomToScale, - getScale: this.getScale - }; - } getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, transition?: string, state?: any } { const script = this.Document.arrangeScript; @@ -682,7 +666,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private childViews = () => { let children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; return [ - , ...children, ...this.views, ]; @@ -712,29 +695,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.overlayViews} -
); } } -@observer -class CollectionFreeFormOverlayView extends React.Component boolean }> { - render() { - return ; - } -} - -@observer -class CollectionFreeFormBackgroundView extends React.Component boolean }> { - render() { - return !this.props.Document.backgroundLayout ? (null) : - (); - } -} - interface CollectionFreeFormViewPannableContentsProps { centeringShiftX: () => number; centeringShiftY: () => number; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4971e6ce5..d375405b9 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -92,26 +92,20 @@ export class DocumentContentsView extends React.Component" : this.layout; - } - render() { - let self = this; - if (this.props.renderDepth > 7) return (null); - if (!this.layout && this.props.layoutKey !== "overlayLayout") return (null); - return 7 || !this.layout) ? (null) : + { console.log(test); }} - />; + onError={(test: any) => { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d4c2c512c..48ad7a632 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -163,6 +163,7 @@ export class DocumentView extends DocComponent(Docu @action componentWillUnmount() { this._dropDisposer && this._dropDisposer(); + Doc.UnBrushDoc(this.props.Document); DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } @@ -697,11 +698,7 @@ export class DocumentView extends DocComponent(Docu opacity: this.Document.opacity }} onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - onPointerEnter={() => { - Doc.UnBrushAllDocs(); - DocListCast(this.props.Document.links).map(Doc.BrushDoc); - Doc.BrushDoc(this.props.Document); - }} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} + onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} > {this.props.Document.links && DocListCast(this.props.Document.links).map((d, i) =>
@@ -739,7 +736,6 @@ export async function swapViews(doc: Doc, newLayoutField: string, oldLayoutField oldLayoutExt.nativeWidth = doc.nativeWidth; oldLayoutExt.nativeHeight = doc.nativeHeight; oldLayoutExt.ignoreAspect = doc.ignoreAspect; - oldLayoutExt.backgroundLayout = doc.backgroundLayout; oldLayoutExt.type = doc.type; oldLayoutExt.layout = doc.layout; } @@ -752,7 +748,6 @@ export async function swapViews(doc: Doc, newLayoutField: string, oldLayoutField doc.nativeWidth = newLayoutExt.nativeWidth; doc.nativeHeight = newLayoutExt.nativeHeight; doc.ignoreAspect = newLayoutExt.ignoreAspect; - doc.backgroundLayout = newLayoutExt.backgroundLayout; doc.type = newLayoutExt.type; doc.layout = await newLayoutExt.layout; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 26355d0e7..69c048ebf 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -592,7 +592,6 @@ export namespace Doc { target.ignoreAspect = templateDoc.nativeWidth ? true : false; target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy](); target.layout = layoutCustomLayout; - target.backgroundLayout = layoutCustomLayout.backgroundLayout; target.layoutNative = Cast(templateDoc.layoutNative, Doc) as Doc; target.layoutCustom = layoutCustom; @@ -602,19 +601,14 @@ export namespace Doc { export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc, suppressTitle: boolean = false): boolean { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let metadataFieldName = StrCast(fieldTemplate.title).replace(/^-/, ""); - let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); let fieldLayoutDoc = fieldTemplate; if (fieldTemplate.layout instanceof Doc) { fieldLayoutDoc = Doc.MakeDelegate(fieldTemplate.layout); } - if (backgroundLayout) { - backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metadataFieldName}"}`); - } fieldTemplate.templateField = metadataFieldName; fieldTemplate.title = metadataFieldName; fieldTemplate.isTemplateField = true; - fieldTemplate.backgroundLayout = backgroundLayout; /* move certain layout properties from the original data doc to the template layout to avoid inheriting them from the template's data doc which may also define these fields for its own use. */ -- cgit v1.2.3-70-g09d2 From 11537da75c76fba79a2709d2ad175dfa16a25256 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 14:00:25 -0400 Subject: fixes for drawing link anchors to pdf text selections. --- src/client/documents/DocumentTypes.ts | 3 ++- src/client/util/DocumentManager.ts | 9 +++++---- src/client/util/LinkManager.ts | 19 +++++++------------ src/client/views/MainView.tsx | 3 ++- src/client/views/nodes/DocuLinkBox.tsx | 7 +++++-- src/client/views/nodes/DocumentView.scss | 3 --- src/client/views/nodes/DocumentView.tsx | 2 ++ src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 6 ++++++ 9 files changed, 30 insertions(+), 24 deletions(-) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index ea37fc2f1..12501065a 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -23,5 +23,6 @@ export enum DocumentType { PRESELEMENT = "preselement", QUERY = "search", COLOR = "color", - DOCULINK = "doculink" + DOCULINK = "doculink", + PDFANNO = "pdfanno" } \ No newline at end of file diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ee6772f8f..0f2a47dd0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -100,10 +100,11 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { - let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || Doc.IsBrushed(dv.props.Document) - || DocumentManager.Instance.DocumentViews.some(dv2 => { - let init = dv2.isSelected() || Doc.IsBrushed(dv2.props.Document); - let rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document)); + let pairs = DocumentManager.Instance.DocumentViews.filter(dv => + dv.isSelected() || Doc.IsBrushed(dv.props.Document) // draw links from DocumentViews that are selected or brushed OR + || DocumentManager.Instance.DocumentViews.some(dv2 => { // Documentviews which + let rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document));// are link doc anchors + let init = dv2.isSelected() || Doc.IsBrushed(dv2.props.Document); // on a view that is selected or brushed return init && rest; }) ).reduce((pairs, dv) => { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 35c0f023f..ee2f2dadc 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,10 +1,7 @@ -import { observable, action } from "mobx"; -import { StrCast, Cast, FieldValue } from "../../new_fields/Types"; import { Doc, DocListCast } from "../../new_fields/Doc"; -import { listSpec } from "../../new_fields/Schema"; import { List } from "../../new_fields/List"; -import { Id } from "../../new_fields/FieldSymbols"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { listSpec } from "../../new_fields/Schema"; +import { Cast, StrCast } from "../../new_fields/Types"; import { Docs } from "../documents/Documents"; import { Scripting } from "./Scripting"; @@ -242,13 +239,11 @@ export class LinkManager { //TODO This should probably return undefined if there isn't an opposite anchor //TODO This should also await the return value of the anchor so we don't filter out promises public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { - if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { - return Cast(linkDoc.anchor2, Doc, null); - } else if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor2, Doc, null))) { - return Cast(linkDoc.anchor1, Doc, null); - } else if (Doc.AreProtosEqual(anchor, linkDoc)) { - return linkDoc; - } + let a1 = Cast(linkDoc.anchor1, Doc, null); + let a2 = Cast(linkDoc.anchor2, Doc, null); + if (Doc.AreProtosEqual(anchor, a1)) return a2; + if (Doc.AreProtosEqual(anchor, a2)) return a1; + if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; } } Scripting.addGlobal(function links(doc: any) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9304f4bef..4c2b6f262 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -183,7 +183,8 @@ export class MainView extends React.Component { y: 400, width: this._panelWidth * .7, height: this._panelHeight, - title: "My Blank Collection" + title: "My Blank Collection", + backgroundColor: "white" }; let workspaces: FieldResult; let freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx index f56bf4ad3..3294a5aa2 100644 --- a/src/client/views/nodes/DocuLinkBox.tsx +++ b/src/client/views/nodes/DocuLinkBox.tsx @@ -2,7 +2,7 @@ import { action, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../new_fields/Doc"; import { makeInterface } from "../../../new_fields/Schema"; -import { NumCast, StrCast } from "../../../new_fields/Types"; +import { NumCast, StrCast, Cast } from "../../../new_fields/Types"; import { Utils } from '../../../Utils'; import { DocumentManager } from "../../util/DocumentManager"; import { DragLinksAsDocuments } from "../../util/DragManager"; @@ -11,6 +11,7 @@ import { documentSchema } from "./DocumentView"; import "./DocuLinkBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; import React = require("react"); +import { DocumentType } from "../../documents/DocumentTypes"; type DocLinkSchema = makeInterface<[typeof documentSchema]>; const DocLinkDocument = makeInterface(documentSchema); @@ -65,13 +66,15 @@ export class DocuLinkBox extends DocComponent(Doc e.stopPropagation(); } render() { + let anchorDoc = Cast(this.props.Document[this.props.fieldKey], Doc); + let hasAnchor = anchorDoc instanceof Doc && anchorDoc.type === DocumentType.PDFANNO; let y = NumCast(this.props.Document[this.props.fieldKey + "_y"], 100); let x = NumCast(this.props.Document[this.props.fieldKey + "_x"], 100); let c = StrCast(this.props.Document.backgroundColor, "lightblue"); return
; } } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 69eb1a843..a0bf74990 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -47,9 +47,6 @@ } } } -.documentView-node-topmost { - background: white; -} .documentView-styleWrapper { position: absolute; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 48ad7a632..8bf698391 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -629,6 +629,7 @@ export class DocumentView extends DocComponent(Docu DataDoc={this.props.DataDoc} />); } linkEndpoint = (linkDoc: Doc) => Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; + linkEndpointDoc = (linkDoc: Doc) => Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor1, Doc) as Doc : Cast(linkDoc.anchor2, Doc) as Doc; render() { if (!this.props.Document) return (null); @@ -701,6 +702,7 @@ export class DocumentView extends DocComponent(Docu onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} > {this.props.Document.links && DocListCast(this.props.Document.links).map((d, i) => + //this.linkEndpointDoc(d).type === DocumentType.PDFANNO ? (null) :
)} diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index ad6240c70..e0a3b9171 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -100,7 +100,7 @@ class RegionAnnotation extends React.Component { let annoGroup = await Cast(this.props.document.group, Doc); if (annoGroup) { DocumentManager.Instance.FollowLink(undefined, annoGroup, - (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "onRight" : "inTab"), + (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"), false, false, undefined); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1bae6128c..6e5f1a981 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -25,6 +25,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { undoBatch } from "../../util/UndoManager"; import { DocAnnotatableComponent } from "../DocComponent"; import { documentSchema } from "../nodes/DocumentView"; +import { DocumentType } from "../../documents/DocumentTypes"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -249,6 +250,7 @@ export class PDFViewer extends DocAnnotatableComponent(annoDocs); } mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title); -- cgit v1.2.3-70-g09d2 From 910e4d8a22a312d2ca0b8a970ff434604f7c6f91 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 23 Oct 2019 23:35:01 -0400 Subject: several fixes to audio documents to make linking work better and to customize the audio controls UI --- src/client/documents/Documents.ts | 3 +- src/client/util/DocumentManager.ts | 4 +- src/client/views/nodes/AudioBox.scss | 62 +++++++++++++++++++--- src/client/views/nodes/AudioBox.tsx | 94 +++++++++++++++++++++------------ src/client/views/nodes/DocuLinkBox.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 16 ++++-- src/new_fields/Doc.ts | 2 + 7 files changed, 134 insertions(+), 51 deletions(-) (limited to 'src/client/util/DocumentManager.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index cad417d33..f26594e04 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -171,7 +171,7 @@ export namespace Docs { }], [DocumentType.AUDIO, { layout: { view: AudioBox, dataField: data }, - options: { height: 32 } + options: { height: 35, backgroundColor: "lightGray", borderRounding: "20%" } }], [DocumentType.PDF, { layout: { view: PDFBox, dataField: data }, @@ -691,6 +691,7 @@ export namespace DocUtils { } }); } + export function MakeLink(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, title: string = "", description: string = "", id?: string) { let sv = DocumentManager.Instance.getDocumentView(source.doc); if (sv && sv.props.ContainingCollectionDoc === target.doc) return; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 0f2a47dd0..346e88f40 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -101,10 +101,10 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { let pairs = DocumentManager.Instance.DocumentViews.filter(dv => - dv.isSelected() || Doc.IsBrushed(dv.props.Document) // draw links from DocumentViews that are selected or brushed OR + (dv.isSelected() || Doc.IsBrushed(dv.props.Document)) // draw links from DocumentViews that are selected or brushed OR || DocumentManager.Instance.DocumentViews.some(dv2 => { // Documentviews which let rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document));// are link doc anchors - let init = dv2.isSelected() || Doc.IsBrushed(dv2.props.Document); // on a view that is selected or brushed + let init = (dv2.isSelected() || Doc.IsBrushed(dv2.props.Document)) && dv2.Document.type !== DocumentType.AUDIO; // on a view that is selected or brushed return init && rest; }) ).reduce((pairs, dv) => { diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 14b90c570..3d6f6c4f9 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -1,10 +1,10 @@ .audiobox-container, .audiobox-container-interactive { width: 100%; height: 100%; - min-height: 32px; position: inherit; display:flex; pointer-events: all; + cursor:default; .audiobox-handle { width:20px; height:100%; @@ -35,18 +35,66 @@ width:100%; height:100%; position: relative; - display: grid; + display: flex; .audiobox-player { margin-top:auto; margin-bottom:auto; width:100%; + height: 80%; position: relative; - display: grid; - .audiobox-marker { - position:absolute; - width:10px; + display: flex; + .audiobox-playhead { + position: relative; + margin-top: auto; + margin-bottom: auto; + width: 25px; + } + .audiobox-timeline { + position:relative; height:100%; - background:green; + width:100%; + .audiobox-current { + width: 1px; + height:100%; + background-color: red; + position: absolute;; + } + .audiobox-linker { + position:absolute; + width:15px; + min-height:10px; + height:15px; + margin-left:-2.55px; + background:gray; + border-radius: 100%; + background-color: transparent; + box-shadow: black 2px 2px 1px; + .docuLinkBox-cont { + width:15px !important; + height:15px !important; + left: calc(100% - 15px) !important; + top: calc(100% - 15px) !important; + } + } + .audiobox-linker:hover { + transform:scale(1.5); + } + .audiobox-marker-container { + position:absolute; + width:10px; + height:100%; + background:gray; + border-radius: 5px; + box-shadow: black 2px 2px 1px; + .audiobox-marker { + position:relative; + height: calc(100% - 15px); + margin-top: 15px; + } + .audio-marker:hover { + border: orange 2px solid; + } + } } } } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 57360272e..3933c6257 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -7,17 +7,18 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField"; import { DocExtendableComponent } from "../DocComponent"; import { makeInterface, createSchema } from "../../../new_fields/Schema"; import { documentSchema } from "../../../new_fields/documentSchemas"; -import { Utils } from "../../../Utils"; +import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent } from "../../../Utils"; import { RouteStore } from "../../../server/RouteStore"; import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx"; import { DateField } from "../../../new_fields/DateField"; import { SelectionManager } from "../../util/SelectionManager"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast, WidthSym } from "../../../new_fields/Doc"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { Id } from "../../../new_fields/FieldSymbols"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { DocumentManager } from "../../util/DocumentManager"; +import { DocumentView } from "./DocumentView"; interface Window { MediaRecorder: MediaRecorder; @@ -44,16 +45,14 @@ export class AudioBox extends DocExtendableComponent AudioBox._scrubTime = timeInMillisFrom1970); public static ActiveRecordings: Doc[] = []; componentDidMount() { - runInAction(() => this._duration = NumCast(this.dataDoc.duration, 1)); runInAction(() => this._audioState = this.path ? "recorded" : "unrecorded"); this._linkPlayDisposer = reaction(() => this.layoutDoc.scrollToLinkID, scrollLinkId => { @@ -75,14 +74,12 @@ export class AudioBox extends DocExtendableComponent { + timecodeChanged = () => { const extensionDoc = this.extensionDoc; const htmlEle = this._ele; const start = extensionDoc && DateCast(extensionDoc.recordingStart); - if (htmlEle && !htmlEle.paused && start) { - htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = this._duration = htmlEle.duration); - setTimeout(this.updateHighlights, 30); - this.Document.currentTimecode = htmlEle.currentTime; + if (start && htmlEle) { + htmlEle && htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration); DocListCast(this.dataDoc.links).map(l => { let la1 = l.anchor1 as Doc; let linkTime = NumCast(l.anchor2Timecode); @@ -90,25 +87,29 @@ export class AudioBox extends DocExtendableComponent this._lastUpdate && linkTime < htmlEle.currentTime) { + if (linkTime > NumCast(this.Document.currentTimecode) && linkTime < htmlEle.currentTime) { Doc.linkFollowHighlight(la1); } }); - this._lastUpdate = htmlEle.currentTime; + this.Document.currentTimecode = htmlEle.currentTime; } } + pause = action(() => { + this._ele!.pause(); + this._playing = false; + }) + playFrom = (seekTimeInSeconds: number) => { if (this._ele) { if (seekTimeInSeconds < 0) { - this._ele.pause(); + this.pause(); } else if (seekTimeInSeconds <= this._ele.duration) { this._ele.currentTime = seekTimeInSeconds; this._ele.play(); - this._lastUpdate = seekTimeInSeconds; - setTimeout(this.updateHighlights, 0); + runInAction(() => this._playing = true); } else { - this._ele.pause(); + this.pause(); } } } @@ -170,6 +171,7 @@ export class AudioBox extends DocExtendableComponent { this._recorder.stop(); + this.dataDoc.duration = (new Date().getTime() - this._recordStart) / 1000; this._audioState = "recorded"; let ind = AudioBox.ActiveRecordings.indexOf(this.props.Document); ind !== -1 && (AudioBox.ActiveRecordings.splice(ind, 1)); @@ -182,12 +184,15 @@ export class AudioBox extends DocExtendableComponent setTimeout(this.updateHighlights, 30); onPlay = (e: any) => this.playFrom(this._ele!.paused ? this._ele!.currentTime : -1); + onStop = (e: any) => { + this.pause(); + this._ele!.currentTime = 0; + e.stopPropagation(); + } setRef = (e: HTMLAudioElement | null) => { - e && e.addEventListener("play", this.playClick as any); - e && e.addEventListener("timeupdate", () => this.props.Document.currentTimecode = e!.currentTime); + e && e.addEventListener("timeupdate", action(() => this.Document.currentTimecode = e!.currentTime)); this._ele = e; } @@ -216,21 +221,40 @@ export class AudioBox extends DocExtendableComponent :
- - {DocListCast(this.dataDoc.links).map((l, i) => { - let la1 = l.anchor1 as Doc; - let la2 = l.anchor2 as Doc; - let linkTime = NumCast(l.anchor2Timecode); - if (Doc.AreProtosEqual(la1, this.dataDoc)) { - la1 = l.anchor2 as Doc; - la2 = l.anchor1 as Doc; - linkTime = NumCast(l.anchor1Timecode); - } - return
- DocumentManager.Instance.FollowLink(l, la2, document => this.props.addDocTab(document, undefined, "onRight"), false)} - style={{ left: `${linkTime / this._duration * 100}%` }} />; - })} - {this.audio} + +
+
e.stopPropagation()} + onPointerDown={e => { + if (e.button === 0 && !e.ctrlKey) { + let rect = (e.target as any).getBoundingClientRect(); + this._ele!.currentTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + this.pause(); + e.stopPropagation(); + } + }} > + {DocListCast(this.dataDoc.links).map((l, i) => { + let la1 = l.anchor1 as Doc; + let la2 = l.anchor2 as Doc; + let linkTime = NumCast(l.anchor2Timecode); + if (Doc.AreProtosEqual(la1, this.dataDoc)) { + la1 = l.anchor2 as Doc; + la2 = l.anchor1 as Doc; + linkTime = NumCast(l.anchor1Timecode); + } + return !linkTime ? (null) :
+
+ +
+
Doc.linkFollowHighlight(la1)} + onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); } }} + onClick={e => { if (e.button === 0 && !e.ctrlKey) { this.pause(); e.stopPropagation(); } }} /> +
; + })} +
+ {this.audio} +
} diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx index 7119b0db0..f2ab6fcd8 100644 --- a/src/client/views/nodes/DocuLinkBox.tsx +++ b/src/client/views/nodes/DocuLinkBox.tsx @@ -33,7 +33,7 @@ export class DocuLinkBox extends DocComponent(Doc document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); document.addEventListener("pointerup", this.onPointerUp); - e.stopPropagation(); + (e.button === 0 && !e.ctrlKey) && e.stopPropagation(); } onPointerMove = action((e: PointerEvent) => { let cdiv = this._ref.current!.parentElement; @@ -43,7 +43,7 @@ export class DocuLinkBox extends DocComponent(Doc let separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY)); let dragdist = Math.sqrt((pt[0] - this._downx) * (pt[0] - this._downx) + (pt[1] - this._downy) * (pt[1] - this._downy)); if (separation > 100) { - DragLinksAsDocuments(this._ref.current!, pt[0], pt[1], this.props.ContainingCollectionDoc as Doc, this.props.Document); // Containging collection is the document, not a collection... hack. + DragLinksAsDocuments(this._ref.current!, pt[0], pt[1], Cast(this.props.Document[this.props.fieldKey], Doc) as Doc, this.props.Document); // Containging collection is the document, not a collection... hack. document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); } else if (dragdist > separation) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c82fd0f0f..ed93aa83e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -41,6 +41,7 @@ import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { FormattedTextBox } from './FormattedTextBox'; import React = require("react"); +import { link } from 'fs'; library.add(fa.faEdit); library.add(fa.faTrash); @@ -585,8 +586,16 @@ export class DocumentView extends DocComponent(Docu layoutKey={this.props.layoutKey || "layout"} DataDoc={this.props.DataDoc} />); } - linkEndpoint = (linkDoc: Doc) => Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; - linkEndpointDoc = (linkDoc: Doc) => Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor1, Doc) as Doc : Cast(linkDoc.anchor2, Doc) as Doc; + linkEndpoint = (linkDoc: Doc) => Doc.LinkEndpoint(linkDoc, this.props.Document); + + // used to decide whether a link document should be created or not. + // if it's a tempoarl link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here. + // would be good to generalize this some way. + isNonTemporalLink = (linkDoc: Doc) => { + let anchor = Cast(Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1 : linkDoc.anchor2, Doc) as Doc; + let ept = Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1Timecode : linkDoc.anchor2Timecode; + return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true; + } render() { if (!this.props.Document) return (null); @@ -658,8 +667,7 @@ export class DocumentView extends DocComponent(Docu onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)} > - {this.Document.links && DocListCast(this.Document.links).map((d, i) => - //this.linkEndpointDoc(d).type === DocumentType.PDFANNO ? (null) : + {this.Document.links && DocListCast(this.Document.links).filter(this.isNonTemporalLink).map((d, i) =>
)} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 08cb66d5f..6aad4a6be 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -669,6 +669,8 @@ export namespace Doc { return doc; } + export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; } + export function linkFollowUnhighlight() { Doc.UnhighlightAll(); document.removeEventListener("pointerdown", linkFollowUnhighlight); -- cgit v1.2.3-70-g09d2