aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/DocumentButtonBar.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/DocumentButtonBar.tsx')
-rw-r--r--src/client/views/DocumentButtonBar.tsx258
1 files changed, 67 insertions, 191 deletions
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index c1ec5b4a4..f0887676f 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -1,36 +1,29 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { IconLookup, IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
-import { action, computed, observable, runInAction } from 'mobx';
+import { Tooltip } from '@mui/material';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
-import { Doc } from '../../fields/Doc';
-import { RichTextField } from '../../fields/RichTextField';
-import { Cast, DocCast, NumCast } from '../../fields/Types';
+import * as React from 'react';
import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils';
-import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
-import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
-import { Docs, DocUtils } from '../documents/Documents';
+import { Doc } from '../../fields/Doc';
+import { Cast, DocCast } from '../../fields/Types';
+import { DocUtils } from '../documents/Documents';
+import { CalendarManager } from '../util/CalendarManager';
import { DragManager } from '../util/DragManager';
import { IsFollowLinkScript } from '../util/LinkFollower';
import { SelectionManager } from '../util/SelectionManager';
import { SharingManager } from '../util/SharingManager';
-import { undoBatch, UndoManager } from '../util/UndoManager';
-import { CollectionDockingView } from './collections/CollectionDockingView';
-import { TabDocView } from './collections/TabDocView';
+import { UndoManager, undoBatch } from '../util/UndoManager';
import './DocumentButtonBar.scss';
+import { ObservableReactComponent } from './ObservableReactComponent';
+import { TabDocView } from './collections/TabDocView';
import { Colors } from './global/globalEnums';
import { LinkPopup } from './linking/LinkPopup';
-import { MetadataEntryMenu } from './MetadataEntryMenu';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
-import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from './nodes/DocumentView';
import { DashFieldView } from './nodes/formattedText/DashFieldView';
-import { GoogleRef } from './nodes/formattedText/FormattedTextBox';
import { PinProps } from './nodes/trails';
-import { TemplateMenu } from './TemplateMenu';
-import React = require('react');
-const higflyout = require('@hig/flyout');
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
+import { faCalendarDays } from '@fortawesome/free-solid-svg-icons';
const cloud: IconProp = 'cloud-upload-alt';
const fetch: IconProp = 'sync-alt';
@@ -42,12 +35,11 @@ enum UtilityButtonState {
}
@observer
-export class DocumentButtonBar extends React.Component<{ views: () => (DocumentView | undefined)[]; stack?: any }, {}> {
+export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> {
private _dragRef = React.createRef<HTMLDivElement>();
private _pullAnimating = false;
private _pushAnimating = false;
private _pullColorAnimating = false;
-
@observable private pushIcon: IconProp = 'arrow-alt-circle-up';
@observable private pullIcon: IconProp = 'arrow-alt-circle-down';
@observable private pullColor: string = 'white';
@@ -60,9 +52,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
public static hasPushedHack = false;
public static hasPulledHack = false;
- constructor(props: { views: () => (DocumentView | undefined)[] }) {
+ constructor(props: any) {
super(props);
- runInAction(() => (DocumentButtonBar.Instance = this));
+ makeObservable(this);
+ DocumentButtonBar.Instance = this;
}
public startPullOutcome = action((success: boolean) => {
@@ -111,110 +104,13 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
});
get view0() {
- return this.props.views()?.[0];
- }
-
- @computed
- get considerGoogleDocsPush() {
- const targetDoc = this.view0?.props.Document;
- const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
- const animation = this.isAnimatingPulse ? 'shadow-pulse 1s linear infinite' : 'none';
- return !targetDoc ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{`${published ? 'Push' : 'Publish'} to Google Docs`}</div>
- </>
- }>
- <div
- className="documentButtonBar-button"
- style={{ animation }}
- onClick={async () => {
- await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
- !published && runInAction(() => (this.isAnimatingPulse = true));
- DocumentButtonBar.hasPushedHack = false;
- targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
- }}>
- <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? 'sm' : 'xs'} />
- </div>
- </Tooltip>
- );
+ return this._props.views()?.[0];
}
- @computed
- get considerGoogleDocsPull() {
- const targetDoc = this.view0?.props.Document;
- const dataDoc = targetDoc && Doc.GetProto(targetDoc);
- const animation = this.isAnimatingFetch ? 'spin 0.5s linear infinite' : 'none';
-
- const title = (() => {
- switch (this.openHover) {
- default:
- case UtilityButtonState.Default:
- return `${!dataDoc?.googleDocUnchanged ? 'Pull from' : 'Fetch'} Google Docs`;
- case UtilityButtonState.OpenRight:
- return 'Open in Right Split';
- case UtilityButtonState.OpenExternally:
- return 'Open in new Browser Tab';
- }
- })();
-
- return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? null : (
- <Tooltip title={<div className="dash-tooltip">{title}</div>}>
- <div
- className="documentButtonBar-button"
- style={{ backgroundColor: this.pullColor }}
- onPointerEnter={action(e => {
- if (e.altKey) {
- this.openHover = UtilityButtonState.OpenExternally;
- } else if (e.shiftKey) {
- this.openHover = UtilityButtonState.OpenRight;
- }
- })}
- onPointerLeave={action(() => (this.openHover = UtilityButtonState.Default))}
- onClick={async e => {
- const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
- if (e.shiftKey) {
- e.preventDefault();
- let googleDoc = await Cast(dataDoc.googleDoc, Doc);
- if (!googleDoc) {
- const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, data_useCors: false };
- googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
- dataDoc.googleDoc = googleDoc;
- }
- CollectionDockingView.AddSplit(googleDoc, OpenWhereMod.right);
- } else if (e.altKey) {
- e.preventDefault();
- window.open(googleDocUrl);
- } else {
- this.clearPullColor();
- DocumentButtonBar.hasPulledHack = false;
- targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
- dataDoc.googleDocUnchanged && runInAction(() => (this.isAnimatingFetch = true));
- }
- }}>
- <FontAwesomeIcon
- className="documentdecorations-icon"
- size="sm"
- style={{ WebkitAnimation: animation, MozAnimation: animation }}
- icon={(() => {
- // prettier-ignore
- switch (this.openHover) {
- default:
- case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch;
- case UtilityButtonState.OpenRight: return 'arrow-alt-circle-right';
- case UtilityButtonState.OpenExternally: return 'share';
- }
- })()}
- />
- </div>
- </Tooltip>
- );
- }
@observable subFollow = '';
@computed
get followLinkButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
const followBtn = (allDocs: boolean, click: (doc: Doc) => void, isSet: (doc?: Doc) => boolean, icon: IconProp) => {
const tooltip = `Follow ${this.subPin}documents`;
return !tooltip ? null : (
@@ -229,7 +125,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
onPointerEnter={action(e => (this.subPin = allDocs ? 'All ' : ''))}
onPointerLeave={action(e => (this.subPin = ''))}
onClick={e => {
- this.props.views().forEach(dv => click(dv!.rootDoc));
+ this._props.views().forEach(dv => click(dv!.Document));
e.stopPropagation();
}}
/>
@@ -243,7 +139,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
<div
className="documentButtonBar-icon documentButtonBar-follow"
style={{ backgroundColor: followLink ? Colors.LIGHT_BLUE : Colors.DARK_GRAY, color: followLink ? Colors.BLACK : Colors.WHITE }}
- onClick={undoBatch(e => this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
+ onClick={undoBatch(e => this._props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
<div className="documentButtonBar-followTypes">
{followBtn(
true,
@@ -260,7 +156,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@observable subLink = '';
@computed get linkButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
return !targetDoc || !this.view0 ? null : (
<div className="documentButtonBar-icon documentButtonBar-link">
<div className="documentButtonBar-linkTypes">
@@ -304,7 +200,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
onPointerLeave={action(e => (this.subEndLink = ''))}
onClick={e => {
this.view0 &&
- DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.props.Document, true, this.view0, {
+ DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.Document, true, this.view0, {
pinDocLayout: pinLayout,
pinData: !pinContent ? {} : { poslayoutview: true, dataannos: true, dataview: pinContent },
} as PinProps);
@@ -331,7 +227,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@observable subPin = '';
@computed
get pinButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
const pinBtn = (pinLayoutView: boolean, pinContentView: boolean, icon: IconProp) => {
const tooltip = `Pin Document and Save ${this.subPin} to trail`;
return !tooltip ? null : (
@@ -353,10 +249,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
)}
onPointerLeave={action(e => (this.subPin = ''))}
onClick={e => {
- const docs = this.props
+ const docs = this._props
.views()
.filter(v => v)
- .map(dv => dv!.rootDoc);
+ .map(dv => dv!.Document);
TabDocView.PinDoc(docs, {
pinAudioPlay: true,
pinDocLayout: pinLayoutView,
@@ -372,14 +268,14 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
);
};
return !targetDoc ? null : (
- <Tooltip title={<div className="dash-tooltip">{`Pin Document ${SelectionManager.Views().length > 1 ? 'multiple documents' : ''} to Trail`}</div>}>
+ <Tooltip title={<div className="dash-tooltip">{`Pin Document ${SelectionManager.Views.length > 1 ? 'multiple documents' : ''} to Trail`}</div>}>
<div
className="documentButtonBar-icon documentButtonBar-pin"
onClick={e => {
- const docs = this.props
+ const docs = this._props
.views()
.filter(v => v)
- .map(dv => dv!.rootDoc);
+ .map(dv => dv!.Document);
TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinData: { dataview: e.altKey }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
e.stopPropagation();
}}>
@@ -396,7 +292,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@computed
get shareButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
return !targetDoc ? null : (
<Tooltip title={<div className="dash-tooltip">{'Open Sharing Manager'}</div>}>
<div className="documentButtonBar-icon" style={{ color: 'white' }} onClick={e => SharingManager.Instance.open(this.view0, targetDoc)}>
@@ -408,36 +304,29 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@computed
get menuButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
return !targetDoc ? null : (
<Tooltip title={<div className="dash-tooltip">{`Open Context Menu`}</div>}>
- <div className="documentButtonBar-icon" style={{ color: 'white', cursor: 'pointer' }} onClick={this.openContextMenu}>
+ <div className="documentButtonBar-icon" style={{ color: 'white', cursor: 'pointer' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => this.openContextMenu(e))}>
<FontAwesomeIcon className="documentdecorations-icon" icon="bars" />
</div>
</Tooltip>
);
}
+
@computed
- get metadataButton() {
- const view0 = this.view0;
- return !view0 ? null : (
- <Tooltip title={<div className="dash-tooltip">Show metadata panel</div>}>
- <div className="documentButtonBar-linkFlyout">
- <Flyout
- anchorPoint={anchorPoints.LEFT_TOP}
- content={
- <MetadataEntryMenu
- docs={this.props
- .views()
- .filter(dv => dv)
- .map(dv => dv!.props.Document)}
- suggestWithFunction
- /> /* tfs: @bcz This might need to be the data document? */
- }>
- <div className={'documentButtonBar-linkButton-' + 'empty'} onPointerDown={e => e.stopPropagation()}>
- {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" />}
- </div>
- </Flyout>
+ get calendarButton() {
+ const targetDoc = this.view0?.Document;
+ return !targetDoc ? null : (
+ <Tooltip title={<div className="dash-calendar-button">Open calendar menu</div>}>
+ <div
+ className="documentButtonBar-icon"
+ style={{ color: 'white' }}
+ onClick={e => {
+ console.log('hi: ', CalendarManager.Instance);
+ CalendarManager.Instance.open(this.view0, targetDoc);
+ }}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon={faCalendarDays as IconLookup} />
</div>
</Tooltip>
);
@@ -447,7 +336,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
_stopFunc: () => void = emptyFunction;
@computed
get recordButton() {
- const targetDoc = this.view0?.props.Document;
+ const targetDoc = this.view0?.Document;
return !targetDoc ? null : (
<Tooltip title={<div className="dash-tooltip">Press to record audio annotation</div>}>
<div
@@ -455,7 +344,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
style={{ backgroundColor: this._isRecording ? Colors.ERROR_RED : Colors.DARK_GRAY, color: Colors.WHITE }}
onPointerDown={action((e: React.PointerEvent) => {
this._isRecording = true;
- this.props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction));
+ this._props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction));
const b = UndoManager.StartBatch('Recording');
setupMoveUpEvents(
this,
@@ -482,8 +371,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
onEmbedButtonMoved = () => {
if (this._dragRef.current) {
const dragDocView = this.view0!;
- const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
- const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ const dragData = new DragManager.DocumentDragData([dragDocView.Document]);
+ const [left, top] = dragDocView._props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
dragData.defaultDropAction = 'embed';
dragData.canEmbed = true;
DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false });
@@ -497,11 +386,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@computed
get templateButton() {
const view0 = this.view0;
- const views = this.props.views();
+ const views = this._props.views();
return !view0 ? null : (
<Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embedding</div>} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
<div className="documentButtonBar-linkFlyout" ref={this._dragRef} onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}>
- <Flyout
+ {/* <Flyout
anchorPoint={anchorPoints.LEFT_TOP}
onOpen={action(() => (this._embedDown = true))}
onClose={action(() => (this._embedDown = false))}
@@ -516,14 +405,14 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
<div className={'documentButtonBar-linkButton-empty'} ref={this._dragRef} onPointerDown={this.onTemplateButton}>
<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />
</div>
- </Flyout>
+ </Flyout> */}
</div>
</Tooltip>
);
}
- openContextMenu = (e: React.MouseEvent) => {
- let child = SelectionManager.Views()[0].ContentDiv!.children[0];
+ openContextMenu = (e: PointerEvent) => {
+ let child = SelectionManager.Views[0].ContentDiv!.children[0];
while (child.children.length) {
const next = Array.from(child.children).find(c => c.className?.toString().includes('SVGAnimatedString') || typeof c.className === 'string');
if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break;
@@ -559,27 +448,24 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
@action
toggleTrail = (e: React.PointerEvent) => {
- const rootView = this.props.views()[0];
- const rootDoc = rootView?.rootDoc;
- if (rootDoc) {
- const anchor = rootView.ComponentView?.getAnchor?.(true) ?? rootDoc;
+ const rootView = this._props.views()[0];
+ const doc = rootView?.Document;
+ if (doc) {
+ const anchor = rootView.ComponentView?.getAnchor?.(true) ?? doc;
const trail = DocCast(anchor.presentationTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true);
if (trail !== anchor.presentationTrail) {
DocUtils.MakeLink(anchor, trail, { link_relationship: 'link trail' });
anchor.presentationTrail = trail;
}
Doc.ActivePresentation = trail;
- this.props.views().lastElement()?.props.addDocTab(trail, OpenWhere.replaceRight);
+ this._props.views().lastElement()?._props.addDocTab(trail, OpenWhere.replaceRight);
}
e.stopPropagation();
};
render() {
- if (!this.view0) return null;
+ const doc = this.view0?.Document;
+ if (!doc || !this.view0) return null;
- const isText = this.view0.props.Document[this.view0.LayoutFieldKey] instanceof RichTextField;
- const doc = this.view0?.props.Document;
- const considerPull = isText && this.considerGoogleDocsPull;
- const considerPush = isText && this.considerGoogleDocsPush;
return (
<div className="documentButtonBar">
<div className="documentButtonBar-button">
@@ -589,9 +475,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
<div style={{ position: 'absolute', zIndex: 1000 }}>
<LinkPopup
key="popup"
- linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
- linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
- linkFrom={() => this.props.views().lastElement()?.rootDoc}
+ linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this._props.views().lastElement()?.Document.onClick))}
+ linkCreateAnchor={() => this._props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
+ linkFrom={() => this._props.views().lastElement()?.Document}
/>
</div>
) : (
@@ -599,22 +485,12 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
)}
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ? <div className="documentButtonBar-button">{this.endLinkButton} </div> : null}
- {
- Doc.noviceMode ? null : <div className="documentButtonBar-button">{this.templateButton}</div>
- /*<div className="documentButtonBar-button"> {this.metadataButton} </div> */
- }
- {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
+ {Doc.noviceMode ? null : <div className="documentButtonBar-button">{this.templateButton}</div>}
+ {!SelectionManager.Views?.some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
<div className="documentButtonBar-button">{this.pinButton}</div>
<div className="documentButtonBar-button">{this.recordButton}</div>
+ <div className="documentButtonBar-button">{this.calendarButton}</div>
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : <div className="documentButtonBar-button">{this.shareButton}</div>}
- {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : (
- <div className="documentButtonBar-button" style={{ display: !considerPush ? 'none' : '' }}>
- {this.considerGoogleDocsPush}
- </div>
- )}
- <div className="documentButtonBar-button" style={{ display: !considerPull ? 'none' : '' }}>
- {this.considerGoogleDocsPull}
- </div>
<div className="documentButtonBar-button">{this.menuButton}</div>
</div>
);