aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-01-24 17:05:25 -0500
committerbobzel <zzzman@gmail.com>2023-01-24 17:05:25 -0500
commit555d67a31adbe7e6d42f7f7805ba1348e6d505f6 (patch)
tree1bf2f5264d9c87cfc3ada1024470686bf0d2494b /src
parenta83e575638a0efe81da7aa0204edd33bb8a6bb2f (diff)
stopped storing presCollection in PresBox in favor of computing it. added anchor menu option for viewing linked trail. fixed showing slected slides in presbox when link with up is used.
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DocumentManager.ts26
-rw-r--r--src/client/views/AntimodeMenu.tsx143
-rw-r--r--src/client/views/DocumentButtonBar.tsx30
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx60
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx12
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts2
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx307
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx10
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx145
-rw-r--r--src/client/views/pdf/Annotation.tsx7
-rw-r--r--src/client/views/search/SearchBox.tsx13
15 files changed, 400 insertions, 368 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 70fe7f2c0..aa09fb005 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -5,7 +5,7 @@ import { listSpec } from '../../fields/Schema';
import { Cast, DocCast, StrCast } from '../../fields/Types';
import { AudioField } from '../../fields/URLField';
import { returnFalse } from '../../Utils';
-import { DocumentType } from '../documents/DocumentTypes';
+import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { CollectionDockingView } from '../views/collections/CollectionDockingView';
import { CollectionFreeFormView } from '../views/collections/collectionFreeForm';
import { CollectionView } from '../views/collections/CollectionView';
@@ -32,11 +32,15 @@ export class DocumentManager {
private constructor() {}
private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
- public AddViewRenderedCb = (doc: Doc, func: (dv: DocumentView) => any) => {
- const dv = this.getDocumentViewById(doc[Id]);
- this._viewRenderedCbs.push({ doc, func });
- if (dv) {
- this.callAddViewFuncs(dv);
+ public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
+ if (doc) {
+ const dv = this.getDocumentViewById(doc[Id]);
+ this._viewRenderedCbs.push({ doc, func });
+ if (dv) {
+ this.callAddViewFuncs(dv);
+ }
+ } else {
+ func(undefined as any);
}
};
callAddViewFuncs = (view: DocumentView) => {
@@ -190,6 +194,16 @@ export class DocumentManager {
return toReturn;
}
+ static GetContextPath(doc: Opt<Doc>) {
+ if (!doc) return [];
+ const srcContext = Cast(doc.context, Doc, null) ?? Cast(Cast(doc.annotationOn, Doc, null)?.context, Doc, null);
+ var containerDocContext = srcContext ? [srcContext] : [];
+ while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && !DocumentManager.Instance.getDocumentView(containerDocContext[0])) {
+ containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
+ }
+ return containerDocContext;
+ }
+
static playAudioAnno(doc: Doc) {
const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement();
if (anno) {
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index 0f1fc6b69..de1207ce4 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -1,8 +1,7 @@
-import React = require("react");
-import { observable, action, runInAction } from "mobx";
-import "./AntimodeMenu.scss";
-export interface AntimodeMenuProps {
-}
+import React = require('react');
+import { observable, action, runInAction } from 'mobx';
+import './AntimodeMenu.scss';
+export interface AntimodeMenuProps {}
/**
* This is an abstract class that serves as the base for a PDF-style or Marquee-style
@@ -17,15 +16,19 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
@observable protected _top: number = -300;
@observable protected _left: number = -300;
@observable protected _opacity: number = 0;
- @observable protected _transitionProperty: string = "opacity";
- @observable protected _transitionDuration: string = "0.5s";
- @observable protected _transitionDelay: string = "";
+ @observable protected _transitionProperty: string = 'opacity';
+ @observable protected _transitionDuration: string = '0.5s';
+ @observable protected _transitionDelay: string = '';
@observable protected _canFade: boolean = false;
@observable public Pinned: boolean = false;
- get width() { return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().width : 0; }
- get height() { return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().height : 0; }
+ get width() {
+ return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().width : 0;
+ }
+ get height() {
+ return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().height : 0;
+ }
@action
/**
@@ -36,12 +39,12 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
*/
public jumpTo = (x: number, y: number, forceJump: boolean = false) => {
if (!this.Pinned || forceJump) {
- this._transitionProperty = this._transitionDuration = this._transitionDelay = "";
+ this._transitionProperty = this._transitionDuration = this._transitionDelay = '';
this._opacity = 1;
this._left = x;
this._top = y;
}
- }
+ };
@action
/**
@@ -51,56 +54,56 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
public fadeOut = (forceOut: boolean) => {
if (!this.Pinned) {
if (this._opacity === 0.2) {
- this._transitionProperty = "opacity";
- this._transitionDuration = "0.1s";
+ this._transitionProperty = 'opacity';
+ this._transitionDuration = '0.1s';
}
if (forceOut) {
- this._transitionProperty = "";
- this._transitionDuration = "";
+ this._transitionProperty = '';
+ this._transitionDuration = '';
}
- this._transitionDelay = "";
+ this._transitionDelay = '';
this._opacity = 0;
this._left = this._top = -300;
}
- }
+ };
@action
protected pointerLeave = (e: React.PointerEvent) => {
if (!this.Pinned && this._canFade) {
- this._transitionProperty = "opacity";
- this._transitionDuration = "0.5s";
- this._transitionDelay = "1s";
+ this._transitionProperty = 'opacity';
+ this._transitionDuration = '0.5s';
+ this._transitionDelay = '1s';
this._opacity = 0.2;
setTimeout(() => this.fadeOut(false), 3000);
}
- }
+ };
@action
protected pointerEntered = (e: React.PointerEvent) => {
- this._transitionProperty = "opacity";
- this._transitionDuration = "0.1s";
- this._transitionDelay = "";
+ this._transitionProperty = 'opacity';
+ this._transitionDuration = '0.1s';
+ this._transitionDelay = '';
this._opacity = 1;
- }
+ };
@action
protected togglePin = (e: React.MouseEvent) => {
- runInAction(() => this.Pinned = !this.Pinned);
- }
+ runInAction(() => (this.Pinned = !this.Pinned));
+ };
protected dragStart = (e: React.PointerEvent) => {
- document.removeEventListener("pointermove", this.dragging);
- document.addEventListener("pointermove", this.dragging);
- document.removeEventListener("pointerup", this.dragEnd);
- document.addEventListener("pointerup", this.dragEnd);
+ document.removeEventListener('pointermove', this.dragging);
+ document.addEventListener('pointermove', this.dragging);
+ document.removeEventListener('pointerup', this.dragEnd);
+ document.addEventListener('pointerup', this.dragEnd);
this._offsetX = e.pageX - this._mainCont.current!.getBoundingClientRect().left;
this._offsetY = e.pageY - this._mainCont.current!.getBoundingClientRect().top;
e.stopPropagation();
e.preventDefault();
- }
+ };
@action
protected dragging = (e: PointerEvent) => {
@@ -115,32 +118,41 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
e.stopPropagation();
e.preventDefault();
- }
+ };
protected dragEnd = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.dragging);
- document.removeEventListener("pointerup", this.dragEnd);
+ document.removeEventListener('pointermove', this.dragging);
+ document.removeEventListener('pointerup', this.dragEnd);
e.stopPropagation();
e.preventDefault();
- }
+ };
protected handleContextMenu = (e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
- }
+ };
protected getDragger = () => {
- return <div className="antimodeMenu-dragger" key="dragger" onPointerDown={this.dragStart} style={{ width: "20px" }} />;
- }
+ return <div className="antimodeMenu-dragger" key="dragger" onPointerDown={this.dragStart} style={{ width: '20px' }} />;
+ };
- protected getElement(buttons: JSX.Element[]) {
+ protected getElement(buttons: JSX.Element) {
return (
- <div className="antimodeMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
+ <div
+ className="antimodeMenu-cont"
+ onPointerLeave={this.pointerLeave}
+ onPointerEnter={this.pointerEntered}
+ ref={this._mainCont}
+ onContextMenu={this.handleContextMenu}
style={{
- left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay,
- position: this.Pinned ? "unset" : undefined
+ left: this._left,
+ top: this._top,
+ opacity: this._opacity,
+ transitionProperty: this._transitionProperty,
+ transitionDuration: this._transitionDuration,
+ transitionDelay: this._transitionDelay,
+ position: this.Pinned ? 'unset' : undefined,
}}>
- {/* {this.getDragger} */}
{buttons}
</div>
);
@@ -148,34 +160,51 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
protected getElementVert(buttons: JSX.Element[]) {
return (
- <div className="antimodeMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
+ <div
+ className="antimodeMenu-cont"
+ onPointerLeave={this.pointerLeave}
+ onPointerEnter={this.pointerEntered}
+ ref={this._mainCont}
+ onContextMenu={this.handleContextMenu}
style={{
left: this.Pinned ? undefined : this._left,
top: this.Pinned ? 0 : this._top,
right: this.Pinned ? 0 : undefined,
- height: "inherit",
+ height: 'inherit',
width: 200,
- opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay,
- position: this.Pinned ? "absolute" : undefined
+ opacity: this._opacity,
+ transitionProperty: this._transitionProperty,
+ transitionDuration: this._transitionDuration,
+ transitionDelay: this._transitionDelay,
+ position: this.Pinned ? 'absolute' : undefined,
}}>
{buttons}
</div>
);
}
-
-
protected getElementWithRows(rows: JSX.Element[], numRows: number, hasDragger: boolean = true) {
return (
- <div className="antimodeMenu-cont with-rows" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
+ <div
+ className="antimodeMenu-cont with-rows"
+ onPointerLeave={this.pointerLeave}
+ onPointerEnter={this.pointerEntered}
+ ref={this._mainCont}
+ onContextMenu={this.handleContextMenu}
style={{
- left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty,
- transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay, height: "auto",
- flexDirection: this.Pinned ? "row" : undefined, position: this.Pinned ? "unset" : undefined
+ left: this._left,
+ top: this._top,
+ opacity: this._opacity,
+ transitionProperty: this._transitionProperty,
+ transitionDuration: this._transitionDuration,
+ transitionDelay: this._transitionDelay,
+ height: 'auto',
+ flexDirection: this.Pinned ? 'row' : undefined,
+ position: this.Pinned ? 'unset' : undefined,
}}>
- {hasDragger ? <div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: "20px" }} /> : (null)}
+ {hasDragger ? <div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: '20px' }} /> : null}
{rows}
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index f06dc93e3..f61d147cf 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -5,11 +5,11 @@ import { action, computed, observable, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import { Doc } from '../../fields/Doc';
import { RichTextField } from '../../fields/RichTextField';
-import { Cast, NumCast } from '../../fields/Types';
+import { Cast, DocCast, NumCast } from '../../fields/Types';
import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
-import { Docs } from '../documents/Documents';
+import { Docs, DocUtils } from '../documents/Documents';
import { DragManager } from '../util/DragManager';
import { SelectionManager } from '../util/SelectionManager';
import { SharingManager } from '../util/SharingManager';
@@ -21,12 +21,13 @@ import { Colors } from './global/globalEnums';
import { LinkPopup } from './linking/LinkPopup';
import { MetadataEntryMenu } from './MetadataEntryMenu';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
-import { DocumentView, DocumentViewInternal, OpenWhereMod } from './nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
import { DashFieldView } from './nodes/formattedText/DashFieldView';
import { GoogleRef } from './nodes/formattedText/FormattedTextBox';
import { TemplateMenu } from './TemplateMenu';
import React = require('react');
import { DocumentType } from '../documents/DocumentTypes';
+import { FontIconBox } from './nodes/button/FontIconBox';
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -270,6 +271,13 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
</button>
</div>
</Tooltip>
+ <Tooltip title={<div>open linked trail</div>}>
+ <div className="documentButtonBar-button">
+ <button style={{ backgroundColor: 'transparent', width: 35, height: 35, display: 'flex', justifyContent: 'center', alignItems: 'center', position: 'relative' }} onPointerDown={this.toggleTrail}>
+ <FontAwesomeIcon icon="taxi" size="lg" />
+ </button>
+ </div>
+ </Tooltip>
</div>
<div style={{ width: 25, height: 25 }}>
<DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} />
@@ -483,6 +491,22 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
this._showLinkPopup = !this._showLinkPopup;
e.stopPropagation();
};
+ @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 trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true);
+ if (trail !== anchor.presTrail) {
+ DocUtils.MakeLink({ doc: anchor }, { doc: trail }, 'link trail');
+ anchor.presTrail = trail;
+ }
+ Doc.ActivePresentation = trail;
+ this.props.views().lastElement()?.props.addDocTab(trail, OpenWhere.replaceRight);
+ }
+ e.stopPropagation();
+ };
render() {
if (!this.view0) return null;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4494166f2..839db5795 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -249,6 +249,7 @@ export class MainView extends React.Component {
fa.faTrash,
fa.faTrashAlt,
fa.faShare,
+ fa.faTaxi,
fa.faDownload,
fa.faExpandArrowsAlt,
fa.faLayerGroup,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index 488f51d77..9581563ce 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -26,33 +26,39 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
render() {
const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: 'auto', width: 19, transform: 'translate(-2px, -2px)' }} />;
- const buttons = [
- <Tooltip key="collect" title={<div className="dash-tooltip">Create a Collection</div>} placement="bottom">
- <button className="antimodeMenu-button" onPointerDown={this.createCollection}>
- <FontAwesomeIcon icon="object-group" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="group" title={<div className="dash-tooltip">Create a Grouping</div>} placement="bottom">
- <button className="antimodeMenu-button" onPointerDown={e => this.createCollection(e, true)}>
- <FontAwesomeIcon icon="layer-group" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="summarize" title={<div className="dash-tooltip">Summarize Documents</div>} placement="bottom">
- <button className="antimodeMenu-button" onPointerDown={this.summarize}>
- <FontAwesomeIcon icon="compress-arrows-alt" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="delete" title={<div className="dash-tooltip">Delete Documents</div>} placement="bottom">
- <button className="antimodeMenu-button" onPointerDown={this.delete}>
- <FontAwesomeIcon icon="trash-alt" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="pinWithView" title={<div className="dash-tooltip">Pin selected region to trail</div>} placement="bottom">
- <button className="antimodeMenu-button" onPointerDown={this.pinWithView}>
- {presPinWithViewIcon}
- </button>
- </Tooltip>,
- ];
+ const buttons = (
+ <>
+ <Tooltip key="collect" title={<div className="dash-tooltip">Create a Collection</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={this.createCollection}>
+ <FontAwesomeIcon icon="object-group" size="lg" />
+ </button>
+ </Tooltip>
+ ,
+ <Tooltip key="group" title={<div className="dash-tooltip">Create a Grouping</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={e => this.createCollection(e, true)}>
+ <FontAwesomeIcon icon="layer-group" size="lg" />
+ </button>
+ </Tooltip>
+ ,
+ <Tooltip key="summarize" title={<div className="dash-tooltip">Summarize Documents</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={this.summarize}>
+ <FontAwesomeIcon icon="compress-arrows-alt" size="lg" />
+ </button>
+ </Tooltip>
+ ,
+ <Tooltip key="delete" title={<div className="dash-tooltip">Delete Documents</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={this.delete}>
+ <FontAwesomeIcon icon="trash-alt" size="lg" />
+ </button>
+ </Tooltip>
+ ,
+ <Tooltip key="pinWithView" title={<div className="dash-tooltip">Pin selected region to trail</div>} placement="bottom">
+ <button className="antimodeMenu-button" onPointerDown={this.pinWithView}>
+ {presPinWithViewIcon}
+ </button>
+ </Tooltip>
+ </>
+ );
return this.getElement(buttons);
}
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 054d01d8e..b94db2c6b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -696,6 +696,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
});
+ @action
onPointerDown = (e: React.PointerEvent): void => {
if (this.rootDoc.type === DocumentType.INK && Doc.ActiveTool === InkTool.Eraser) return;
// continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document)
@@ -736,6 +737,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
document.removeEventListener('pointerup', this.onPointerUp);
document.addEventListener('pointerup', this.onPointerUp);
+ } else {
+ this._cursorTimer && clearTimeout(this._cursorTimer);
+ this._cursorPress = false;
}
};
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index e477d7ae2..1de29f806 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -161,7 +161,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
</div>
);
return (
- <div className={`menuButton ${this.type} ${numBtnType}`} onClick={action(() => (this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen))}>
+ <div className={`menuButton ${this.type} ${numBtnType}`} onPointerDown={e => e.stopPropagation()} onClick={action(() => (this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen))}>
{checkResult}
{label}
{this.rootDoc.dropDownOpen ? dropdown : null}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 63347015b..39005a18b 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -287,12 +287,12 @@ export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> {
document.addEventListener('pointerdown', hideMenu, true);
};
render() {
- return this.getElement([
+ return this.getElement(
<Tooltip key="trash" title={<div className="dash-tooltip">{`Show Pivot Viewer for '${this._fieldKey}'`}</div>}>
<button className="antimodeMenu-button" onPointerDown={this.showFields}>
<FontAwesomeIcon icon="eye" size="lg" />
</button>
- </Tooltip>,
- ]);
+ </Tooltip>
+ );
}
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index deb1d68a7..8407eee96 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -693,6 +693,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@undoBatch
makeTargetToggle = (anchor: Doc) => (anchor.followLinkToggle = !anchor.followLinkToggle);
+ @undoBatch
+ showTargetTrail = (anchor: Doc) => {
+ const trail = DocCast(anchor.presTrail);
+ if (trail) {
+ Doc.ActivePresentation = trail;
+ this.props.addDocTab(trail, OpenWhere.replaceRight);
+ }
+ };
+
isTargetToggler = (anchor: Doc) => BoolCast(anchor.followLinkToggle);
specificContextMenu = (e: React.MouseEvent): void => {
@@ -717,6 +726,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
AnchorMenu.Instance.Pinned = false;
AnchorMenu.Instance.PinToPres = () => this.pinToPres(anchor as Doc);
AnchorMenu.Instance.MakeTargetToggle = () => this.makeTargetToggle(anchor as Doc);
+ AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(anchor as Doc);
AnchorMenu.Instance.IsTargetToggler = () => this.isTargetToggler(anchor as Doc);
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
})
@@ -1471,7 +1481,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (!this._editorView?.state.selection.empty && !(this._editorView?.state.selection instanceof NodeSelection) && FormattedTextBox._canAnnotate && !(e.nativeEvent as any).dash) this.setupAnchorMenu();
if (!this._downEvent) return;
this._downEvent = false;
- if (this.props.isContentActive(true) && !(e.nativeEvent as any).dash) {
+ if (this._editorView?.state.selection.empty && this.props.isContentActive(true) && !(e.nativeEvent as any).dash) {
const editor = this._editorView!;
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
!this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 8d43c33f0..3898490d3 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -108,7 +108,7 @@ export const marks: { [index: string]: MarkSpec } = {
node.attrs.title,
],
]
- : ['a', { class: anchorids, 'data-targethrefs': targethrefs, title: node.attrs.title, 'data-noPreview': node.attrs.noPreview, location: node.attrs.location, style: `text-decoration: underline` }, 0];
+ : ['a', { class: anchorids, 'data-targethrefs': targethrefs, title: node.attrs.title, 'data-noPreview': node.attrs.noPreview, location: node.attrs.location, style: `text-decoration: underline; cursor: default` }, 0];
},
},
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 226fd8d7d..4a60c99ec 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -129,8 +129,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc;
clearSelectedArray = () => this.selectedArray.clear();
- addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc);
- removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc);
+ addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc));
+ removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc));
_unmounting = false;
@action
@@ -211,12 +211,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
nextSlide = (slideNum?: number) => {
const nextSlideInd = slideNum ?? this.itemIndex + 1;
let curSlideInd = nextSlideInd;
- const resetSelection = action(() => {
- this.clearSelectedArray();
- for (let i = nextSlideInd; i <= curSlideInd; i++) {
- this.addToSelectedArray(this.childDocs[i]);
- }
- });
CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.());
this.clearSelectedArray();
const doGroupWithUp =
@@ -224,6 +218,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
() => {
if (nextSelected < this.childDocs.length) {
if (force || this.childDocs[nextSelected].groupWithUp) {
+ this.addToSelectedArray(this.childDocs[nextSelected]);
const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1;
if (serial) {
this.gotoDocument(nextSelected, this.activeItem, true, async () => {
@@ -232,7 +227,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
doGroupWithUp(nextSelected + 1)();
});
} else {
- this.gotoDocument(nextSelected, this.activeItem, undefined, resetSelection);
+ this.gotoDocument(nextSelected, this.activeItem, true);
curSlideInd = this.itemIndex;
doGroupWithUp(nextSelected + 1)();
}
@@ -513,24 +508,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
console.log('Finish Slide Nav: ' + targetDoc.title);
targetDoc[AnimationSym] = undefined;
};
- const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null);
- const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
- const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
- const includesDoc = () => (DocumentManager.Instance.getDocumentView(targetDoc) ? true : false); // DocListCast(presCollection?.data).includes(targetDoc);
- const tabMap = CollectionDockingView.Instance?.tabMap;
- const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc === srcContext || tab.DashDoc === targetDoc);
- // Handles the setting of presCollection
- if (includesDoc()) {
- //Case 1: Pres collection should not change as it is already the same
- } else if (tab !== undefined) {
- // Case 2: Pres collection should update
- this.layoutDoc.presCollection = srcContext;
- }
const selViewCache = Array.from(this.selectedArray);
const dragViewCache = Array.from(this._dragArray);
const eleViewCache = Array.from(this._eleArray);
const resetSelection = action(() => {
- if (!includesDoc()) {
+ if (!this.props.isSelected()) {
const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
if (presDocView) SelectionManager.SelectView(presDocView, false);
this.clearSelectedArray();
@@ -542,17 +524,28 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
const createDocView = (doc: Doc, finished?: () => void) => {
DocumentManager.Instance.AddViewRenderedCb(doc, () => finished?.());
- (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.lightbox);
- this.layoutDoc.presCollection = targetDoc;
+ LightboxView.AddDocTab(doc, OpenWhere.lightbox);
};
- PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc() || tab ? finished : resetSelection);
+ PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, resetSelection);
};
- static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, srcContext: Doc, finished?: () => void) {
+ static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, finished?: () => void) {
if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) {
(DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
return;
}
+ const options: DocFocusOptions = {
+ willPan: activeItem.presMovement !== PresMovement.None,
+ willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center,
+ zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1),
+ zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500),
+ effect: activeItem,
+ noSelect: true,
+ originatingDoc: activeItem,
+ easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any,
+ zoomTextSelections: BoolCast(activeItem.presZoomText),
+ playAudio: BoolCast(activeItem.presPlayAudio),
+ };
const restoreLayout = () => {
// After navigating to the document, if it is added as a presPinView then it will
// adjust the pan and scale to that of the pinView when it was added.
@@ -562,47 +555,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
PresBox.restoreTargetDocView(DocumentManager.Instance.getFirstDocumentView(targetDoc), { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500));
}
};
- // If openDocument is selected then it should open the document for the user
- if (activeItem.openDocument) {
- LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc);
- setTimeout(restoreLayout);
- } else {
- if (targetDoc) {
- const options: DocFocusOptions = {
- willPan: activeItem.presMovement !== PresMovement.None,
- willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center,
- zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1),
- zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500),
- effect: activeItem,
- noSelect: true,
- originatingDoc: activeItem,
- easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any,
- zoomTextSelections: BoolCast(activeItem.presZoomText),
- playAudio: BoolCast(activeItem.presPlayAudio),
- };
- if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined;
- var containerDocContext = srcContext ? [srcContext] : [];
- while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) {
- containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
- }
- const testTarget = containerDocContext.length ? containerDocContext[0] : targetDoc;
- if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(testTarget)) {
- DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => {
- if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(LightboxView.LightboxDoc)) {
- DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished);
- restoreLayout();
- } else {
- LightboxView.SetLightboxDoc(undefined);
- DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished);
- restoreLayout();
- }
- });
- return;
- }
- DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished);
- restoreLayout();
- } else restoreLayout();
+ const finishAndRestoreLayout = () => {
+ finished?.();
+ restoreLayout();
+ };
+ const containerDocContext = DocumentManager.GetContextPath(targetDoc);
+
+ let context = containerDocContext.length ? containerDocContext[0] : targetDoc;
+ if (activeItem.presOpenInLightbox) {
+ if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(DocCast(targetDoc.annotationOn) ?? targetDoc))) {
+ context = DocCast(targetDoc.annotationOn) ?? targetDoc;
+ LightboxView.SetLightboxDoc(context); // openInTab(targetDoc);
+ }
}
+ if (targetDoc) {
+ if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined;
+
+ DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => {
+ if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(context.annotationOn) ?? context)) {
+ LightboxView.SetLightboxDoc(undefined);
+ }
+ DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finishAndRestoreLayout);
+ });
+ } else finishAndRestoreLayout();
}
/**
@@ -615,38 +590,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const curDoc = Cast(doc, Doc, null);
const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
- if (tagDoc === this.layoutDoc.presCollection) {
- tagDoc.opacity = 1;
- } else {
- if (curDoc.presHide) {
- if (index !== this.itemIndex) {
- tagDoc.opacity = 1;
- }
+ if (curDoc.presHide) {
+ if (index !== this.itemIndex) {
+ tagDoc.opacity = 1;
}
- const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex);
- if (curDoc.presHideBefore && index === hidingIndBef) {
- if (index > this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideAfter) {
- tagDoc.opacity = 1;
- }
+ }
+ const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex);
+ if (curDoc.presHideBefore && index === hidingIndBef) {
+ if (index > this.itemIndex) {
+ tagDoc.opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideAfter) {
+ tagDoc.opacity = 1;
}
- const hidingIndAft = itemIndexes
- .slice()
- .reverse()
- .find(item => item < this.itemIndex);
- if (curDoc.presHideAfter && index === hidingIndAft) {
- if (index < this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideBefore) {
- tagDoc.opacity = 1;
- }
+ }
+ const hidingIndAft = itemIndexes
+ .slice()
+ .reverse()
+ .find(item => item < this.itemIndex);
+ if (curDoc.presHideAfter && index === hidingIndAft) {
+ if (index < this.itemIndex) {
+ tagDoc.opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideBefore) {
+ tagDoc.opacity = 1;
}
- const hidingInd = itemIndexes.find(item => item === this.itemIndex);
- if (curDoc.presHide && index === hidingInd) {
- if (index === this.itemIndex) {
- tagDoc.opacity = 0;
- }
+ }
+ const hidingInd = itemIndexes.find(item => item === this.itemIndex);
+ if (curDoc.presHide && index === hidingInd) {
+ if (index === this.itemIndex) {
+ tagDoc.opacity = 0;
}
}
});
@@ -894,8 +865,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
selectElement = async (doc: Doc) => {
CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.());
this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
- if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0);
- else this.updateCurrentPresentation(DocCast(doc.context));
+ // if (doc.presPinView) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0);
+ // else
+ this.updateCurrentPresentation(DocCast(doc.context));
};
//Command click
@@ -1043,7 +1015,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get order() {
const order: JSX.Element[] = [];
const docs: Doc[] = [];
- const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
+ const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement();
const dv = DocumentManager.Instance.getDocumentView(presCollection);
this.childDocs
.filter(doc => Cast(doc.presentationTargetDoc, Doc, null))
@@ -1209,8 +1181,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
@action
updateOpenDoc = (activeItem: Doc) => {
- activeItem.openDocument = !activeItem.openDocument;
- this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument));
+ activeItem.presOpenInLightbox = !activeItem.presOpenInLightbox;
+ this.selectedArray.forEach(doc => (doc.presOpenInLightbox = activeItem.presOpenInLightbox));
};
@undoBatch
@action
@@ -1255,8 +1227,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get transitionDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
- const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection;
- const isPinWithView: boolean = BoolCast(activeItem.presPinView);
const presEffect = (effect: PresEffect) => (
<div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect)}>
{effect}
@@ -1309,11 +1279,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
{this.movementName(activeItem)}
<FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
<div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={StopEvent} style={{ display: this._openMovementDropdown ? 'grid' : 'none' }}>
- {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.None)}
+ {presMovement(PresMovement.None)}
{presMovement(PresMovement.Center)}
{presMovement(PresMovement.Zoom)}
{presMovement(PresMovement.Pan)}
- {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.Jump)}
+ {presMovement(PresMovement.Jump)}
</div>
</div>
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
@@ -1355,29 +1325,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="ribbon-box">
Visibility {'&'} Duration
<div className="ribbon-doubleButton">
- {isPresCollection ? null : (
- <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}>
- <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
- Hide before
- </div>
- </Tooltip>
- )}
- {isPresCollection ? null : (
- <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
- <div className={`ribbon-toggle ${activeItem.presHide ? 'active' : ''}`} onClick={() => this.updateHide(activeItem)}>
- Hide
- </div>
- </Tooltip>
- )}
- {isPresCollection ? null : (
- <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
- <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
- Hide after
- </div>
- </Tooltip>
- )}
+ <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
+ Hide before
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHide ? 'active' : ''}`} onClick={() => this.updateHide(activeItem)}>
+ Hide
+ </div>
+ </Tooltip>
+
+ <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
+ Hide after
+ </div>
+ </Tooltip>
+
<Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
+ <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presOpenInLightbox ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
Lightbox
</div>
</Tooltip>
@@ -1412,48 +1378,46 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</>
)}
</div>
- {isPresCollection ? null : (
- <div className="ribbon-box">
- Effects
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Play Audio Annotation</div>
- <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} />
- </div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Zoom Text Selections</div>
- <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} />
- </div>
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this._openEffectDropdown = !this._openEffectDropdown;
- })}
- style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
- {effect?.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this._openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
- {presEffect(PresEffect.None)}
- {presEffect(PresEffect.Fade)}
- {presEffect(PresEffect.Flip)}
- {presEffect(PresEffect.Rotate)}
- {presEffect(PresEffect.Bounce)}
- {presEffect(PresEffect.Roll)}
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}>
- <div className="presBox-subheading">Effect direction</div>
- <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</div>
- </div>
- <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}>
- {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
- {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
- {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
- {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
- {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+ <div className="ribbon-box">
+ Effects
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Play Audio Annotation</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Zoom Text Selections</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} />
+ </div>
+ <div
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openEffectDropdown = !this._openEffectDropdown;
+ })}
+ style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ {effect?.toString()}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this._openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
+ {presEffect(PresEffect.None)}
+ {presEffect(PresEffect.Fade)}
+ {presEffect(PresEffect.Flip)}
+ {presEffect(PresEffect.Rotate)}
+ {presEffect(PresEffect.Bounce)}
+ {presEffect(PresEffect.Roll)}
</div>
</div>
- )}
+ <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}>
+ <div className="presBox-subheading">Effect direction</div>
+ <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</div>
+ </div>
+ <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}>
+ {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+ {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+ {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+ {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+ {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+ </div>
+ </div>
<div className="ribbon-final-box">
<div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
Apply to all
@@ -1658,7 +1622,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get newDocumentToolbarDropdown() {
return (
<div
- className={'presBox-toolbar-dropdown'}
+ className="presBox-toolbar-dropdown"
style={{ display: this._newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
onClick={e => e.stopPropagation()}
onPointerUp={e => e.stopPropagation()}
@@ -1794,7 +1758,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (freeform && layout) doc = this.createTemplate(layout, title);
if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title });
if (doc) {
- const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
+ const tabMap = CollectionDockingView.Instance?.tabMap;
+ const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc;
+ const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentationTargetDoc ?? tab;
const data = Cast(presCollection?.data, listSpec(Doc));
const presData = Cast(this.rootDoc.data, listSpec(Doc));
if (data && presData) {
@@ -2300,12 +2266,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
static NavigateToDoc(bestTarget: Doc, activeItem: Doc) {
- const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null);
const openInTab = (doc: Doc, finished?: () => void) => {
CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
finished?.();
};
- PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext);
+ PresBox.NavigateToTarget(bestTarget, activeItem, openInTab);
}
}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f1c97d26a..788900b46 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -365,8 +365,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
// a previously recorded video will have timecode defined
- static videoIsRecorded = (activeItem: Doc) => {
- const casted = Cast(activeItem.recording, Doc, null);
+ static videoIsRecorded = (activeItem: Opt<Doc>) => {
+ const casted = Cast(activeItem?.recording, Doc, null);
return casted && 'currentTimecode' in casted;
};
@@ -381,10 +381,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
static removeEveryExistingRecordingInOverlay = () => {
// Remove every recording that already exists in overlay view
DocListCast(Doc.MyOverlayDocs.data).forEach(doc => {
- // if it's a recording video, don't remove from overlay (user can lose data)
- if (!PresElementBox.videoIsRecorded(DocCast(doc.slides))) return;
-
if (doc.slides !== null) {
+ // if it's a recording video, don't remove from overlay (user can lose data)
+ if (!PresElementBox.videoIsRecorded(DocCast(doc.slides))) return;
+
Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc);
}
});
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 2fb795b06..9af686d83 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -11,13 +11,13 @@ import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
import { LinkPopup } from '../linking/LinkPopup';
import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu';
import './AnchorMenu.scss';
-import { truncate } from 'lodash';
@observer
export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
static Instance: AnchorMenu;
private _disposer: IReactionDisposer | undefined;
+ private _disposer2: IReactionDisposer | undefined;
private _commentCont = React.createRef<HTMLButtonElement>();
private _palette = [
'rgba(208, 2, 27, 0.8)',
@@ -37,9 +37,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
'rgba(0, 0, 0, 0.8)',
];
- @observable private _keyValue: string = '';
- @observable private _valueValue: string = '';
- @observable private _added: boolean = false;
@observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)';
@observable private _showLinkPopup: boolean = false;
@@ -56,9 +53,9 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public Highlight: (color: string, isTargetToggler: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
public Delete: () => void = unimplementedFunction;
- public AddTag: (key: string, value: string) => boolean = returnFalse;
public PinToPres: () => void = unimplementedFunction;
public MakeTargetToggle: () => void = unimplementedFunction;
+ public ShowTargetTrail: () => void = unimplementedFunction;
public IsTargetToggler: () => boolean = returnFalse;
public get Active() {
return this._left > 0;
@@ -71,7 +68,17 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
AnchorMenu.Instance._canFade = false;
}
+ componentWillUnmount() {
+ this._disposer?.();
+ this._disposer2?.();
+ }
+
componentDidMount() {
+ this._disposer2 = reaction(
+ () => this._opacity,
+ opacity => !opacity && (this._showLinkPopup = false),
+ { fireImmediately: true }
+ );
this._disposer = reaction(
() => SelectionManager.Views(),
selected => {
@@ -175,82 +182,62 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
this.highlightColor = Utils.colorString(col);
};
- @action keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._keyValue = e.currentTarget.value;
- };
- @action valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._valueValue = e.currentTarget.value;
- };
- @action addTag = (e: React.PointerEvent) => {
- if (this._keyValue.length > 0 && this._valueValue.length > 0) {
- this._added = this.AddTag(this._keyValue, this._valueValue);
- setTimeout(
- action(() => (this._added = false)),
- 1000
- );
- }
- };
-
render() {
const buttons =
- this.Status === 'marquee'
- ? [
- this.highlighter,
-
- <Tooltip key="annotate" title={<div className="dash-tooltip">{'Drag to Place Annotation'}</div>}>
- <button className="antimodeMenu-button annotate" ref={this._commentCont} onPointerDown={this.pointerDown} style={{ cursor: 'grab' }}>
- <FontAwesomeIcon icon="comment-alt" size="lg" />
- </button>
- </Tooltip>,
- AnchorMenu.Instance.OnAudio === unimplementedFunction ? (
- <></>
- ) : (
- <Tooltip key="annoaudiotate" title={<div className="dash-tooltip">{'Click to Record Annotation'}</div>}>
- <button className="antimodeMenu-button annotate" onPointerDown={this.audioDown} style={{ cursor: 'grab' }}>
- <FontAwesomeIcon icon="microphone" size="lg" />
- </button>
- </Tooltip>
- ),
- <Tooltip key="link" title={<div className="dash-tooltip">{'Find document to link to selected text'}</div>}>
- <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
- <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(1.5)' }} icon={'search'} size="lg" />
- <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(0.5)', transformOrigin: 'top left', top: 12, left: 12 }} icon={'link'} size="lg" />
- </button>
- </Tooltip>,
- <LinkPopup key="popup" showPopup={this._showLinkPopup} linkCreateAnchor={this.onMakeAnchor} />,
- AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? (
- <></>
- ) : (
- <Tooltip key="crop" title={<div className="dash-tooltip">{'Click/Drag to create cropped image'}</div>}>
- <button className="antimodeMenu-button annotate" onPointerDown={this.cropDown} style={{ cursor: 'grab' }}>
- <FontAwesomeIcon icon="image" size="lg" />
- </button>
- </Tooltip>
- ),
- ]
- : [
- <Tooltip key="trash" title={<div className="dash-tooltip">{'Remove Link Anchor'}</div>}>
- <button className="antimodeMenu-button" onPointerDown={this.Delete}>
- <FontAwesomeIcon icon="trash-alt" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="Pin" title={<div className="dash-tooltip">{'Pin to Presentation'}</div>}>
- <button className="antimodeMenu-button" onPointerDown={this.PinToPres}>
- <FontAwesomeIcon icon="map-pin" size="lg" />
- </button>
- </Tooltip>,
- <Tooltip key="toggle" title={<div className="dash-tooltip">{'make target visibility toggle on click'}</div>}>
- <button className="antimodeMenu-button" style={{ color: this.IsTargetToggler() ? 'black' : 'white', backgroundColor: this.IsTargetToggler() ? 'white' : 'black' }} onPointerDown={this.MakeTargetToggle}>
- <FontAwesomeIcon icon="thumbtack" size="lg" />
- </button>
- </Tooltip>,
- // <div key="7" className="anchorMenu-addTag" >
- // <input onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
- // <input onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
- // </div>,
- // <button key="8" className="antimodeMenu-button" title={`Add tag: ${this._keyValue} with value: ${this._valueValue}`} onPointerDown={this.addTag}>
- // <FontAwesomeIcon style={{ transition: "all .2s" }} color={this._added ? "#42f560" : "white"} icon="check" size="lg" /></button>,
- ];
+ this.Status === 'marquee' ? (
+ <>
+ {this.highlighter}
+ <Tooltip key="annotate" title={<div className="dash-tooltip">Drag to Place Annotation</div>}>
+ <button className="antimodeMenu-button annotate" ref={this._commentCont} onPointerDown={this.pointerDown} style={{ cursor: 'grab' }}>
+ <FontAwesomeIcon icon="comment-alt" size="lg" />
+ </button>
+ </Tooltip>
+ {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
+ <Tooltip key="annoaudiotate" title={<div className="dash-tooltip">Click to Record Annotation</div>}>
+ <button className="antimodeMenu-button annotate" onPointerDown={this.audioDown} style={{ cursor: 'grab' }}>
+ <FontAwesomeIcon icon="microphone" size="lg" />
+ </button>
+ </Tooltip>
+ )}
+ <Tooltip key="link" title={<div className="dash-tooltip">Find document to link to selected text</div>}>
+ <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup}>
+ <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(1.5)' }} icon={'search'} size="lg" />
+ <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(0.5)', transformOrigin: 'top left', top: 12, left: 12 }} icon={'link'} size="lg" />
+ </button>
+ </Tooltip>
+ <LinkPopup key="popup" showPopup={this._showLinkPopup} linkCreateAnchor={this.onMakeAnchor} />,
+ {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
+ <Tooltip key="crop" title={<div className="dash-tooltip">Click/Drag to create cropped image</div>}>
+ <button className="antimodeMenu-button annotate" onPointerDown={this.cropDown} style={{ cursor: 'grab' }}>
+ <FontAwesomeIcon icon="image" size="lg" />
+ </button>
+ </Tooltip>
+ )}
+ </>
+ ) : (
+ <>
+ <Tooltip key="trash" title={<div className="dash-tooltip">Remove Link Anchor</div>}>
+ <button className="antimodeMenu-button" onPointerDown={this.Delete}>
+ <FontAwesomeIcon icon="trash-alt" size="lg" />
+ </button>
+ </Tooltip>
+ <Tooltip key="Pin" title={<div className="dash-tooltip">Pin to Presentation</div>}>
+ <button className="antimodeMenu-button" onPointerDown={this.PinToPres}>
+ <FontAwesomeIcon icon="map-pin" size="lg" />
+ </button>
+ </Tooltip>
+ <Tooltip key="trail" title={<div className="dash-tooltip">Show Linked Trail</div>}>
+ <button className="antimodeMenu-button" onPointerDown={this.ShowTargetTrail}>
+ <FontAwesomeIcon icon="taxi" size="lg" />
+ </button>
+ </Tooltip>
+ <Tooltip key="toggle" title={<div className="dash-tooltip">make target visibility toggle on click</div>}>
+ <button className="antimodeMenu-button" style={{ color: this.IsTargetToggler() ? 'black' : 'white', backgroundColor: this.IsTargetToggler() ? 'white' : 'black' }} onPointerDown={this.MakeTargetToggle}>
+ <FontAwesomeIcon icon="thumbtack" size="lg" />
+ </button>
+ </Tooltip>
+ </>
+ );
return this.getElement(buttons);
}
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index d8e44ae9d..0a8c69881 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -65,7 +65,6 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
AnchorMenu.Instance.Status = 'annotation';
AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this);
AnchorMenu.Instance.Pinned = false;
- AnchorMenu.Instance.AddTag = this.addTag.bind(this);
AnchorMenu.Instance.PinToPres = this.pinToPres;
AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
@@ -77,12 +76,6 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
}
};
- addTag = (key: string, value: string): boolean => {
- const valNum = parseInt(value);
- this.annoTextRegion[key] = isNaN(valNum) ? value : valNum;
- return true;
- };
-
render() {
const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion);
return (
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index aac488559..7e2a5a237 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -10,6 +10,7 @@ import { DocUtils } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { LinkManager } from '../../util/LinkManager';
+import { undoBatch } from '../../util/UndoManager';
import { CollectionDockingView } from '../collections/CollectionDockingView';
import { ViewBoxBaseComponent } from '../DocComponent';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -113,14 +114,12 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, false));
});
- // TODO: nda -- Change this method to change what happens when you click on the item.
+ @undoBatch
makeLink = action((linkTo: Doc) => {
- if (this.props.linkCreateAnchor) {
- const linkFrom = this.props.linkCreateAnchor();
- if (linkFrom) {
- const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo });
- link && this.props.linkCreated?.(link);
- }
+ const linkFrom = this.props.linkCreateAnchor?.();
+ if (linkFrom) {
+ const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo });
+ link && this.props.linkCreated?.(link);
}
});