diff options
Diffstat (limited to 'src/client/views')
4 files changed, 39 insertions, 46 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index ae5688b48..51cb9387a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -41,44 +41,41 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() setTimeout(action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. if (!linkDoc.linkAutoMove) return; - const acont = A.props.Document.type === DocumentType.LINK ? A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; - const bcont = B.props.Document.type === DocumentType.LINK ? B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; - const adiv = (acont.length ? acont[0] : A.ContentDiv); - const bdiv = (bcont.length ? bcont[0] : B.ContentDiv); + const acont = A.rootDoc.type === DocumentType.LINK ? A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const bcont = B.rootDoc.type === DocumentType.LINK ? B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const adiv = acont.length ? acont[0] : A.ContentDiv; + const bdiv = bcont.length ? bcont[0] : B.ContentDiv; const a = adiv.getBoundingClientRect(); const b = bdiv.getBoundingClientRect(); const { left: aleft, top: atop, width: awidth, height: aheight } = adiv.parentElement!.getBoundingClientRect(); const { left: bleft, top: btop, width: bwidth, height: bheight } = bdiv.parentElement!.getBoundingClientRect(); const apt = Utils.closestPtBetweenRectangles(aleft, atop, awidth, aheight, bleft, btop, bwidth, bheight, a.left + a.width / 2, a.top + a.height / 2); const bpt = Utils.closestPtBetweenRectangles(bleft, btop, bwidth, bheight, aleft, atop, awidth, aheight, apt.point.x, apt.point.y); - const afield = A.props.LayoutTemplateString?.indexOf("anchor1") === -1 ? "anchor2" : "anchor1"; - const bfield = afield === "anchor1" ? "anchor2" : "anchor1"; // really hacky stuff to make the LinkAnchorBox display where we want it to: - // if there's an element in the DOM with a classname containing the link's id and a data-targetids attribute containing the other end of the link, + // if there's an element in the DOM with a classname containing a link anchor's id, // then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right // otherwise, we just use the computed nearest point on the document boundary to the target Document - const linkEles = Array.from(window.document.getElementsByClassName(linkDoc[Id])); - const targetAhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes((linkDoc[afield] as Doc)[Id])); - const targetBhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes((linkDoc[bfield] as Doc)[Id])); + const targetAhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.anchor1 as Doc)[Id])).lastElement(); + const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.anchor2 as Doc)[Id])).lastElement(); if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return; - if (!targetBhyperlink) { - A.rootDoc[afield + "_x"] = (apt.point.x - aleft) / awidth * 100; - A.rootDoc[afield + "_y"] = (apt.point.y - atop) / aheight * 100; + if (!targetAhyperlink) { + linkDoc.anchor1_x = (apt.point.x - aleft) / awidth * 100; + linkDoc.anchor1_y = (apt.point.y - atop) / aheight * 100; } else { - const m = targetBhyperlink.getBoundingClientRect(); + const m = targetAhyperlink.getBoundingClientRect(); const mp = A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); - A.rootDoc[afield + "_x"] = Math.min(1, mp[0] / A.props.PanelWidth()) * 100; - A.rootDoc[afield + "_y"] = Math.min(1, mp[1] / A.props.PanelHeight()) * 100; + linkDoc.anchor1_x = Math.min(1, mp[0] / A.props.PanelWidth()) * 100; + linkDoc.anchor1_y = Math.min(1, mp[1] / A.props.PanelHeight()) * 100; } - if (!targetAhyperlink) { - B.rootDoc[bfield + "_x"] = (bpt.point.x - bleft) / bwidth * 100; - B.rootDoc[bfield + "_y"] = (bpt.point.y - btop) / bheight * 100; + if (!targetBhyperlink) { + linkDoc.anchor2_x = (bpt.point.x - bleft) / bwidth * 100; + linkDoc.anchor2_y = (bpt.point.y - btop) / bheight * 100; } else { - const m = targetAhyperlink.getBoundingClientRect(); + const m = targetBhyperlink.getBoundingClientRect(); const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); - B.rootDoc[bfield + "_x"] = Math.min(1, mp[0] / B.props.PanelWidth()) * 100; - B.rootDoc[bfield + "_y"] = Math.min(1, mp[1] / B.props.PanelHeight()) * 100; + linkDoc.anchor2_x = Math.min(1, mp[0] / B.props.PanelWidth()) * 100; + linkDoc.anchor2_y = Math.min(1, mp[1] / B.props.PanelHeight()) * 100; } } @@ -162,8 +159,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2; const pt1norm = clipped ? [0, 0] : [pt1vec[0] / pt1len * ptlen, pt1vec[1] / pt1len * ptlen]; const pt2norm = clipped ? [0, 0] : [pt2vec[0] / pt2len * ptlen, pt2vec[1] / pt2len * ptlen]; - const aActive = A.isSelected() || Doc.IsBrushed(A.props.Document); - const bActive = B.isSelected() || Doc.IsBrushed(B.props.Document); + const aActive = A.isSelected() || Doc.IsBrushed(A.rootDoc); + const bActive = B.isSelected() || Doc.IsBrushed(B.rootDoc); const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].linkOffsetX); const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].linkOffsetY); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 4dab8f15b..5e0b31754 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -3,32 +3,27 @@ import { observer } from "mobx-react"; import { Doc } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { Utils } from "../../../../Utils"; -import { DocumentType } from "../../../documents/DocumentTypes"; import { DocumentManager } from "../../../util/DocumentManager"; import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); +import { DocumentType } from "../../../documents/DocumentTypes"; @observer export class CollectionFreeFormLinksView extends React.Component { @computed get uniqueConnections() { - const connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => { - if (!drawnPairs.reduce((found, drawnPair) => { - const match1 = (connection.a === drawnPair.a && connection.b === drawnPair.b); - const match2 = (connection.a === drawnPair.b && connection.b === drawnPair.a); - const 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.filter(c => c.a.props.Document.type === DocumentType.LINK) - .map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />); + const connections = DocumentManager.Instance.LinkedDocumentViews + .filter(c => c.a.props.Document.type === DocumentType.LINK || c.b.props.Document.type === DocumentType.LINK) + .reduce((drawnPairs, connection) => { + const matchingPairs = drawnPairs.filter(pair => connection.a === pair.a && connection.b === pair.b); + matchingPairs.forEach(drawnPair => drawnPair.l.add(connection.l)); + if (!matchingPairs.length) drawnPairs.push({ a: connection.a, b: connection.b, l: new Set<Doc>([connection.l]) }); + return drawnPairs; + }, [] as { a: DocumentView, b: DocumentView, l: Set<Doc> }[]); + const set = new Map<Doc, { a: DocumentView, b: DocumentView, l: Doc[] }>(); + connections.map(c => !set.has(Array.from(c.l)[0]) && set.set(Array.from(c.l)[0], { a: c.a, b: c.b, l: Array.from(c.l) })); + return Array.from(set.values()).map(c => <CollectionFreeFormLinkView key={c.l[0][Id]} A={c.a} B={c.b} LinkDocs={c.l} />); } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 463e59bd1..bfdacdb45 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -759,18 +759,19 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if (this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null; if (this.layoutDoc.presBox || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return (null); - const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden); - return filtered.map((d, i) => + // need to use allLinks for RTF since embedded linked text anchors are not rendered with DocumentViews. All other documents render their anchors with nested DocumentViews so we just need to render the directLinks here + const filtered = DocUtils.FilterDocs(this.rootDoc.type === DocumentType.RTF ? this.allLinks : this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden); + return filtered.map((link, i) => <div className="documentView-anchorCont" key={i + 1}> <DocumentView {...this.props} - Document={d} + Document={link} PanelWidth={this.anchorPanelWidth} PanelHeight={this.anchorPanelHeight} dontRegisterView={false} styleProvider={this.anchorStyleProvider} removeDocument={this.hideLinkAnchor} LayoutTemplate={undefined} - LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(d, this.props.Document)}`)} /> + LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(link, this.rootDoc)}`)} /> </div >); } diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index d86dfd7b1..ca6c71ea3 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -134,7 +134,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch </div>} </div> ); - return <div className={`linkAnchorBox-cont${small ? "-small" : ""} ${this.rootDoc[Id]}`} + return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} onPointerEnter={action(e => LinkDocPreview.LinkInfo = { docprops: this.props, |
