aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/MainView.tsx56
-rw-r--r--src/client/views/linking/LinkMenu.tsx9
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx4
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx30
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx21
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx107
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx120
8 files changed, 246 insertions, 103 deletions
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index c05ca33fb..d544e13eb 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 <div className="documentButtonBar">
<div className="documentButtonBar-button">
- <DocumentLinksButton View={this.view0} AlwaysOn={true} />
+ <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} />
</div>
<div className="documentButtonBar-button">
{this.templateButton}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 200486279..da76bed11 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -65,7 +65,7 @@ export class MainView extends React.Component {
public static Instance: MainView;
private _buttonBarHeight = 36;
private _flyoutSizeOnDown = 0;
- private _urlState: HistoryUtil.DocUrl;
+ private static _urlState: HistoryUtil.DocUrl;
private _docBtnRef = React.createRef<HTMLDivElement>();
private _mainViewRef = React.createRef<HTMLDivElement>();
@@ -73,12 +73,12 @@ export class MainView extends React.Component {
@observable private _panelHeight: number = 0;
@observable private _flyoutTranslate: boolean = true;
@observable public flyoutWidth: number = 250;
- private get darkScheme() { return BoolCast(Cast(this.userDoc?.activeWorkspace, Doc, null)?.darkScheme); }
+ private get darkScheme() { return BoolCast(Cast(MainView.userDoc?.activeWorkspace, Doc, null)?.darkScheme); }
- @computed private get userDoc() { return Doc.UserDoc(); }
- @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
+ @computed private static get userDoc() { return Doc.UserDoc(); }
+ @computed private get mainContainer() { return MainView.userDoc ? FieldValue(Cast(MainView.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
@computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
- @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; }
+ @computed public get sidebarButtonsDoc() { return Cast(MainView.userDoc["tabs-buttons"], Doc) as Doc; }
public isPointerDown = false;
@@ -119,7 +119,7 @@ export class MainView extends React.Component {
constructor(props: Readonly<{}>) {
super(props);
MainView.Instance = this;
- this._urlState = HistoryUtil.parseUrl(window.location) || {} as any;
+ MainView._urlState = HistoryUtil.parseUrl(window.location) || {} as any;
// causes errors to be generated when modifying an observable outside of an action
configure({ enforceActions: "observed" });
if (window.location.pathname !== "/home") {
@@ -128,7 +128,7 @@ export class MainView extends React.Component {
const type = pathname[0];
if (type === "doc") {
CurrentUserUtils.MainDocId = pathname[1];
- if (!this.userDoc) {
+ if (!MainView.userDoc) {
runInAction(() => this.flyoutWidth = 0);
DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt<Field>) =>
field instanceof Doc && (CurrentUserUtils.GuestTarget = field)));
@@ -172,14 +172,14 @@ export class MainView extends React.Component {
initAuthenticationRouters = async () => {
// Load the user's active workspace, or create a new one if initial session after signup
const received = CurrentUserUtils.MainDocId;
- if (received && !this.userDoc) {
+ if (received && !MainView.userDoc) {
reaction(
() => CurrentUserUtils.GuestTarget,
target => target && this.createNewWorkspace(),
{ fireImmediately: true }
);
} else {
- if (received && this._urlState.sharing) {
+ if (received && MainView._urlState.sharing) {
reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized,
initialized => initialized && received && DocServer.GetRefField(received).then(docField => {
if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) {
@@ -188,9 +188,9 @@ export class MainView extends React.Component {
}),
);
}
- const doc = this.userDoc && await Cast(this.userDoc.activeWorkspace, Doc);
+ const doc = MainView.userDoc && await Cast(MainView.userDoc.activeWorkspace, Doc);
if (doc) {
- this.openWorkspace(doc);
+ MainView.openWorkspace(doc);
} else {
this.createNewWorkspace();
}
@@ -199,7 +199,7 @@ export class MainView extends React.Component {
@action
createNewWorkspace = async (id?: string) => {
- const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc;
+ const workspaces = Cast(MainView.userDoc.myWorkspaces, Doc) as Doc;
const workspaceCount = DocListCast(workspaces.data).length + 1;
const freeformOptions: DocumentOptions = {
x: 0,
@@ -219,19 +219,19 @@ export class MainView extends React.Component {
Doc.AddDocToList(workspaces, "data", workspaceDoc);
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
- setTimeout(() => this.openWorkspace(workspaceDoc), 0);
+ setTimeout(() => MainView.openWorkspace(workspaceDoc), 0);
}
@action
- openWorkspace = (doc: Doc, fromHistory = false) => {
+ static openWorkspace = (doc: Doc, fromHistory = false) => {
CurrentUserUtils.MainDocId = doc[Id];
if (doc) { // this has the side-effect of setting the main container since we're assigning the active/guest workspace
!("presentationView" in doc) && (doc.presentationView = new List<Doc>([Docs.Create.TreeDocument([], { title: "Presentation" })]));
- this.userDoc ? (this.userDoc.activeWorkspace = doc) : (CurrentUserUtils.GuestWorkspace = doc);
+ MainView.userDoc ? (MainView.userDoc.activeWorkspace = doc) : (CurrentUserUtils.GuestWorkspace = doc);
}
- const state = this._urlState;
- if (state.sharing === true && !this.userDoc) {
+ const state = MainView._urlState;
+ if (state.sharing === true && !MainView.userDoc) {
DocServer.Control.makeReadOnly();
} else {
fromHistory || HistoryUtil.pushState({
@@ -257,7 +257,7 @@ export class MainView extends React.Component {
}
// if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized)
setTimeout(async () => {
- const col = this.userDoc && await Cast(this.userDoc.rightSidebarCollection, Doc);
+ const col = MainView.userDoc && await Cast(MainView.userDoc.rightSidebarCollection, Doc);
col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col);
}, 100);
return true;
@@ -305,7 +305,7 @@ export class MainView extends React.Component {
DataDoc={undefined}
LibraryPath={emptyPath}
addDocument={undefined}
- addDocTab={this.addDocTabFunc}
+ addDocTab={MainView.addDocTabFunc}
pinToPres={emptyFunction}
rootSelected={returnTrue}
onClick={undefined}
@@ -378,16 +378,16 @@ export class MainView extends React.Component {
document.removeEventListener("pointerup", this.onPointerUp);
}
flyoutWidthFunc = () => this.flyoutWidth;
- addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
+ static addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
- doc.dockingConfig ? this.openWorkspace(doc) :
+ doc.dockingConfig ? MainView.openWorkspace(doc) :
CollectionDockingView.AddRightSplit(doc, libraryPath);
}
sidebarScreenToLocal = () => new Transform(0, RichTextMenu.Instance.Pinned ? -35 : 0, 1);
mainContainerXf = () => this.sidebarScreenToLocal().translate(0, -this._buttonBarHeight);
@computed get flyout() {
- const sidebarContent = this.userDoc?.["tabs-panelContainer"];
+ const sidebarContent = MainView.userDoc?.["tabs-panelContainer"];
if (!(sidebarContent instanceof Doc)) {
return (null);
}
@@ -399,7 +399,7 @@ export class MainView extends React.Component {
LibraryPath={emptyPath}
addDocument={undefined}
rootSelected={returnTrue}
- addDocTab={this.addDocTabFunc}
+ addDocTab={MainView.addDocTabFunc}
pinToPres={emptyFunction}
removeDocument={undefined}
onClick={undefined}
@@ -425,7 +425,7 @@ export class MainView extends React.Component {
DataDoc={undefined}
LibraryPath={emptyPath}
addDocument={undefined}
- addDocTab={this.addDocTabFunc}
+ addDocTab={MainView.addDocTabFunc}
pinToPres={emptyFunction}
NativeHeight={returnZero}
NativeWidth={returnZero}
@@ -459,8 +459,8 @@ export class MainView extends React.Component {
}
@computed get mainContent() {
- const sidebar = this.userDoc?.["tabs-panelContainer"];
- return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
+ const sidebar = MainView.userDoc?.["tabs-panelContainer"];
+ return !MainView.userDoc || !(sidebar instanceof Doc) ? (null) : (
<div className="mainView-mainContent" style={{
color: this.darkScheme ? "rgb(205,205,205)" : "black",
height: RichTextMenu.Instance?.Pinned ? `calc(100% - ${ANTIMODEMENU_HEIGHT})` : "100%"
@@ -531,7 +531,7 @@ export class MainView extends React.Component {
moveDocument={this.moveButtonDoc}
CollectionView={undefined}
addDocument={this.addButtonDoc}
- addDocTab={this.addDocTabFunc}
+ addDocTab={MainView.addDocTabFunc}
pinToPres={emptyFunction}
removeDocument={this.remButtonDoc}
onClick={undefined}
@@ -628,5 +628,5 @@ Scripting.addGlobal(function copyWorkspace() {
const workspaces = Cast(Doc.UserDoc().myWorkspaces, Doc, null);
Doc.AddDocToList(workspaces, "data", copiedWorkspace);
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
- setTimeout(() => MainView.Instance.openWorkspace(copiedWorkspace), 0);
+ setTimeout(() => MainView.openWorkspace(copiedWorkspace), 0);
});
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 0fcc0f0b9..9fd2b98b1 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -28,9 +28,13 @@ export class LinkMenu extends React.Component<Props> {
@action
onClick = (e: PointerEvent) => {
- if (!Array.from(this._linkMenuRef?.getElementsByTagName((e.target as HTMLElement).tagName) || []).includes(e.target as any)) {
+ if (this._linkMenuRef && !Array.from(this._linkMenuRef?.getElementsByTagName((e.target as HTMLElement).tagName) || []).includes(e.target as any)) {
DocumentLinksButton.EditLink = undefined;
}
+
+ // if (this._linkMenuRef && !this._linkMenuRef.contains(e.target)) {
+ // DocumentLinksButton.EditLink = undefined;
+ // }
}
@action
componentDidMount() {
@@ -70,7 +74,8 @@ export class LinkMenu extends React.Component<Props> {
render() {
const sourceDoc = this.props.docView.props.Document;
const groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc);
- return <div className="linkMenu-list" ref={(r) => this._linkMenuRef = r} style={{ left: this.props.location[0], top: this.props.location[1] }}>
+ return <div className="linkMenu-list"
+ ref={(r) => this._linkMenuRef = r} style={{ left: this.props.location[0], top: this.props.location[1] }}>
{!this._editingLink ?
this.renderAllGroups(groups) :
<LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)} />
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 89deb3a55..7892d381b 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -80,11 +80,11 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
return (
<div className="linkMenu-group">
- <div className="linkMenu-group-name">
+ {/* <div className="linkMenu-group-name">
<p ref={this._drag} onPointerDown={this.onLinkButtonDown}
className={this.props.groupType === "*" || this.props.groupType === "" ? "" : "expand-one"} > {this.props.groupType}:</p>
{this.props.groupType === "*" || this.props.groupType === "" ? <></> : this.viewGroupAsTable(this.props.groupType)}
- </div>
+ </div> */}
<div className="linkMenu-group-wrapper">
{groupItems}
</div>
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index edc18b6a9..d5d31d1ba 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -13,6 +13,8 @@ import React = require("react");
import { DocumentManager } from '../../util/DocumentManager';
import { setupMoveUpEvents, emptyFunction } from '../../../Utils';
import { DocumentView } from '../nodes/DocumentView';
+import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
+import { LinkDocPreview } from '../nodes/LinkDocPreview';
library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp);
@@ -124,7 +126,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
e.stopPropagation();
}
+ @action
onContextMenu = (e: React.MouseEvent) => {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
e.preventDefault();
ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => this.followDefault(), icon: "arrow-right" });
ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
@@ -132,9 +137,19 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
@action.bound
async followDefault() {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false);
}
+ @action
+ deleteLink = (): void => {
+ LinkManager.Instance.deleteLink(this.props.linkDoc);
+ //this.props.showLinks();
+ LinkDocPreview.LinkInfo = undefined;
+ DocumentLinksButton.EditLink = undefined;
+ }
+
render() {
const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
const canExpand = keys ? keys.length > 0 : false;
@@ -142,12 +157,23 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
return (
<div className="linkMenu-item">
<div className={canExpand ? "linkMenu-item-content expand-three" : "linkMenu-item-content expand-two"}>
- <div ref={this._drag} className="linkMenu-name" title="drag to view target. click to customize." onPointerDown={this.onLinkButtonDown}>
+ <div ref={this._drag} className="linkMenu-name" title="drag to view target. click to customize."
+ onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)}
+ onPointerEnter={action(e => this.props.linkDoc && (LinkDocPreview.LinkInfo = {
+ addDocTab: this.props.addDocTab,
+ linkSrc: this.props.sourceDoc,
+ linkDoc: this.props.linkDoc,
+ Location: [e.clientX, e.clientY + 20]
+ }))}
+ onPointerDown={this.onLinkButtonDown}>
<p >{StrCast(this.props.destinationDoc.title)}</p>
<div className="linkMenu-item-buttons">
{canExpand ? <div title="Show more" className="button" onPointerDown={e => this.toggleShowMore(e)}>
<FontAwesomeIcon className="fa-icon" icon={this._showMore ? "chevron-up" : "chevron-down"} size="sm" /></div> : <></>}
- <div title="Edit link" className="button" ref={this._editRef} onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
+
+ {/* <div title="Edit link" className="button" ref={this._editRef} onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div> */}
+ <div title="Delete link" className="button" ref={this._editRef} onPointerDown={this.deleteLink}>
+ <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div>
<div title="Follow link" className="button" onClick={this.followDefault} onContextMenu={this.onContextMenu}>
<FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" />
</div>
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 4f4f12521..c625c4cd6 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -18,6 +18,7 @@ interface DocumentLinksButtonProps {
View: DocumentView;
Offset?: number[];
AlwaysOn?: boolean;
+ InMenu?: boolean;
}
@observer
export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
@@ -52,10 +53,11 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
@observable static StartLink: DocumentView | undefined;
onLinkButtonDown = (e: React.PointerEvent): void => {
+
setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => {
if (doubleTap) {
DocumentLinksButton.StartLink = this.props.View;
- } else {
+ } else if (!!!this.props.InMenu) {
DocumentLinksButton.EditLink = this.props.View;
DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY];
}
@@ -85,14 +87,15 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
<div title="Drag(create link) Tap(view links)" ref={this._linkButton} style={{ minWidth: 20, minHeight: 20, position: "absolute", left: this.props.Offset?.[0] }}>
<div className={"documentLinksButton"} style={{ backgroundColor: DocumentLinksButton.StartLink ? "transparent" : "" }}
onPointerDown={this.onLinkButtonDown}
- onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)}
- 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 : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />}
+ // onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)}
+ // 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 && !!!this.props.InMenu ? links.length : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />}
</div>
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} onPointerDown={this.completeLink} /> : (null)}
{DocumentLinksButton.StartLink === this.props.View ? <div className={"documentLinksButton-startLink"} /> : (null)}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 92b443d3b..1d2c022a7 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -10,6 +10,11 @@ import { Transform } from "../../util/Transform";
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import React = require("react");
import { DocumentView } from './DocumentView';
+import { sortAndDeduplicateDiagnostics } from 'typescript';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { LinkManager } from '../../util/LinkManager';
+import { DocumentLinksButton } from './DocumentLinksButton';
+import { ContextMenu } from '../ContextMenu';
interface Props {
linkDoc?: Doc;
@@ -24,6 +29,31 @@ export class LinkDocPreview extends React.Component<Props> {
@observable public static LinkInfo: Opt<{ linkDoc?: Doc; addDocTab: (document: Doc, where: string) => boolean, linkSrc: Doc; href?: string; Location: number[] }>;
@observable _targetDoc: Opt<Doc>;
@observable _toolTipText = "";
+ _editRef = React.createRef<HTMLDivElement>();
+
+ @action
+ deleteLink = (): void => {
+ this.props.linkDoc ? LinkManager.Instance.deleteLink(this.props.linkDoc) : null;
+ //this.props.showLinks();
+ LinkDocPreview.LinkInfo = undefined;
+ DocumentLinksButton.EditLink = undefined;
+ }
+
+ @action
+ onContextMenu = (e: React.MouseEvent) => {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
+ e.preventDefault();
+ ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => this.followDefault(), icon: "arrow-right" });
+ ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
+ }
+
+ @action.bound
+ async followDefault() {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
+ this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "onRight"), false) : null;
+ }
componentDidUpdate() { this.updatePreview(); }
componentDidMount() { this.updatePreview(); }
@@ -56,42 +86,57 @@ export class LinkDocPreview extends React.Component<Props> {
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));
+ width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
+ height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225));
@computed get targetDocView() {
return !this._targetDoc ?
- <div style={{ pointerEvents: "all", maxWidth: 350, maxHeight: 250, width: "100%", height: "100%", overflow: "hidden" }}>
+ <div style={{
+ pointerEvents: "all", maxWidth: 225, maxHeight: 225, width: "100%", height: "100%",
+ overflow: "hidden"
+ }}>
<div style={{ width: "100%", height: "100%", textOverflow: "ellipsis", }} onPointerDown={this.pointerDown}>
{this._toolTipText}
</div>
</div> :
- <ContentFittingDocumentView
- Document={this._targetDoc}
- LibraryPath={emptyPath}
- fitToBox={true}
- backgroundColor={this.props.backgroundColor}
- moveDocument={returnFalse}
- rootSelected={returnFalse}
- ScreenToLocalTransform={Transform.Identity}
- parentActive={returnFalse}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- dontRegisterView={true}
- docFilters={returnEmptyFilter}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
- renderDepth={0}
- PanelWidth={this.width}
- PanelHeight={this.height}
- focus={emptyFunction}
- whenActiveChanged={returnFalse}
- bringToFront={returnFalse}
- ContentScaling={returnOne}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- />;
+ <div style={{
+ border: "6px solid white",
+ }}>
+ <div style={{ backgroundColor: "white" }}> {this._targetDoc.title}
+ <div className="wrapper" style={{ float: "right" }}>
+ <div title="Delete link" className="button" style={{ display: "inline" }} ref={this._editRef} onPointerDown={this.deleteLink}>
+ <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div>
+ <div title="Follow link" className="button" style={{ display: "inline" }} onClick={this.followDefault} onContextMenu={this.onContextMenu}>
+ <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" />
+ </div>
+ </div>
+ </div>
+ <ContentFittingDocumentView
+ Document={this._targetDoc}
+ LibraryPath={emptyPath}
+ fitToBox={true}
+ backgroundColor={this.props.backgroundColor}
+ moveDocument={returnFalse}
+ rootSelected={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ parentActive={returnFalse}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ dontRegisterView={true}
+ docFilters={returnEmptyFilter}
+ ContainingCollectionDoc={undefined}
+ ContainingCollectionView={undefined}
+ renderDepth={0}
+ PanelWidth={this.width}
+ PanelHeight={this.height}
+ focus={emptyFunction}
+ whenActiveChanged={returnFalse}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ /></div>;
}
render() {
@@ -99,7 +144,7 @@ export class LinkDocPreview extends React.Component<Props> {
style={{
position: "absolute", left: this.props.location[0],
top: this.props.location[1], width: this.width(), height: this.height(),
- boxShadow: "black 2px 2px 1em"
+ boxShadow: "black 2px 2px 1em", zIndex: 1000
}}>
{this.targetDocView}
</div>;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 90f2c0aa6..a4153a40c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -16,6 +16,13 @@ import React = require("react");
import { Docs } from "../../../documents/Documents";
import wiki from "wikijs";
import { DocumentType } from "../../../documents/DocumentTypes";
+import { computed, action, observable } from "mobx";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { LinkManager } from "../../../util/LinkManager";
+import { LinkDocPreview } from "../LinkDocPreview";
+import { DocumentLinksButton } from "../DocumentLinksButton";
+import { ContextMenu } from "../../ContextMenu";
+import { MainView } from "../../MainView";
export let formattedTextBoxCommentPlugin = new Plugin({
view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -62,6 +69,10 @@ export class FormattedTextBoxComment {
static mark: Mark;
static textBox: FormattedTextBox | undefined;
static linkDoc: Doc | undefined;
+
+ static targetDoc: Doc | undefined;
+ static _editRef = React.createRef<HTMLDivElement>();
+
constructor(view: any) {
if (!FormattedTextBoxComment.tooltip) {
const root = document.getElementById("root");
@@ -75,8 +86,8 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipText);
FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip";
FormattedTextBoxComment.tooltip.style.pointerEvents = "all";
- FormattedTextBoxComment.tooltip.style.maxWidth = "350px";
- FormattedTextBoxComment.tooltip.style.maxHeight = "250px";
+ FormattedTextBoxComment.tooltip.style.maxWidth = "225px";
+ FormattedTextBoxComment.tooltip.style.maxHeight = "225px";
FormattedTextBoxComment.tooltip.style.width = "100%";
FormattedTextBoxComment.tooltip.style.height = "100%";
FormattedTextBoxComment.tooltip.style.overflow = "hidden";
@@ -106,6 +117,31 @@ export class FormattedTextBoxComment {
}
}
+ @action
+ public static deleteLink = (): void => {
+ FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null;
+ //this.props.showLinks();
+ LinkDocPreview.LinkInfo = undefined;
+ DocumentLinksButton.EditLink = undefined;
+ }
+
+ @action
+ public static onContextMenu = (e: React.MouseEvent) => {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
+ e.preventDefault();
+ ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => FormattedTextBoxComment.followDefault(), icon: "arrow-right" });
+ ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
+ }
+
+ @action.bound
+ public static async followDefault() {
+ DocumentLinksButton.EditLink = undefined;
+ LinkDocPreview.LinkInfo = undefined;
+ FormattedTextBoxComment.targetDoc ? DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, FormattedTextBoxComment.targetDoc,
+ doc => MainView.addDocTabFunc(doc, "onRight"), false) : null;
+ }
+
public static Hide() {
FormattedTextBoxComment.textBox = undefined;
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
@@ -119,6 +155,22 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "");
}
+ @action
+ onClick = (e: PointerEvent) => {
+ if (FormattedTextBoxComment._editRef && !FormattedTextBoxComment._editRef.current?.contains(e.target as Node)) {
+ FormattedTextBoxComment.linkDoc = undefined;
+ FormattedTextBoxComment.targetDoc = undefined;
+ }
+ }
+ @action
+ componentDidMount() {
+ document.addEventListener("pointerdown", this.onClick);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener("pointerdown", this.onClick);
+ }
+
static showCommentbox(set: string, view: EditorView, nbef: number) {
const state = view.state;
if (set !== "none") {
@@ -157,6 +209,7 @@ export class FormattedTextBoxComment {
(FormattedTextBoxComment.tooltipText as any).href = "";
FormattedTextBoxComment.tooltipText.style.whiteSpace = "";
FormattedTextBoxComment.tooltipText.style.overflow = "";
+
// this section checks to see if the insertion point is over text entered by a different user. If so, it sets ths comment text to indicate the user and the modification date
if (state.selection.$from) {
nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
@@ -209,33 +262,44 @@ export class FormattedTextBoxComment {
target._scrollY = NumCast(anchor?.y);
}
if (target?.author) {
+
+ const docPreview = <div style={{ backgroundColor: "white" }}> {target.title}
+ <div className="wrapper" style={{ float: "right" }}>
+ <div title="Delete link" className="button" style={{ display: "inline" }} ref={this._editRef} onPointerDown={this.deleteLink}>
+ <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div>
+ <div title="Follow link" className="button" style={{ display: "inline" }} onClick={this.followDefault} onContextMenu={this.onContextMenu}>
+ <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" />
+ </div>
+ </div>
+ <ContentFittingDocumentView
+ Document={target}
+ LibraryPath={emptyPath}
+ fitToBox={true}
+ moveDocument={returnFalse}
+ rootSelected={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ parentActive={returnFalse}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ dontRegisterView={true}
+ docFilters={returnEmptyFilter}
+ ContainingCollectionDoc={undefined}
+ ContainingCollectionView={undefined}
+ renderDepth={0}
+ PanelWidth={() => Math.min(350, NumCast(target._width, 350))}
+ PanelHeight={() => Math.min(250, NumCast(target._height, 250))}
+ focus={emptyFunction}
+ whenActiveChanged={returnFalse}
+ bringToFront={returnFalse}
+ ContentScaling={returnOne}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ />
+ </div>;
FormattedTextBoxComment.showCommentbox("", view, nbef);
- ReactDOM.render(<ContentFittingDocumentView
- Document={target}
- LibraryPath={emptyPath}
- fitToBox={true}
- moveDocument={returnFalse}
- rootSelected={returnFalse}
- ScreenToLocalTransform={Transform.Identity}
- parentActive={returnFalse}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- dontRegisterView={true}
- docFilters={returnEmptyFilter}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
- renderDepth={0}
- PanelWidth={() => Math.min(350, NumCast(target._width, 350))}
- PanelHeight={() => Math.min(250, NumCast(target._height, 250))}
- focus={emptyFunction}
- whenActiveChanged={returnFalse}
- bringToFront={returnFalse}
- ContentScaling={returnOne}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- />, FormattedTextBoxComment.tooltipText);
+ ReactDOM.render(docPreview, FormattedTextBoxComment.tooltipText);
FormattedTextBoxComment.tooltip.style.width = NumCast(target._width) ? `${NumCast(target._width)}` : "100%";
FormattedTextBoxComment.tooltip.style.height = NumCast(target._height) ? `${NumCast(target._height)}` : "100%";
}