/* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconLookup, IconProp } from '@fortawesome/fontawesome-svg-core'; import { faCalendarDays } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Popup } from 'browndash-components'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaEdit } from 'react-icons/fa'; import { returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; import { Doc } from '../../fields/Doc'; import { Cast, DocCast } from '../../fields/Types'; import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils'; import { CalendarManager } from '../util/CalendarManager'; import { DictationManager } from '../util/DictationManager'; import { DragManager } from '../util/DragManager'; import { dropActionType } from '../util/DropActionTypes'; import { SharingManager } from '../util/SharingManager'; import { UndoManager, undoBatch } from '../util/UndoManager'; import './DocumentButtonBar.scss'; import { ObservableReactComponent } from './ObservableReactComponent'; import { PinProps } from './PinFuncs'; import { TemplateMenu } from './TemplateMenu'; import { Colors } from './global/globalEnums'; import { LinkPopup } from './linking/LinkPopup'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { OpenWhere } from './nodes/OpenWhere'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; @observer export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> { private _dragRef = React.createRef(); // eslint-disable-next-line no-use-before-define public static Instance: DocumentButtonBar; constructor(props: any) { super(props); makeObservable(this); DocumentButtonBar.Instance = this; } get view0() { return this._props.views()?.[0]; } @computed get followLinkButton() { 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 : ( {tooltip}}>
{ this.subPin = allDocs ? 'All ' : ''; })} onPointerLeave={action(() => { this.subPin = ''; })} onClick={e => { this._props.views().forEach(dv => click(dv!.Document)); e.stopPropagation(); }} />
); }; const followLink = IsFollowLinkScript(targetDoc?.onClick); return !targetDoc ? null : ( Set onClick to follow primary link}>
this._props.views().map(view => view?.toggleFollowLink(undefined, false)))}>
{followBtn( true, (doc: Doc) => { doc.followAllLinks = !doc.followAllLinks; }, (doc?: Doc) => !!doc?.followAllLinks, 'window-maximize' )}
); } @observable subLink = ''; @computed get linkButton() { const targetDoc = this.view0?.Document; return !targetDoc || !this.view0 ? null : (
search for target
}>
open linked trail
}>
); } @observable subEndLink = ''; @computed get endLinkButton() { const linkBtn = (pinLayout: boolean, pinContent: boolean, icon: IconProp) => { const tooltip = `Finish Link and Save ${this.subEndLink} data`; return !this.view0 ? null : ( {tooltip}}>
{ this.subEndLink = (pinLayout ? 'Layout' : '') + (pinLayout && pinContent ? ' &' : '') + (pinContent ? ' Content' : ''); })} onPointerLeave={action(() => { this.subEndLink = ''; })} onClick={e => { 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); e.stopPropagation(); }} />
); }; return !this.view0 ? null : (
{linkBtn(true, false, 'window-maximize')} {linkBtn(false, true, 'address-card')} {linkBtn(true, true, 'id-card')}
); } @observable subPin = ''; @computed get pinButton() { 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 : ( {tooltip}}>
{ this.subPin = (pinLayoutView ? 'Layout' : '') + (pinLayoutView && pinContentView ? ' &' : '') + (pinContentView ? ' Content View' : '') + (pinLayoutView && pinContentView ? '(shift+alt)' : pinLayoutView ? '(shift)' : pinContentView ? '(alt)' : ''); })} onPointerLeave={action(() => { this.subPin = ''; })} onClick={e => { const docs = this._props .views() .filter(v => v) .map(dv => dv!.Document); DocumentView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: pinLayoutView, pinData: { dataview: pinContentView }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null), currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null), }); e.stopPropagation(); }} />
); }; return !targetDoc ? null : ( {`Pin Document ${DocumentView.Selected().length > 1 ? 'multiple documents' : ''} to Trail`}}>
{ const docs = this._props .views() .filter(v => v) .map(dv => dv!.Document); DocumentView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinData: { dataview: e.altKey }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); e.stopPropagation(); }}>
{pinBtn(true, false, 'window-maximize')} {pinBtn(false, true, 'address-card')} {pinBtn(true, true, 'id-card')}
); } @computed get shareButton() { const targetDoc = this.view0?.Document; return !targetDoc ? null : ( Open Sharing Manager}>
SharingManager.Instance.open(this.view0, targetDoc)}>
); } @computed get menuButton() { const targetDoc = this.view0?.Document; return !targetDoc ? null : ( Open Context Menu}>
setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => this.openContextMenu(clickEv))}>
); } @computed get calendarButton() { const targetDoc = this.view0?.Document; return !targetDoc ? null : ( Open calendar menu}>
{ CalendarManager.Instance.open(this.view0, targetDoc); }}>
); } @observable _isRecording = false; _stopFunc: () => void = emptyFunction; @computed get recordButton() { const targetDoc = this.view0?.Document; return !targetDoc ? null : ( Press to record audio annotation}>
{ this._isRecording = true; this._props.views().map( view => view && DictationManager.recordAudioAnnotation( view.dataDoc, view.LayoutFieldKey, stopFunc => { this._stopFunc = stopFunc; }, emptyFunction ) ); const b = UndoManager.StartBatch('Recording'); setupMoveUpEvents( this, e, returnFalse, action(() => { this._isRecording = false; this._stopFunc(); b.end(); }), emptyFunction ); })}>
); } @observable _embedDown = false; onTemplateButton = action((e: React.PointerEvent): void => { this._tooltipOpen = false; setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction); }); onEmbedButtonMoved = () => { if (this._dragRef.current) { const dragDocView = this.view0!; const dragData = new DragManager.DocumentDragData([dragDocView.Document]); const origin = dragDocView.screenToContentsTransform().inverse().transformPoint(0, 0); dragData.defaultDropAction = dropActionType.embed; dragData.canEmbed = true; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, origin[0], origin[1], { hideSource: false }); return true; } return false; }; _ref = React.createRef(); @observable _tooltipOpen: boolean = false; @computed get templateMenu() { return (
v) .map(v => v as DocumentView)} />
); } @computed get templateButton() { return !this.view0 ? null : ( Tap to Customize Layout. Drag an embedding} open={this._tooltipOpen} onClose={action(() => { this._tooltipOpen = false; })} placement="bottom">
{ !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true); })}> } popup={this.templateMenu} popupContainsPt={returnTrue} />
); } openContextMenu = (e: PointerEvent) => { let child = DocumentView.Selected()[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; if (next?.className?.toString().includes(DashFieldView.name)) break; if (next) child = next; else break; } simulateMouseClick(child, e.clientX, e.clientY - 30, e.screenX, e.screenY - 30); }; @observable _showLinkPopup = false; @action toggleLinkSearch = (e: React.PointerEvent) => { this._showLinkPopup = !this._showLinkPopup; e.stopPropagation(); }; @observable _captureEndLinkLayout = false; @action captureEndLinkLayout = () => { this._captureEndLinkLayout = !this._captureEndLinkLayout; }; @observable _captureEndLinkContent = false; @action captureEndLinkContent = () => { this._captureEndLinkContent = !this._captureEndLinkContent; }; @action captureEndLinkState = () => { this._captureEndLinkContent = this._captureEndLinkLayout = !this._captureEndLinkLayout; }; @action toggleTrail = (e: React.PointerEvent) => { 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); } e.stopPropagation(); }; render() { const doc = this.view0?.Document; if (!doc || !this.view0) return null; return (
{this._showLinkPopup ? (
this._props.views().lastElement()?.ComponentView?.getAnchor?.(true)} linkFrom={() => this._props.views().lastElement()?.Document} />
) : (
{this.linkButton}
)} {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ?
{this.endLinkButton}
: null}
{this.templateButton}
{!DocumentView.Selected().some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
{this.recordButton}
{this.calendarButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
}
{this.menuButton}
); } }