From 8e9f77d93ec4393c52a215e75bcd9a362173e06a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jun 2020 16:24:37 -0400 Subject: made persistent link Icon in bottom left of document --- src/client/views/nodes/DocumentLinksButton.tsx | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/client/views/nodes/DocumentLinksButton.tsx (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx new file mode 100644 index 000000000..4f94b06cb --- /dev/null +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -0,0 +1,75 @@ +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { computed, action, runInAction, observable } from "mobx"; +import { observer } from "mobx-react"; +import './DocumentLinksButton.scss'; +import React = require("react"); +import { emptyFunction, setupMoveUpEvents } from "../../../Utils"; +import { DocListCast, Doc } from "../../../fields/Doc"; +import { DocumentView } from "./DocumentView"; +import { LinkMenu } from "../linking/LinkMenu"; +import { UndoManager } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; + +interface DocumentLinksButtonProps { + View: DocumentView; +} +@observer +export class DocumentLinksButton extends React.Component { + private _linkButton = React.createRef(); + + @action + onLinkButtonMoved = (e: PointerEvent) => { + if (this._linkButton.current !== null) { + const linkDrag = UndoManager.StartBatch("Drag Link"); + this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View.props.Document, e.pageX, e.pageY, { + dragComplete: dropEv => { + const linkDoc = dropEv.linkDragData?.linkDocument as Doc; // equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop + if (this.props.View && linkDoc) { + !linkDoc.linkRelationship && (Doc.GetProto(linkDoc).linkRelationship = "hyperlink"); + + // we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks) + // the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures + // however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView + // The documentView passes a function prop returning this link doc to its descendants who can react to changes to it. + dropEv.linkDragData?.linkDropCallback?.(dropEv.linkDragData); + runInAction(() => this.props.View._link = linkDoc); + setTimeout(action(() => this.props.View._link = undefined), 0); + } + linkDrag?.end(); + }, + hideSource: false + }); + return true; + } + return false; + } + + onLinkButtonDown = (e: React.PointerEvent): void => { + setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e) => { + DocumentLinksButton.EditLink = this.props.View; + DocumentLinksButton.EditLinkLoc = [e.clientX, e.clientY]; + })); + } + + @observable + public static EditLink: DocumentView | undefined; + public static EditLinkLoc: number[] = [0, 0]; + + @computed + get linkButton() { + const view0 = this.props.View; + const linkCount = view0 && DocListCast(view0.props.Document.links).length; + return !view0 || !linkCount ? (null) : +
+
+ {linkCount ? linkCount : } +
+
; + } + render() { + return this.linkButton; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From fe6da65c9ac7ff797a2e0b6047bef2656463c008 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jun 2020 16:58:07 -0400 Subject: added halo for link buttons --- src/client/views/nodes/DocumentLinksButton.tsx | 23 ++++++++++------------- src/client/views/nodes/DocumentView.tsx | 12 +++++++++++- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 4f94b06cb..8ab3aed00 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -1,14 +1,12 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { computed, action, runInAction, observable } from "mobx"; +import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import './DocumentLinksButton.scss'; -import React = require("react"); +import { Doc, DocListCast } from "../../../fields/Doc"; import { emptyFunction, setupMoveUpEvents } from "../../../Utils"; -import { DocListCast, Doc } from "../../../fields/Doc"; -import { DocumentView } from "./DocumentView"; -import { LinkMenu } from "../linking/LinkMenu"; -import { UndoManager } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; +import { UndoManager } from "../../util/UndoManager"; +import './DocumentLinksButton.scss'; +import { DocumentView } from "./DocumentView"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -60,12 +58,11 @@ export class DocumentLinksButton extends React.Component -
- {linkCount ? linkCount : } +
+ {links.length}
; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d9a211e7a..20a606937 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -584,10 +584,14 @@ export class DocumentView extends DocComponent(Docu toggleLinkButtonBehavior = (): void => { if (this.Document.isLinkButton || this.layoutDoc.onClick || this.Document.ignoreClick) { this.Document.isLinkButton = false; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = false); this.Document.ignoreClick = false; this.layoutDoc.onClick = undefined; } else { this.Document.isLinkButton = true; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = true); this.Document.followLinkZoom = false; this.Document.followLinkLocation = undefined; } @@ -597,8 +601,12 @@ export class DocumentView extends DocComponent(Docu toggleFollowInPlace = (): void => { if (this.Document.isLinkButton) { this.Document.isLinkButton = false; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = false); } else { this.Document.isLinkButton = true; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = true); this.Document.followLinkZoom = true; this.Document.followLinkLocation = "inPlace"; } @@ -608,6 +616,8 @@ export class DocumentView extends DocComponent(Docu toggleFollowOnRight = (): void => { if (this.Document.isLinkButton) { this.Document.isLinkButton = false; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = false); } else { this.Document.isLinkButton = true; this.Document.followLinkZoom = false; @@ -1192,7 +1202,7 @@ export class DocumentView extends DocComponent(Docu color: StrCast(this.layoutDoc.color, "inherit"), outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, - boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, + boxShadow: this.Document.isLinkButton ? StrCast(this.props.Document._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, background: finalColor, opacity: finalOpacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), -- cgit v1.2.3-70-g09d2 From 4ee4b611c6d6732377f2f9160237118847fca92b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jun 2020 18:49:25 -0400 Subject: added ability to start a link & finish a link with double click --- src/client/views/DocumentButtonBar.tsx | 29 ++++++++++++------ src/client/views/GlobalKeyHandler.ts | 2 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.scss | 14 ++++++++- src/client/views/nodes/DocumentLinksButton.tsx | 35 +++++++++++++++++----- 5 files changed, 64 insertions(+), 18 deletions(-) (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 208b4d57a..8cd1b650e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,28 +1,28 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowAltCircleDown, faPhotoVideo, faArrowAltCircleUp, faArrowAltCircleRight, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../fields/Doc"; import { RichTextField } from '../../fields/RichTextField'; -import { NumCast, StrCast, Cast } from "../../fields/Types"; +import { Cast, NumCast } from "../../fields/Types"; import { emptyFunction, setupMoveUpEvents } from "../../Utils"; +import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; +import { Docs, DocUtils } from '../documents/Documents'; +import { DragManager } from '../util/DragManager'; import { UndoManager } from "../util/UndoManager"; import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView'; import { ParentDocSelector } from './collections/ParentDocumentSelector'; import './collections/ParentDocumentSelector.scss'; import './DocumentButtonBar.scss'; -import { LinkMenu } from "./linking/LinkMenu"; +import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentView } from './nodes/DocumentView'; import { GoogleRef } from "./nodes/formattedText/FormattedTextBox"; import { TemplateMenu } from "./TemplateMenu"; import { Template, Templates } from "./Templates"; import React = require("react"); -import { DragManager } from '../util/DragManager'; -import { MetadataEntryMenu } from './MetadataEntryMenu'; -import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; -import { Docs } from '../documents/Documents'; +import { DocumentLinksButton } from './nodes/DocumentLinksButton'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -142,7 +142,16 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV onLinkButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, emptyFunction); + setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, (e, doubleTap) => { + if (doubleTap) { + if (!DocumentLinksButton.StartLink) { + runInAction(() => DocumentLinksButton.StartLink = this.view0); + } else { + DocumentLinksButton.StartLink !== this.view0 && this.view0 && + DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.view0.props.Document }, "long drag"); + } + } + }); } @@ -242,7 +251,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV return !view0 || linkCount ? (null) :
-
+
{linkCount ? linkCount : }
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 27755737e..7bc8cf6a7 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -19,6 +19,7 @@ import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView"; import { DocumentDecorations } from "./DocumentDecorations"; import { MainView } from "./MainView"; import { DocumentView } from "./nodes/DocumentView"; +import { DocumentLinksButton } from "./nodes/DocumentLinksButton"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -77,6 +78,7 @@ export default class KeyManager { // MarqueeView.DragMarquee = !MarqueeView.DragMarquee; // bcz: this needs a better disclosure UI break; case "escape": + DocumentLinksButton.StartLink = undefined; const main = MainView.Instance; Doc.SetSelectedTool(InkTool.None); if (main.isPointerDown) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3a8778c14..eddc225b1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -245,7 +245,7 @@ export class CollectionFreeFormView extends CollectionSubView { - setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e) => { - DocumentLinksButton.EditLink = this.props.View; - DocumentLinksButton.EditLinkLoc = [e.clientX, e.clientY]; + setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => { + if (doubleTap) { + DocumentLinksButton.StartLink = this.props.View; + } else { + DocumentLinksButton.EditLink = this.props.View; + DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY]; + } + })); + } + completeLink = (e: React.PointerEvent): void => { + setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e, doubleTap) => { + if (doubleTap) { + if (DocumentLinksButton.StartLink === this.props.View) { + DocumentLinksButton.StartLink = undefined; + } else { + DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View && + DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); + } + } })); } @@ -59,11 +78,13 @@ export class DocumentLinksButton extends React.Component + return !links.length || links[0].hidden ? (null) : +
- {links.length} + {links.length ? links.length : }
+ {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ?
: (null)} + {DocumentLinksButton.StartLink === this.props.View ?
: (null)}
; } render() { -- cgit v1.2.3-70-g09d2 From ba42ca25ae828b6279f618dea87f7cd37a3b3814 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 25 Jun 2020 00:19:40 -0400 Subject: added link preview for blue buttons. --- src/client/util/DragManager.ts | 2 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/MainView.tsx | 4 + src/client/views/nodes/DocumentLinksButton.scss | 28 ++----- src/client/views/nodes/DocumentLinksButton.tsx | 15 +++- src/client/views/nodes/DocumentView.tsx | 10 ++- src/client/views/nodes/LinkAnchorBox.tsx | 8 ++ src/client/views/nodes/LinkDocPreview.tsx | 107 ++++++++++++++++++++++++ 8 files changed, 148 insertions(+), 28 deletions(-) create mode 100644 src/client/views/nodes/LinkDocPreview.tsx (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 91bc51101..417ddf989 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -353,7 +353,7 @@ export namespace DragManager { const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; const rect = ele.getBoundingClientRect(); const scaleX = rect.width / ele.offsetWidth, - scaleY = rect.height / ele.offsetHeight; + scaleY = ele.offsetHeight ? rect.height / ele.offsetHeight : scaleX; elesCont.left = Math.min(rect.left, elesCont.left); elesCont.top = Math.min(rect.top, elesCont.top); elesCont.right = Math.max(rect.right, elesCont.right); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 8cd1b650e..106b7163e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -248,7 +248,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get linkButton() { const view0 = this.view0; const linkCount = view0 && DocListCast(view0.props.Document.links).length; - return !view0 || linkCount ? (null) : + return !view0 ? (null) :
{DocumentLinksButton.EditLink ? : (null)} + {LinkDocPreview.LinkInfo ? : (null)} diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index b4c59b91c..79364ab8e 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -1,21 +1,9 @@ @import "../globalCssVariables.scss"; -.documentLinksButton-button-empty:hover { - background: $main-accent; - transform: scale(1.05); - cursor: pointer; -} - -.documentLinksButton-button-nonempty:hover { - background: $main-accent; - transform: scale(1.05); - cursor: pointer; -} - -.documentLinksButton-button, -.documentLinksButton-button-empty, -.documentLinksButton-button-nonempty { +.documentLinksButton, +.documentLinksButton-endLink, +.documentLinksButton-startLink { height: 20px; width: 20px; left: -15px; @@ -34,18 +22,18 @@ align-items: center; &:hover { - background: $main-accent; + background: deepskyblue; transform: scale(1.05); - cursor: pointer; + cursor: default; } } -.documentLinksButton-button-nonempty { +.documentLinksButton { background-color: $link-color; } -.documentLinksButton-button-empty { +.documentLinksButton-endLink { border: red solid 2px; } -.documentLinksButton-button { +.documentLinksButton-startLink { border: red solid 2px; background-color: rgba(255, 192, 203, 0.5); } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index c9083a65f..fc314ae8b 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -9,6 +9,7 @@ import { DocumentView } from "./DocumentView"; import React = require("react"); import { DocUtils } from "../../documents/Documents"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { LinkDocPreview } from "./LinkDocPreview"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -80,11 +81,19 @@ export class DocumentLinksButton extends React.Component -
+
LinkDocPreview.LinkInfo = undefined)} + onPointerEnter={action(e => LinkDocPreview.LinkInfo = { + addDocTab: this.props.View.props.addDocTab, + linkSrc: this.props.View.props.Document, + linkDoc: links[0], + Location: [e.clientX, e.clientY + 20] + })} > {links.length ? links.length : }
- {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ?
: (null)} - {DocumentLinksButton.StartLink === this.props.View ?
: (null)} + {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ?
: (null)} + {DocumentLinksButton.StartLink === this.props.View ?
: (null)}
; } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 20a606937..4cb08bab3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1047,7 +1047,7 @@ export class DocumentView extends DocComponent(Docu onClick={this.onClickHandler} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.showLinks ? this.anchors : (null)} - {this.props.forcedBackgroundColor?.(this.Document) === "transparent" ? (null) : } + {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.props.dontRegisterView ? (null) : }
); } @@ -1071,7 +1071,7 @@ export class DocumentView extends DocComponent(Docu anchorPanelHeight = () => this.props.PanelHeight() || 1; @computed get anchors() { TraceMobx(); - return this.layoutDoc.presBox ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => + return this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.presBox || this.props.dontRegisterView ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => (Docu PanelWidth={this.anchorPanelWidth} PanelHeight={this.anchorPanelHeight} ContentScaling={returnOne} + dontRegisterView={false} forcedBackgroundColor={returnTransparent} removeDocument={this.hideLinkAnchor} pointerEvents={false} @@ -1202,7 +1203,10 @@ export class DocumentView extends DocComponent(Docu color: StrCast(this.layoutDoc.color, "inherit"), outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, - boxShadow: this.Document.isLinkButton ? StrCast(this.props.Document._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, + boxShadow: this.Document.isLinkButton && !this.props.dontRegisterView && this.props.forcedBackgroundColor?.(this.Document) !== "transparent" ? + StrCast(this.props.Document._linkButtonShadow, "lightblue 0em 0em 1em") : + this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : + undefined, background: finalColor, opacity: finalOpacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 2b64cdab6..2bcc6168b 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -18,6 +18,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SelectionManager } from "../../util/SelectionManager"; import { TraceMobx } from "../../../fields/util"; import { Id } from "../../../fields/FieldSymbols"; +import { LinkDocPreview } from "./LinkDocPreview"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -132,6 +133,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent LinkDocPreview.LinkInfo = undefined)} + onPointerEnter={action(e => LinkDocPreview.LinkInfo = { + addDocTab: this.props.addDocTab, + linkSrc: this.props.ContainingCollectionDoc!, + linkDoc: this.rootDoc, + Location: [e.clientX, e.clientY + 20] + })} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu} ref={this._ref} style={{ background: c, diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx new file mode 100644 index 000000000..126dc240a --- /dev/null +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -0,0 +1,107 @@ +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from "mobx-react"; +import wiki from "wikijs"; +import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { Cast, FieldValue, NumCast } from "../../../fields/Types"; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils"; +import { Docs } from "../../documents/Documents"; +import { DocumentManager } from "../../util/DocumentManager"; +import { Transform } from "../../util/Transform"; +import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; +import React = require("react"); +import { DocumentView } from './DocumentView'; + +interface Props { + linkDoc?: Doc; + linkSrc?: Doc; + href?: string; + backgroundColor: (doc: Doc) => string; + addDocTab: (document: Doc, where: string) => boolean; + location: number[]; +} +@observer +export class LinkDocPreview extends React.Component { + @observable public static LinkInfo: Opt<{ linkDoc?: Doc; addDocTab: (document: Doc, where: string) => boolean, linkSrc: Doc; href?: string; Location: number[] }>; + @observable _targetDoc: Opt; + @observable _toolTipText = ""; + + componentDidUpdate() { this.updatePreview() } + componentDidMount() { this.updatePreview() } + async updatePreview() { + const linkDoc = this.props.linkDoc; + const linkSrc = this.props.linkSrc; + if (this.props.href) { + if (this.props.href.startsWith("https://en.wikipedia.org/wiki/")) { + wiki().page(this.props.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500)))); + } else { + runInAction(() => this._toolTipText = "external => " + this.props.href); + } + } else if (linkDoc && linkSrc) { + const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), linkSrc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); + const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; + runInAction(() => { + this._toolTipText = ""; + this._targetDoc = target; + if (anchor !== this._targetDoc && anchor && this._targetDoc) { + this._targetDoc._scrollY = NumCast(anchor?.y); + } + }); + } + } + pointerDown = (e: React.PointerEvent) => { + if (this.props.linkDoc && this.props.linkSrc) { + DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.linkSrc, + (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } else if (this.props.href) { + this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, UseCors: true }), "onRight"); + } + } + width = () => Math.min(350, NumCast(this._targetDoc?.[WidthSym](), 350)); + height = () => Math.min(350, NumCast(this._targetDoc?.[HeightSym](), 350)); + @computed get targetDocView() { + return !this._targetDoc ? +
+
+ {this._toolTipText} +
+
: + ; + } + + render() { + return
+ {this.targetDocView} +
; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From c692276b6c6909d6cf32b620eb69b114057662ca Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 25 Jun 2020 00:57:56 -0400 Subject: cleaned up DoucmentButtonBar to use DocumentLinksButton --- src/client/views/DocumentButtonBar.tsx | 62 ++----------------------- src/client/views/nodes/DocumentLinksButton.scss | 1 - src/client/views/nodes/DocumentLinksButton.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 6 insertions(+), 62 deletions(-) (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 106b7163e..49c15f764 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -113,48 +113,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get view0() { return this.props.views()?.[0]; } - @action - onLinkButtonMoved = (e: PointerEvent) => { - if (this._linkButton.current !== null) { - const linkDrag = UndoManager.StartBatch("Drag Link"); - this.view0 && DragManager.StartLinkDrag(this._linkButton.current, this.view0.props.Document, e.pageX, e.pageY, { - dragComplete: dropEv => { - const linkDoc = dropEv.linkDragData?.linkDocument as Doc; // equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop - if (this.view0 && linkDoc) { - !linkDoc.linkRelationship && (Doc.GetProto(linkDoc).linkRelationship = "hyperlink"); - - // we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks) - // the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures - // however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView - // The documentView passes a function prop returning this link doc to its descendants who can react to changes to it. - dropEv.linkDragData?.linkDropCallback?.(dropEv.linkDragData); - runInAction(() => this.view0!._link = linkDoc); - setTimeout(action(() => this.view0!._link = undefined), 0); - } - linkDrag?.end(); - }, - hideSource: false - }); - return true; - } - return false; - } - - - onLinkButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, (e, doubleTap) => { - if (doubleTap) { - if (!DocumentLinksButton.StartLink) { - runInAction(() => DocumentLinksButton.StartLink = this.view0); - } else { - DocumentLinksButton.StartLink !== this.view0 && this.view0 && - DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.view0.props.Document }, "long drag"); - } - } - }); - } - - @computed get considerGoogleDocsPush() { const targetDoc = this.view0?.props.Document; @@ -244,22 +202,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
; } - @computed - get linkButton() { - const view0 = this.view0; - const linkCount = view0 && DocListCast(view0.props.Document.links).length; - return !view0 ? (null) : -
-
-
- {linkCount ? linkCount : } -
-
-
; - } - @computed get metadataButton() { const view0 = this.view0; @@ -328,7 +270,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPull = isText && this.considerGoogleDocsPull; const considerPush = isText && this.considerGoogleDocsPush; return
- {this.linkButton} +
+ +
{this.templateButton}
diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index 79364ab8e..484f8c469 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -6,7 +6,6 @@ .documentLinksButton-startLink { height: 20px; width: 20px; - left: -15px; position: absolute; border-radius: 50%; opacity: 0.9; diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index fc314ae8b..ef900fff6 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -16,6 +16,7 @@ export const Flyout = higflyout.default; interface DocumentLinksButtonProps { View: DocumentView; + Offset?: number[]; } @observer export class DocumentLinksButton extends React.Component { @@ -80,7 +81,7 @@ export class DocumentLinksButton extends React.Component +
LinkDocPreview.LinkInfo = undefined)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4cb08bab3..8f139e39e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1047,7 +1047,7 @@ export class DocumentView extends DocComponent(Docu onClick={this.onClickHandler} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.showLinks ? this.anchors : (null)} - {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.props.dontRegisterView ? (null) : } + {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.props.dontRegisterView ? (null) : }
); } -- cgit v1.2.3-70-g09d2 From d0e20b86d1236f99f58b0241b61af15e39561c66 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 25 Jun 2020 12:23:42 -0400 Subject: fixed blue button visibility for document decoration button bar --- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 49c15f764..fcaea0f0b 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -271,7 +271,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPush = isText && this.considerGoogleDocsPush; return
- +
{this.templateButton} diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index ef900fff6..f35b48ce4 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -17,6 +17,7 @@ export const Flyout = higflyout.default; interface DocumentLinksButtonProps { View: DocumentView; Offset?: number[]; + AlwaysOn?: boolean; } @observer export class DocumentLinksButton extends React.Component { @@ -80,7 +81,7 @@ export class DocumentLinksButton extends React.Component
Date: Thu, 25 Jun 2020 14:29:27 -0400 Subject: fixed linkicon dragging feedback --- src/client/views/nodes/DocumentLinksButton.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/DocumentLinksButton.tsx') diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index f35b48ce4..4f4f12521 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -82,16 +82,16 @@ export class DocumentLinksButton extends React.Component +
LinkDocPreview.LinkInfo = undefined)} - onPointerEnter={action(e => LinkDocPreview.LinkInfo = { + onPointerEnter={action(e => links.length && (LinkDocPreview.LinkInfo = { addDocTab: this.props.View.props.addDocTab, linkSrc: this.props.View.props.Document, linkDoc: links[0], Location: [e.clientX, e.clientY + 20] - })} > + }))} > {links.length ? links.length : }
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ?
: (null)} -- cgit v1.2.3-70-g09d2