aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/AudioBox.tsx23
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx30
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx13
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx49
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx35
-rw-r--r--src/client/views/nodes/DocumentIcon.tsx4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx44
-rw-r--r--src/client/views/nodes/DocumentView.tsx1371
-rw-r--r--src/client/views/nodes/EquationBox.tsx6
-rw-r--r--src/client/views/nodes/FieldView.tsx113
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx35
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx68
-rw-r--r--src/client/views/nodes/LabelBox.scss5
-rw-r--r--src/client/views/nodes/LabelBox.tsx27
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx21
-rw-r--r--src/client/views/nodes/LinkBox.tsx16
-rw-r--r--src/client/views/nodes/LinkDescriptionPopup.tsx31
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx13
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx20
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx12
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx5
-rw-r--r--src/client/views/nodes/MapBox/MapPushpinBox.tsx4
-rw-r--r--src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx30
-rw-r--r--src/client/views/nodes/PDFBox.tsx39
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx12
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx13
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx8
-rw-r--r--src/client/views/nodes/VideoBox.tsx57
-rw-r--r--src/client/views/nodes/WebBox.tsx55
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx10
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx8
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx72
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx3
-rw-r--r--src/client/views/nodes/importBox/ImportElementBox.tsx6
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx49
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx13
40 files changed, 1130 insertions, 1198 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 908cd5dc0..8a38ef663 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -5,6 +5,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../fields/DateField';
import { Doc } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { ComputedField } from '../../../fields/ScriptField';
import { Cast, DateCast, NumCast } from '../../../fields/Types';
import { AudioField, nullAudio } from '../../../fields/URLField';
@@ -19,8 +20,7 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import './AudioBox.scss';
-import { DocFocusOptions } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
/**
@@ -121,7 +121,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
if (this.path) {
this.mediaState = media_state.Paused;
this.setPlayheadTime(NumCast(this.layoutDoc.clipStart));
@@ -211,7 +211,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// removes from currently playing display
@action
removeCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (CollectionStackedTimeline.CurrentlyPlaying && docView) {
const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView);
index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1);
@@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// adds doc to currently playing display
@action
addCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (!CollectionStackedTimeline.CurrentlyPlaying) {
CollectionStackedTimeline.CurrentlyPlaying = [];
}
@@ -374,9 +374,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
action(() => {
const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
const textField = Doc.LayoutFieldKey(newDoc);
- Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc;
- Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
- Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
+ const newDocData = newDoc[DocData];
+ newDocData[`${textField}_recordingSource`] = this.dataDoc;
+ newDocData[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
+ newDocData.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
if (Doc.IsInMyOverlay(this.Document)) {
newDoc.overlayX = this.Document.x;
newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height);
@@ -432,7 +433,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
// plays link
- playLink = (link: Doc, options: DocFocusOptions) => {
+ playLink = (link: Doc, options: FocusViewOptions) => {
if (link.annotationOn === this.Document) {
if (!this.layoutDoc.dontAutoPlayFollowedLinks) {
this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link));
@@ -567,8 +568,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const [xp, yp] = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y);
de.complete.docDragData && this.timeline?.internalDocDrop(e, de, de.complete.docDragData, xp);
},
- this.layoutDoc,
- undefined
+ this.layoutDoc
);
}
};
@@ -717,7 +717,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
renderDepth={this._props.renderDepth + 1}
startTag={'_timecodeToShow' /* audioStart */}
endTag={'_timecodeToHide' /* audioEnd */}
- bringToFront={emptyFunction}
playFrom={this.playFrom}
setTime={this.setPlayheadTime}
playing={this.playing}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ad5aabc21..0ae4ed62c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -12,10 +12,11 @@ import { DocumentManager } from '../../util/DocumentManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { DocComponent } from '../DocComponent';
+import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import './CollectionFreeFormDocumentView.scss';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView';
+import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView';
import { FieldViewProps } from './FieldView';
export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps {
@@ -37,8 +38,8 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView
CollectionFreeFormView: CollectionFreeFormView;
}
@observer
-export class CollectionFreeFormDocumentViewWrapper extends DocComponent<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>() implements CollectionFreeFormDocumentViewProps {
- constructor(props: any) {
+export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent<CollectionFreeFormDocumentViewWrapperProps> {
+ constructor(props: CollectionFreeFormDocumentViewWrapperProps) {
super(props);
makeObservable(this);
}
@@ -59,6 +60,9 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
CollectionFreeFormView = this.props.CollectionFreeFormView; // needed for type checking
RenderCutoffProvider = this.props.RenderCutoffProvider; // needed for type checking
+ get Document() {
+ return this._props.Document;
+ }
@computed get WrapperKeys() {
return Object.keys(this).filter(key => key.startsWith('w_')).map(key => key.replace('w_', ''))
.map(key => ({upper:key, lower:key[0].toLowerCase() + key.substring(1)})); // prettier-ignore
@@ -100,7 +104,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
);
}
}
-export interface CollectionFreeFormDocumentViewProps {
+export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
w_X: () => number;
w_Y: () => number;
w_Z: () => number;
@@ -121,8 +125,8 @@ export interface CollectionFreeFormDocumentViewProps {
}
@observer
-export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps & DocumentViewProps>() {
- constructor(props: any) {
+export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps>() {
+ constructor(props: CollectionFreeFormDocumentViewProps) {
super(props);
makeObservable(this);
}
@@ -149,7 +153,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return this._props.CollectionFreeFormView;
}
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (doc === this.layoutDoc) {
switch (property) {
case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children
@@ -227,9 +231,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
});
}
- @action public float = () => {
+ float = () => {
const topDoc = this.Document;
- const containerDocView = this._props.docViewPath().lastElement();
+ const containerDocView = this._props.containerViewPath?.().lastElement();
const screenXf = containerDocView?.screenToContentsTransform();
if (screenXf) {
SelectionManager.DeselectAll();
@@ -252,9 +256,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
};
nudge = (x: number, y: number) => {
- const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y);
- this._props.Document.x = this._props.w_X() + locX;
- this._props.Document.y = this._props.w_Y() + locY;
+ const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y);
+ this.Document.x = this._props.w_X() + locX;
+ this.Document.y = this._props.w_Y() + locY;
};
screenToLocalTransform = () =>
this._props
@@ -288,7 +292,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
zIndex: this._props.w_ZIndex?.(),
display: this._props.w_Width?.() ? undefined : 'none',
}}>
- {this._props.RenderCutoffProvider(this._props.Document) ? (
+ {this._props.RenderCutoffProvider(this.Document) ? (
<div style={{ position: 'absolute', width: this._props.PanelWidth(), height: this._props.PanelHeight(), background: 'lightGreen' }} />
) : (
<DocumentView {...passOnProps} CollectionFreeFormDocumentView={this.returnThis} styleProvider={this.styleProvider} ScreenToLocalTransform={this.screenToLocalTransform} isGroupActive={this.isGroupActive} />
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 5e7e568b0..116dc48a6 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -8,20 +8,20 @@ import { DocCast, NumCast, StrCast } from '../../../fields/Types';
import { DocUtils, Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { StyleProp } from '../StyleProvider';
import './ComparisonBox.scss';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView';
+import { DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
@observer
-export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ComparisonBox, fieldKey);
}
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -35,7 +35,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
return '_' + this._props.fieldKey + '_clipWidth';
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
this._disposers[disposerId]?.();
@@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
e => this.clearDoc(which)
);
};
- docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
if (property === StyleProp.PointerEvents) return 'none';
return this._props.styleProvider?.(doc, props, property);
};
@@ -178,6 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
{...this._props}
Document={targetDoc}
TemplateDataDocument={undefined}
+ containerViewPath={this.DocumentView?.().docViewPath}
moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2}
NativeWidth={returnZero}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 5a55ca764..8365f4770 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
-import { ObservableMap, action, computed, observable, runInAction } from 'mobx';
+import { ObservableMap, action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils';
@@ -14,14 +14,13 @@ import { TraceMobx } from '../../../../fields/util';
import { Docs } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { MarqueeAnnotator } from '../../MarqueeAnnotator';
import { SidebarAnnos } from '../../SidebarAnnos';
-import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
import './DataVizBox.scss';
import { Histogram } from './components/Histogram';
@@ -37,22 +36,28 @@ export enum DataVizView {
}
@observer
-export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
- private _ffref = React.createRef<CollectionFreeFormView>();
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined;
- @observable schemaDataVizChildren: any = undefined;
+ @observable _schemaDataVizChildren: any = undefined;
@observable _marqueeing: number[] | undefined = undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ this._props.setContentViewBox?.(this);
+ }
+
@computed get annotationLayer() {
TraceMobx();
return <div className="dataVizBox-annotationLayer" style={{ height: this._props.PanelHeight(), width: this._props.PanelWidth() }} ref={this._annotationLayer} />;
}
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -211,12 +216,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
.ScreenToLocalTransform()
.scale(this._props.NativeDimScaling?.() || 1)
.transformDirection(delta[0], delta[1]);
- const fullWidth = this._props.width;
- const mapWidth = fullWidth! - this.sidebarWidth();
+ const fullWidth = NumCast(this.layoutDoc._width);
+ const mapWidth = fullWidth - this.sidebarWidth();
if (this.sidebarWidth() + localDelta[0] > 0) {
this.layoutDoc._layout_showSidebar = true;
- this.layoutDoc._width = fullWidth! + localDelta[0];
- this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%';
+ this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+ this.layoutDoc._width = fullWidth + localDelta[0];
} else {
this.layoutDoc._layout_showSidebar = false;
this.layoutDoc._width = mapWidth;
@@ -228,7 +233,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
);
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar();
@@ -249,7 +254,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeDocument(doc, sidebarKey);
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
}
@@ -269,12 +274,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
axes: this.axes,
//width: this.SidebarShown? this._props.PanelWidth()*.9/1.2: this._props.PanelWidth() * 0.9,
height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
- width: (this._props.PanelWidth() / scale) * 0.9,
+ width: ((this._props.PanelWidth() - this.sidebarWidth()) / scale) * 0.9,
margin: { top: 10, right: 25, bottom: 75, left: 45 },
};
if (!this.records.length) return 'no data/visualization';
switch (this.dataVizView) {
- case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this._props.DocumentView} selectAxes={this.selectAxes} />;
+ case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this.DocumentView} selectAxes={this.selectAxes} />;
case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} vizBox={this} />;
case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
case DataVizView.PIECHART: return <PieChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)}
@@ -285,7 +290,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
onPointerDown = (e: React.PointerEvent): void => {
if ((this.Document._freeform_scale || 1) !== 1) return;
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
@@ -345,7 +350,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
render() {
if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) {
- this.schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length;
+ this._schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length;
this.updateSchemaViz();
}
@@ -366,7 +371,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}}
onWheel={e => e.stopPropagation()}
ref={this._mainCont}>
- <div className={'datatype-button'}>
+ <div className="datatype-button">
<Toggle text={' TABLE '} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} />
<Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} />
<Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} />
@@ -414,7 +419,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</div>
{this.sidebarHandle}
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
ref={this._marqueeref}
Document={this.Document}
@@ -422,7 +427,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
scrollTop={0}
annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)}
scaling={returnOne}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
addDocument={this.sidebarAddDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 4cc7fe4c8..07e179246 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -24,7 +24,6 @@ import { YoutubeBox } from './../../apis/youtube/YoutubeBox';
import { AudioBox } from './AudioBox';
import { ComparisonBox } from './ComparisonBox';
import { DataVizBox } from './DataVizBox/DataVizBox';
-import { DocumentViewProps } from './DocumentView';
import './DocumentView.scss';
import { EquationBox } from './EquationBox';
import { FieldView, FieldViewProps } from './FieldView';
@@ -114,14 +113,11 @@ export class HTMLtag extends React.Component<HTMLtagProps> {
}
}
+export interface DocumentContentsViewProps extends FieldViewProps {
+ layoutFieldKey: string;
+}
@observer
-export class DocumentContentsView extends ObservableReactComponent<
- DocumentViewProps &
- FieldViewProps & {
- setHeight?: (height: number) => void;
- layout_fieldKey: string;
- }
-> {
+export class DocumentContentsView extends ObservableReactComponent<DocumentContentsViewProps> {
constructor(props: any) {
super(props);
makeObservable(this);
@@ -131,8 +127,8 @@ export class DocumentContentsView extends ObservableReactComponent<
TraceMobx();
if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString;
if (!this.layoutDoc) return '<p>awaiting layout</p>';
- if (this._props.layout_fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString());
- const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layout_fieldKey ? this._props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string');
+ if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString());
+ const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string');
if (layout === undefined) return this._props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString();
if (typeof layout === 'string') return layout;
return '<p>Loading layout</p>';
@@ -140,30 +136,31 @@ export class DocumentContentsView extends ObservableReactComponent<
get layoutDoc() {
// bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script
- // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined);
+ // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined);
const template: Doc =
this._props.LayoutTemplate?.() ||
(this._props.LayoutTemplateString && this._props.Document) ||
- (this._props.layout_fieldKey && StrCast(this._props.Document[this._props.layout_fieldKey]) && this._props.Document) ||
- Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined);
+ (this._props.layoutFieldKey && StrCast(this._props.Document[this._props.layoutFieldKey]) && this._props.Document) ||
+ Doc.Layout(this._props.Document, this._props.layoutFieldKey ? Cast(this._props.Document[this._props.layoutFieldKey], Doc, null) : undefined);
return Doc.expandTemplateLayout(template, this._props.Document);
}
CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings {
const docOnlyProps = [
- // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
+ // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
'hideResizeHandles',
'hideTitle',
- 'contentPointerEvents',
- 'radialMenu',
+ 'bringToFront',
+ 'childContentPointerEvents',
'LayoutTemplateString',
'LayoutTemplate',
+ 'layoutFieldKey',
'dontCenter',
'contextMenuItems',
//'onClick', // don't need to omit this since it will be set
- 'onDoubleClick',
- 'onPointerDown',
- 'onPointerUp',
+ 'onDoubleClickScript',
+ 'onPointerDownScript',
+ 'onPointerUpScript',
];
const templateDataDoc = this._props.TemplateDataDocument ?? (this.layoutDoc !== this._props.Document ? this._props.Document[DocData] : undefined);
const list: BindingProps & React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLDivElement>, HTMLDivElement> = {
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index dfd610581..4a22766cc 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -25,11 +25,11 @@ export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> {
}
static get DocViews() {
- return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews;
+ return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.Contains(v)) : DocumentManager.Instance.DocumentViews;
}
render() {
const view = this._props.view;
- const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 };
+ const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 };
return (
<div
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index c549a146a..d1805308d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -17,6 +17,7 @@ import { DocumentView } from './DocumentView';
import { LinkDescriptionPopup } from './LinkDescriptionPopup';
import { TaskCompletionBox } from './TaskCompletedBox';
import { PinProps } from './trails';
+import { DocData } from '../../../fields/DocSymbols';
interface DocumentLinksButtonProps {
View: DocumentView;
@@ -152,47 +153,46 @@ export class DocumentLinksButton extends ObservableReactComponent<DocumentLinksB
DocumentLinksButton.AnnotationUri = undefined;
//!this._props.StartLink
} else if (startLink !== endLink) {
- endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
- startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
+ endLink = endLinkView?.ComponentView?.getAnchor?.(true, pinProps) || endLink;
+ startLink = DocumentLinksButton.StartLinkView?.ComponentView?.getAnchor?.(true) || startLink;
const linkDoc = DocUtils.MakeLink(startLink, endLink, { link_relationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
LinkManager.currentLink = linkDoc;
- if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
- // if linking from a Hypothes.is annotation
- Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
- Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
- Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
- const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
- Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc
- }
-
if (linkDoc) {
+ if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
+ // if linking from a Hypothes.is annotation
+ const linkDocData = linkDoc[DocData];
+ linkDocData.linksToAnnotation = true;
+ linkDocData.annotationId = DocumentLinksButton.AnnotationId;
+ linkDocData.annotationUri = DocumentLinksButton.AnnotationUri;
+ const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
+ Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc
+ }
+
TaskCompletionBox.textDisplayed = 'Link Created';
TaskCompletionBox.popupX = screenX;
TaskCompletionBox.popupY = screenY - 133;
TaskCompletionBox.taskCompleted = true;
- if (LinkDescriptionPopup.showDescriptions === 'ON' || !LinkDescriptionPopup.showDescriptions) {
- LinkDescriptionPopup.popupX = screenX;
- LinkDescriptionPopup.popupY = screenY - 100;
- LinkDescriptionPopup.descriptionPopup = true;
+ if (LinkDescriptionPopup.Instance.showDescriptions === 'ON' || !LinkDescriptionPopup.Instance.showDescriptions) {
+ LinkDescriptionPopup.Instance.popupX = screenX;
+ LinkDescriptionPopup.Instance.popupY = screenY - 100;
+ LinkDescriptionPopup.Instance.display = true;
}
const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
+ if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.Instance.popupX -= 190;
TaskCompletionBox.popupX -= 40;
}
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
+ if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.Instance.popupY -= 40;
TaskCompletionBox.popupY -= 40;
}
setTimeout(
- action(() => {
- TaskCompletionBox.taskCompleted = false;
- }),
+ action(() => (TaskCompletionBox.taskCompleted = false)),
2500
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6cc61ec62..8eb354e1e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,19 +3,17 @@ import { Dropdown, DropdownType, Type } from 'browndash-components';
import { Howl } from 'howler';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
-import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal';
import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
-import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols';
+import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
-import { RefField } from '../../../fields/RefField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { AudioField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { DocServer } from '../../DocServer';
@@ -33,34 +31,27 @@ import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { SharingManager } from '../../util/SharingManager';
import { SnappingManager } from '../../util/SnappingManager';
-import { Transform } from '../../util/Transform';
-import { UndoManager, undoBatch } from '../../util/UndoManager';
+import { UndoManager, undoBatch, undoable } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocComponent } from '../DocComponent';
+import { DocComponent, ViewBoxInterface } from '../DocComponent';
import { EditableView } from '../EditableView';
import { GestureOverlay } from '../GestureOverlay';
import { LightboxView } from '../LightboxView';
-import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
-import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
import './DocumentView.scss';
-import { FieldViewProps } from './FieldView';
+import { FieldViewProps, FieldViewSharedProps } from './FieldView';
import { KeyValueBox } from './KeyValueBox';
import { LinkAnchorBox } from './LinkAnchorBox';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails';
-import { PinProps, PresBox } from './trails/PresBox';
-
interface Window {
MediaRecorder: MediaRecorder;
}
-
declare class MediaRecorder {
- // whatever MediaRecorder has
- constructor(e: any);
+ constructor(e: any); // whatever MediaRecorder has
}
export enum OpenWhereMod {
@@ -89,118 +80,10 @@ export enum OpenWhere {
addRightKeyvalue = 'add:right:keyValue',
}
-export interface DocFocusOptions {
- willPan?: boolean; // determines whether to pan to target document
- willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document
- zoomScale?: number; // percent of containing frame to zoom into document
- zoomTime?: number;
- didMove?: boolean; // whether a document was changed during the showDocument process
- docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy
- instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
- preview?: boolean; // whether changes should be previewed by the componentView or written to the document
- effect?: Doc; // animation effect for focus
- noSelect?: boolean; // whether target should be selected after focusing
- playAudio?: boolean; // whether to play audio annotation on focus
- playMedia?: boolean; // whether to play start target videos
- openLocation?: OpenWhere; // where to open a missing document
- zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections
- toggleTarget?: boolean; // whether to toggle target on and off
- anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc
- easeFunc?: 'linear' | 'ease'; // transition method for scrolling
-}
-export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt<number>;
-export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => any;
-export interface DocComponentView {
- fieldKey?: string;
- annotationKey?: string;
- updateIcon?: () => void; // updates the icon representation of the document
- getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
- restoreView?: (viewSpec: Doc) => boolean;
- scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus
- brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms)
- getView?: (doc: Doc, options: DocFocusOptions) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
- addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
- addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
- select?: (ctrlKey: boolean, shiftKey: boolean) => void;
- focus?: (textAnchor: Doc, options: DocFocusOptions) => Opt<number>;
- isAnyChildContentActive?: () => boolean; // is any child content of the document active
- onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected
- getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
- setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
- playFrom?: (time: number, endTime?: number) => void;
- Pause?: () => void; // pause a media document (eg, audio/video)
- IsPlaying?: () => boolean; // is a media document playing
- TogglePause?: (keep?: boolean) => void; // toggle media document playing state
- setFocus?: () => void; // sets input focus to the componentView
- setData?: (data: Field | Promise<RefField | undefined>) => boolean;
- componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
- dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set<Doc>) => void;
- incrementalRendering?: () => void;
- infoUI?: () => JSX.Element | null;
- screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>;
- ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
- ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
- snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number };
- search?: (str: string, bwd?: boolean, clear?: boolean) => boolean;
-}
-// These props are passed to both FieldViews and DocumentViews
-export interface DocumentViewSharedProps {
- renderDepth: number;
- Document: Doc;
- TemplateDataDocument?: Doc;
- scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
- DocumentView?: () => DocumentView;
- CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
- fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
- isGroupActive?: () => string | undefined; // is this document part of a group that is active
- setContentView?: (view: DocComponentView) => any;
- PanelWidth: () => number;
- PanelHeight: () => number;
- docViewPath: () => DocumentView[];
- childFilters: () => string[];
- childFiltersByRanges: () => string[];
- styleProvider: Opt<StyleProviderFunc>;
- setTitleFocus?: () => void;
- focus: DocFocusFunc;
- layout_fitWidth?: (doc: Doc) => boolean | undefined;
- searchFilterDocs: () => Doc[];
- layout_showTitle?: () => string;
- whenChildContentsActiveChanged: (isActive: boolean) => void;
- rootSelected?: () => boolean; // whether the root of a template has been selected
- addDocTab: (doc: Doc, where: OpenWhere) => boolean;
- filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
- addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
- removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
- moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean;
- pinToPres: (document: Doc, pinProps: PinProps) => void;
- ScreenToLocalTransform: () => Transform;
- bringToFront: (doc: Doc, sendToBack?: boolean) => void;
- waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
- defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
- pointerEvents?: () => Opt<string>;
- treeViewDoc?: Doc;
- xPadding?: number;
- yPadding?: number;
- dontRegisterView?: boolean;
- childHideDecorationTitle?: boolean;
- childHideResizeHandles?: boolean;
- childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
- dropAction?: dropActionType;
- dragAction?: dropActionType;
- dragWhenActive?: boolean;
- dontHideOnDrag?: boolean;
- hideLinkButton?: boolean;
- hideCaptions?: boolean;
- ignoreAutoHeight?: boolean;
- forceAutoHeight?: boolean;
- suppressSetHeight?: boolean;
- disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
- onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
+export function returnEmptyDocViewList() {
+ return [] as DocumentView[];
}
-
-// these props are specific to DocuentViews
-export interface DocumentViewProps extends DocumentViewSharedProps {
- // properties specific to DocumentViews but not to FieldView
+export interface DocumentViewProps extends FieldViewSharedProps {
hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected
hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected
hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
@@ -209,37 +92,35 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
hideOpenButton?: boolean;
hideDeleteButton?: boolean;
hideLinkAnchors?: boolean;
+ hideLinkButton?: boolean;
+ hideCaptions?: boolean;
contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
- LayoutTemplateString?: string;
dontCenter?: 'x' | 'y' | 'xy';
- isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
- isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
+ childHideDecorationTitle?: boolean;
+ childHideResizeHandles?: boolean;
+ childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
+ dragWhenActive?: boolean;
+ dontHideOnDrag?: boolean;
+ suppressSetHeight?: boolean;
+ onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
NativeWidth?: () => number;
NativeHeight?: () => number;
- NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps
- LayoutTemplate?: () => Opt<Doc>;
contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[];
- onClick?: () => ScriptField;
- onDoubleClick?: () => ScriptField;
- onPointerDown?: () => ScriptField;
- onPointerUp?: () => ScriptField;
- onBrowseClick?: () => ScriptField | undefined;
- onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
dragStarting?: () => void;
dragEnding?: () => void;
}
-
-// these props are only available in DocumentViewIntenral
-export interface DocumentViewInternalProps extends DocumentViewProps {
- isSelected: () => boolean;
- select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
- DocumentView: () => DocumentView;
- viewPath: () => DocumentView[];
-}
-
@observer
-export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps>() {
+export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps>() {
+ // this makes mobx trace() statements more descriptive
+ public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore
public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered.
+
+ /**
+ * This function is filled in by MainView to allow non-viewBox views to add Docs as tabs without
+ * needing to know about/reference MainView
+ */
+ public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse;
+
private _disposers: { [name: string]: IReactionDisposer } = {};
private _doubleClickTimeout: NodeJS.Timeout | undefined;
private _singleClickFunc: undefined | (() => any);
@@ -252,72 +133,51 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
private _mainCont = React.createRef<HTMLDivElement>();
private _titleRef = React.createRef<EditableView>();
private _dropDisposer?: DragManager.DragDropDisposer;
- constructor(props: any) {
+ constructor(props: FieldViewProps & DocumentViewProps) {
super(props);
makeObservable(this);
}
- @observable _componentView: Opt<DocComponentView> = undefined; // needs to be accessed from DocumentView wrapper class
+ @observable _changingTitleField = false;
+ @observable _titleDropDownInnerWidth = 0; // width of menu dropdown when setting doc title
+ @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI )
+ @observable _isContentActive: boolean | undefined = undefined;
+ @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined;
+ @observable _componentView: Opt<ViewBoxInterface> = undefined; // needs to be accessed from DocumentView wrapper class
@observable _animateScaleTime: Opt<number> = undefined; // milliseconds for animating between views. defaults to 300 if not uset
@observable _animateScalingTo = 0;
- public get animateScaleTime() {
- return this._animateScaleTime ?? 100;
- }
- public get displayName() {
- return 'DocumentViewInternal(' + this._props.Document.title + ')';
- } // this makes mobx trace() statements more descriptive
+ get _contentDiv() { return this._mainCont.current; } // prettier-ignore
+ get _docView() { return this._props.DocumentView?.(); } // prettier-ignore
+
+ animateScaleTime = () => this._animateScaleTime ?? 100;
+ style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop);
+ @computed get layout_showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore
+ @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore
+ @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore
+ @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore
+ @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore
+ @computed get backgroundBoxColor() { return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':box'); } // prettier-ignore
+ @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore
+ @computed get layout_showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore
+ @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore
+ @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore
+ @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore
+ @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore
- public get ContentDiv() {
- return this._mainCont.current;
- }
- public get LayoutFieldKey() {
- return Doc.LayoutFieldKey(this.layoutDoc);
- }
- @computed get layout_showTitle() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowTitle) as Opt<string>;
- }
- @computed get NativeDimScaling() {
- return this._props.NativeDimScaling?.() || 1;
- }
- @computed get thumb() {
- return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png');
- }
- @computed get opacity() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Opacity);
- }
- @computed get boxShadow() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow);
- }
- @computed get borderRounding() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
- }
- @computed get widgetDecorations() {
- TraceMobx();
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Decorations);
- }
- @computed get backgroundBoxColor() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor + ':box');
- }
- @computed get docContents() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.DocContents);
- }
- @computed get headerMargin() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) || 0;
- }
- @computed get layout_showCaption() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowCaption) || 0;
+ @computed get onClickHandler() {
+ return this._props.onClickScript?.() ?? this._props.onBrowseClickScript?.() ?? ScriptCast(this.Document.onClick, ScriptCast(this.layoutDoc.onClick));
}
- @computed get titleHeight() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.TitleHeight) || 0;
+ @computed get onDoubleClickHandler() {
+ return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick, ScriptCast(this.Document.onDoubleClick));
}
- @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined;
- @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
- return this._pointerEvents;
+ @computed get onPointerDownHandler() {
+ return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown, ScriptCast(this.Document.onPointerDown));
}
- @computed get finalLayoutKey() {
- return StrCast(this.Document.layout_fieldKey, 'layout');
+ @computed get onPointerUpHandler() {
+ return this._props.onPointerUpScript?.() ?? ScriptCast(this.layoutDoc.onPointerUp, ScriptCast(this.Document.onPointerUp));
}
+
@computed get disableClickScriptFunc() {
const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
// prettier-ignore
@@ -327,23 +187,50 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
(onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))
);
}
- @computed get onClickHandler() {
- return this._props.onClick?.() ?? this._props.onBrowseClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null));
+ @computed get _rootSelected() {
+ return this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
}
- @computed get onDoubleClickHandler() {
- return this._props.onDoubleClick?.() ?? Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick;
+ /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive
+ @computed get _contentPointerEvents() {
+ TraceMobx();
+ return this._props.contentPointerEvents ??
+ ((!this.disableClickScriptFunc && //
+ this.onClickHandler &&
+ !this._props.onBrowseClickScript?.() &&
+ this.isContentActive() !== true) ||
+ this.isContentActive() === false)
+ ? 'none'
+ : this._pointerEvents;
}
- @computed get onPointerDownHandler() {
- return this._props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown);
+
+ // We need to use allrelatedLinks to get not just links to the document as a whole, but links to
+ // anchors that are not rendered as DocumentViews (marked as 'layout_unrendered' with their 'annotationOn' set to this document). e.g.,
+ // - PDF text regions are rendered as an Annotations without generating a DocumentView, '
+ // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link
+ // - and links to PDF/Web docs at a certain scroll location never create an explicit view.
+ // For each of these, we create LinkAnchorBox's on the border of the DocumentView.
+ @computed get directLinks() {
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(
+ link =>
+ (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) ||
+ (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) ||
+ ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) ||
+ ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document))
+ );
}
- @computed get onPointerUpHandler() {
- return this._props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp);
+ @computed get _allLinks() {
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document);
+ }
+
+ @computed get filteredLinks() {
+ return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines);
}
componentWillUnmount() {
this.cleanupHandlers(true);
}
- @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI )
componentDidMount() {
runInAction(() => (this._mounted = true));
@@ -363,47 +250,48 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{ fireImmediately: true }
);
this._disposers.pointerevents = reaction(
- () => this._props.styleProvider?.(this.Document, this._props, StyleProp.PointerEvents),
+ () => this.style(this.Document, StyleProp.PointerEvents),
pointerevents => (this._pointerEvents = pointerevents),
{ fireImmediately: true }
);
}
- preDropFunc = (e: Event, de: DragManager.DropEvent) => {
- const dropAction = this.layoutDoc.dropAction as dropActionType;
- if (de.complete.docDragData && this.isContentActive() && !this._props.treeViewDoc) {
- dropAction && (de.complete.docDragData.dropAction = dropAction);
+ preDrop = (e: Event, de: DragManager.DropEvent, dropAction: dropActionType) => {
+ const dragData = de.complete.docDragData;
+ if (dragData && this.isContentActive() && !this.props.dontRegisterView) {
+ dragData.dropAction = dropAction ? dropAction : dragData.dropAction;
e.stopPropagation();
}
};
setupHandlers() {
this.cleanupHandlers(false);
if (this._mainCont.current) {
- this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this._props.Document, this.preDropFunc);
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.Document, this.preDrop);
}
}
cleanupHandlers(unbrush: boolean) {
this._dropDisposer?.();
- unbrush && Doc.UnBrushDoc(this._props.Document);
+ unbrush && Doc.UnBrushDoc(this.Document);
Object.values(this._disposers).forEach(disposer => disposer?.());
}
startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
- if (this._mainCont.current) {
- const views = SelectionManager.Views.filter(dv => dv.docView?._mainCont.current);
- const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()];
+ const docView = this._docView;
+ if (this._mainCont.current && docView) {
+ const views = SelectionManager.Views.filter(dv => dv.ContentDiv);
+ const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [docView];
const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document));
- const screenXf = this.props.DocumentView().screenToViewTransform();
+ const screenXf = docView.screenToViewTransform();
const [left, top] = screenXf.inverse().transformPoint(0, 0);
dragData.offset = screenXf.transformDirection(x - left, y - top);
dragData.dropAction = dropAction;
- dragData.treeViewDoc = this._props.treeViewDoc;
dragData.removeDocument = this._props.removeDocument;
dragData.moveDocument = this._props.moveDocument;
- dragData.draggedViews = [this._props.DocumentView()];
+ dragData.draggedViews = [docView];
dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false;
+ this._componentView?.dragConfig?.(dragData);
DragManager.StartDocumentDrag(
- selected.map(dv => dv.docView!._mainCont.current!),
+ selected.map(dv => dv.ContentDiv!),
dragData,
x,
y,
@@ -412,29 +300,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
- defaultRestoreTargetView = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
- const targetMatch =
- Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document
- (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document
- ? true
- : false;
- return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined;
- };
-
// switches text input focus to the title bar of the document (and displays the title bar if it hadn't been)
setTitleFocus = () => {
if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title';
setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined
};
-
- public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse;
-
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- if (!this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+ const documentView = this._docView;
+ if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
let stopPropagate = true;
let preventDefault = true;
- !this.layoutDoc._keepZWhenDragged && this._props.bringToFront(this.Document);
+ !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
if (this.onDoubleClickHandler?.script) {
@@ -443,7 +320,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const func = () => this.onDoubleClickHandler.script.run( {
this: this.Document,
scriptContext: this._props.scriptContext,
- documentView: this._props.DocumentView(),
+ documentView,
clientX, clientY, altKey, shiftKey, ctrlKey,
value: undefined,
}, console.log );
@@ -451,7 +328,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
} else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) {
UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap');
SelectionManager.DeselectAll();
- Doc.UnBrushDoc(this._props.Document);
+ Doc.UnBrushDoc(this.Document);
} else {
this._singleClickFunc?.();
}
@@ -474,7 +351,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this: this.Document,
_readOnly_: false,
scriptContext: this._props.scriptContext,
- documentView: this._props.DocumentView(),
+ documentView,
clientX,
clientY,
shiftKey,
@@ -498,7 +375,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const sendToBack = e.altKey;
this._singleClickFunc =
// prettier-ignore
- clickFunc ?? (() => (sendToBack ? this._props.DocumentView()._props.bringToFront(this.Document, true) :
+ clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront?.(this.Document, true) :
this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ??
this._props.select(e.ctrlKey||e.shiftKey, e.metaKey)));
const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
@@ -517,12 +394,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onPointerDown = (e: React.PointerEvent): void => {
if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- this._longPressSelector = setTimeout(() => {
- if (DocumentView.LongPress) {
- this._props.select(false);
- }
- }, 1000);
- if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView();
+ this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000);
+ if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._docView;
this._downX = e.clientX;
this._downY = e.clientY;
@@ -533,7 +406,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (
// prettier-ignore
(this._props.isDocumentActive?.() || this._props.isContentActive?.()) &&
- !this._props.onBrowseClick?.() &&
+ !this._props.onBrowseClickScript?.() &&
!this.Document.ignoreClick &&
e.button === 0 &&
!Doc.IsInMyOverlay(this.layoutDoc)
@@ -579,40 +452,41 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (DocumentView.LongPress) e.preventDefault();
};
- @undoBatch
- toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => {
+ toggleFollowLink = undoable((zoom?: boolean, setTargetToggle?: boolean): void => {
const hadOnClick = this.Document.onClick;
this.noOnClick();
this.Document.onClick = hadOnClick ? undefined : FollowLinkScript();
this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never';
- };
- @undoBatch
- followLinkOnClick = () => {
+ }, 'toggle follow link');
+
+ followLinkOnClick = undoable(() => {
this.Document.ignoreClick = false;
this.Document.onClick = FollowLinkScript();
this.Document.followLinkToggle = false;
this.Document.followLinkZoom = false;
this.Document.followLinkLocation = undefined;
- };
- @undoBatch
- noOnClick = () => {
- this.Document.ignoreClick = false;
- this.Document.onClick = Doc.GetProto(this.Document).onClick = undefined;
- };
-
- @undoBatch deleteClicked = () => this._props.removeDocument?.(this._props.Document);
- @undoBatch setToggleDetail = () =>
- (this.Document.onClick = ScriptField.MakeScript(
- `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
- .replace('layout_', '')
- .replace(/^layout$/, 'detail')}")`,
- { documentView: 'any' }
- ));
+ }, 'follow link on click');
- @undoBatch
- drop = (e: Event, de: DragManager.DropEvent) => {
+ noOnClick = undoable(() => {
+ this.Document.ignoreClick = false;
+ this.Document.onClick = this.Document[DocData].onClick = undefined;
+ }, 'default on click');
+
+ deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
+ setToggleDetail = undoable(
+ () =>
+ (this.Document.onClick = ScriptField.MakeScript(
+ `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
+ .replace('layout_', '')
+ .replace(/^layout$/, 'detail')}")`,
+ { documentView: 'any' }
+ )),
+ 'set toggle detail'
+ );
+
+ drop = undoable((e: Event, de: DragManager.DropEvent) => {
if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false;
- if (this._props.Document === Doc.ActiveDashboard) {
+ if (this.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
alert(
@@ -634,7 +508,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
if (de.complete.linkDocument) {
de.complete.linkDocument.layout_isSvg = true;
- this._props.DocumentView().CollectionFreeFormView?.addDocument(de.complete.linkDocument);
+ this._docView?.CollectionFreeFormView?.addDocument(de.complete.linkDocument);
}
}
e.stopPropagation();
@@ -642,27 +516,26 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
return false;
- };
+ }, 'drop doc');
- @undoBatch
- makeIntoPortal = () => {
- const portalLink = this.allLinks.find(d => d.link_anchor_1 === this._props.Document && d.link_relationship === 'portal to:portal from');
+ makeIntoPortal = undoable(() => {
+ const portalLink = this._allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from');
if (!portalLink) {
DocUtils.MakeLink(
- this._props.Document,
+ this.Document,
Docs.Create.FreeformDocument([], {
_width: NumCast(this.layoutDoc._width) + 10,
_height: Math.max(NumCast(this.layoutDoc._height), NumCast(this.layoutDoc._width) + 10),
_isLightbox: true,
_layout_fitWidth: true,
- title: StrCast(this._props.Document.title) + ' [Portal]',
+ title: StrCast(this.Document.title) + ' [Portal]',
}),
{ link_relationship: 'portal to:portal from' }
);
}
this.Document.followLinkLocation = OpenWhere.lightbox;
this.Document.onClick = FollowLinkScript();
- };
+ }, 'make into portal');
importDocument = () => {
const input = document.createElement('input');
@@ -686,7 +559,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) {
e.preventDefault();
e.stopPropagation();
- //!this._props.isSelected(true) && SelectionManager.SelectView(this._props.DocumentView(), false);
+ //!this._props.isSelected(true) && SelectionManager.SelectView(this.DocumentView(), false);
}
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
if (e) {
@@ -708,7 +581,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e && !(e.nativeEvent as any).dash) {
const onDisplay = () => {
- if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this._props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear.
+ if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear.
setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY));
};
if (navigator.userAgent.includes('Macintosh')) {
@@ -719,14 +592,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
return;
}
- const customScripts = Cast(this._props.Document.contextMenuScripts, listSpec(ScriptField), []);
+ const customScripts = Cast(this.Document.contextMenuScripts, listSpec(ScriptField), []);
StrListCast(this.Document.contextMenuLabels).forEach((label, i) =>
cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this._props.scriptContext }), icon: 'sticky-note' })
);
this._props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this._props.scriptContext }), icon: item.icon as IconProp }));
- if (!this._props.Document.isFolder) {
- const templateDoc = Cast(this._props.Document[StrCast(this._props.Document.layout_fieldKey)], Doc, null);
+ if (!this.Document.isFolder) {
+ const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null);
const appearance = cm.findByDescription('Appearance...');
const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
@@ -737,40 +610,38 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
!Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this._props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
!appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' });
- if (!Doc.IsSystem(this.Document) && this.Document.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._type_collection as any)) {
+ if (this._props.bringToFront) {
+ const zorders = cm.findByDescription('ZOrder...');
+ const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
+ zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' });
+ zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront?.(dv.Document, true)), icon: 'arrow-down' });
+ zorderItems.push({
+ description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
+ event: undoBatch(action(() => (this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged))),
+ icon: 'hand-point-up',
+ });
+ !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' });
+ }
+
+ if (!Doc.IsSystem(this.Document) && !this.Document.hideClickBehaviors && !this._props.hideClickBehaviors) {
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
- if (this._props.bringToFront !== emptyFunction) {
- const zorders = cm.findByDescription('ZOrder...');
- const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
- zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront(dv.Document, false)), icon: 'arrow-up' });
- zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront(dv.Document, true)), icon: 'arrow-down' });
- zorderItems.push({
- description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
- event: undoBatch(action(() => (this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged))),
- icon: 'hand-point-up',
- });
- !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' });
- }
-
onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' });
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
- if (!this._props.treeViewDoc) {
- if (!this.Document.annotationOn) {
- const options = cm.findByDescription('Options...');
- const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
- !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
-
- onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
- !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this._props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
- !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
- } else if (LinkManager.Links(this.Document).length) {
- onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
- onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
- !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' });
- }
+ if (!this.Document.annotationOn) {
+ const options = cm.findByDescription('Options...');
+ const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
+ !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
+
+ onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
+ !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
+ !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
+ } else if (LinkManager.Links(this.Document).length) {
+ onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
+ onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
+ !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' });
}
}
@@ -786,15 +657,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const moreItems = more && 'subitems' in more ? more.subitems : [];
if (!Doc.IsSystem(this.Document)) {
if (!Doc.noviceMode) {
- moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this._props.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
+ moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' });
- if (Cast(Doc.GetProto(this._props.Document).data, listSpec(Doc))) {
- moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this._props.Document }).then(console.log), icon: 'caret-square-right' });
- moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this._props.Document), icon: 'caret-square-right' });
- moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this._props.Document), icon: 'caret-square-right' });
+ if (Cast(Doc.GetProto(this.Document).data, listSpec(Doc))) {
+ moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.Document }).then(console.log), icon: 'caret-square-right' });
+ moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this.Document), icon: 'caret-square-right' });
+ moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this.Document), icon: 'caret-square-right' });
}
- moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this._props.Document)), icon: 'fingerprint' });
+ moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' });
}
}
@@ -802,14 +673,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
const constantItems: ContextMenuProps[] = [];
if (!Doc.IsSystem(this.Document) && this.Document._type_collection !== CollectionViewType.Docking) {
- constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this._props.Document) });
- (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._props.DocumentView()), icon: 'users' });
- if (this._props.removeDocument && Doc.ActiveDashboard !== this._props.Document) {
+ constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.Document) });
+ (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._docView), icon: 'users' });
+ if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) {
// need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' });
}
}
- constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this._props.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' });
+ constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' });
cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' });
const help = cm.findByDescription('Help...');
@@ -820,7 +691,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
let documentationDescription: string | undefined = undefined;
let documentationLink: string | undefined = undefined;
- switch (this._props.Document.type) {
+ switch (this.Document.type) {
case DocumentType.COL:
documentationDescription = 'See collection documentation';
documentationLink = 'https://brown-dash.github.io/Dash-Documentation/views/';
@@ -854,8 +725,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/dataViz/';
break;
}
- // Add link to help documentation
- if (!this._props.treeViewDoc && documentationDescription && documentationLink) {
+ // Add link to help documentation (unless the doc contents have been overriden in which case the documentation isn't relevant)
+ if (!this.docContents && documentationDescription && documentationLink) {
helpItems.push({
description: documentationDescription,
event: () => window.open(documentationLink, '_blank'),
@@ -869,69 +740,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15, undefined, undefined, undefined);
};
- @computed get _rootSelected() {
- return this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
- }
rootSelected = () => this._rootSelected;
panelHeight = () => this._props.PanelHeight() - this.headerMargin;
- screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin);
- onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler);
+ screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin);
+ onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler;
setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height);
- setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
- @observable _isContentActive: boolean | undefined = undefined;
-
+ setContentView = action((view: ViewBoxInterface) => (this._componentView = view));
isContentActive = (): boolean | undefined => this._isContentActive;
childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
- /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive
- @computed get _contentPointerEvents() {
- TraceMobx();
- return this._props.contentPointerEvents ??
- ((!this.disableClickScriptFunc && //
- this.onClickHandler &&
- !this._props.onBrowseClick?.() &&
- this.isContentActive() !== true) ||
- this.isContentActive() === false)
- ? 'none'
- : this.pointerEvents;
- }
contentPointerEvents = () => this._contentPointerEvents;
- @computed get contents() {
- TraceMobx();
- const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
- const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
- return (
- <div
- className="documentView-contentsView"
- style={{
- pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'),
- height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
- }}>
- <DocumentContentsView
- key={1}
- {...this._props}
- fieldKey=""
- pointerEvents={this.contentPointerEvents}
- docViewPath={this._props.viewPath}
- setContentView={this.setContentView}
- childFilters={this.childFilters}
- PanelHeight={this.panelHeight}
- setHeight={this.setHeight}
- isContentActive={this.isContentActive}
- ScreenToLocalTransform={this.screenToLocalContent}
- rootSelected={this.rootSelected}
- onClick={this.onClickFunc}
- setTitleFocus={this.setTitleFocus}
- layout_fieldKey={this.finalLayoutKey}
- />
- {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
- </div>
- );
- }
anchorPanelWidth = () => this._props.PanelWidth() || 1;
anchorPanelHeight = () => this._props.PanelHeight() || 1;
- anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
// prettier-ignore
switch (property.split(':')[0]) {
case StyleProp.ShowTitle: return '';
@@ -944,39 +766,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
return this._props.styleProvider?.(doc, props, property);
};
- // We need to use allrelatedLinks to get not just links to the document as a whole, but links to
- // anchors that are not rendered as DocumentViews (marked as 'layout_unrendered' with their 'annotationOn' set to this document). e.g.,
- // - PDF text regions are rendered as an Annotations without generating a DocumentView, '
- // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link
- // - and links to PDF/Web docs at a certain scroll location never create an explicit view.
- // For each of these, we create LinkAnchorBox's on the border of the DocumentView.
- @computed get directLinks() {
- TraceMobx();
- return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(
- link =>
- (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) ||
- (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) ||
- ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) ||
- ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document))
- );
- }
- @computed get allLinks() {
- TraceMobx();
- return LinkManager.Instance.getAllRelatedLinks(this.Document);
- }
- hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false));
- @computed get allLinkEndpoints() {
+
+ removeLinkByHiding = (link: Doc) => () => (link.link_displayLine = false);
+ allLinkEndpoints = () => {
// the small blue dots that mark the endpoints of links
- TraceMobx();
if (this._componentView instanceof KeyValueBox || this._props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this._props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
- const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines);
- return filtered.map(link => (
+ return this.filteredLinks.map(link => (
<div className="documentView-anchorCont" key={link[Id]}>
<DocumentView
{...this._props}
isContentActive={returnFalse}
Document={link}
- docViewPath={this._props.viewPath}
+ containerViewPath={this._props.docViewPath}
PanelWidth={this.anchorPanelWidth}
PanelHeight={this.anchorPanelHeight}
dontRegisterView={false}
@@ -984,107 +785,55 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
hideCaptions={true}
hideLinkAnchors={true}
layout_fitWidth={returnTrue}
- removeDocument={this.hideLink(link)}
+ removeDocument={this.removeLinkByHiding(link)}
styleProvider={this.anchorStyleProvider}
LayoutTemplate={undefined}
LayoutTemplateString={LinkAnchorBox.LayoutString(`link_anchor_${LinkManager.anchorIndex(link, this.Document)}`)}
/>
</div>
));
- }
-
- static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
- let gumStream: any;
- let recorder: any;
- navigator.mediaDevices
- .getUserMedia({
- audio: true,
- })
- .then(function (stream) {
- let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
- if (audioTextAnnos) audioTextAnnos.push('');
- else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
- DictationManager.Controls.listen({
- interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value),
- continuous: { indefinite: false },
- }).then(results => {
- if (results && [DictationManager.Controls.Infringed].includes(results)) {
- DictationManager.Controls.stop();
- }
- onEnd?.();
- });
+ };
- gumStream = stream;
- recorder = new MediaRecorder(stream);
- recorder.ondataavailable = async (e: any) => {
- const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
- if (!(result instanceof Error)) {
- const audioField = new AudioField(result.accessPaths.agnostic.client);
- const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
- if (audioAnnos === undefined) {
- dataDoc[field + '_audioAnnotations'] = new List([audioField]);
- } else {
- audioAnnos.push(audioField);
- }
- }
- };
- //runInAction(() => (dataDoc.audioAnnoState = 'recording'));
- recorder.start();
- const stopFunc = () => {
- recorder.stop();
- DictationManager.Controls.stop(false);
- runInAction(() => (dataDoc.audioAnnoState = 'stopped'));
- gumStream.getAudioTracks()[0].stop();
- };
- if (onRecording) onRecording(stopFunc);
- else setTimeout(stopFunc, 5000);
- });
- }
- playAnnotation = () => {
- const self = this;
- const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped';
- const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
- const anno = audioAnnos?.lastElement();
- if (anno instanceof AudioField) {
- switch (audioAnnoState) {
- case 'stopped':
- this.dataDoc[AudioPlay] = new Howl({
- src: [anno.url.href],
- format: ['mp3'],
- autoplay: true,
- loop: false,
- volume: 0.5,
- onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')),
- });
- this.dataDoc.audioAnnoState = 'playing';
- break;
- case 'playing':
- this.dataDoc[AudioPlay]?.stop();
- this.dataDoc.audioAnnoState = 'stopped';
- break;
- }
- }
+ viewBoxContents = () => {
+ TraceMobx();
+ const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
+ const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
+ return (
+ <div
+ className="documentView-contentsView"
+ style={{
+ pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'),
+ height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
+ }}>
+ <DocumentContentsView
+ {...this._props}
+ layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')}
+ pointerEvents={this.contentPointerEvents}
+ setContentViewBox={this.setContentView}
+ childFilters={this.childFilters}
+ PanelHeight={this.panelHeight}
+ setHeight={this.setHeight}
+ isContentActive={this.isContentActive}
+ ScreenToLocalTransform={this.screenToLocalContent}
+ rootSelected={this.rootSelected}
+ onClickScript={this.onClickFunc}
+ setTitleFocus={this.setTitleFocus}
+ hideClickBehaviors={BoolCast(this.layoutDoc.hideClickBehaviors)}
+ />
+ {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints()}
+ </div>
+ );
};
- captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
- @observable _changingTitleField = false;
- @observable _dropDownInnerWidth = 0;
- fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
- const filteredOptions = new Set(inputOptions);
- const scaling = this.titleHeight / 30; /* height of Dropdown */
- Object.entries(DocOptions)
- .filter(opts => opts[1].filterable)
- .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0]));
- filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle));
- const options = Array.from(filteredOptions)
- .filter(f => f)
- .map(facet => ({ val: facet, text: facet }));
+ captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
+ fieldsDropdown = (reqdFields: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
+ const filteredFields = Object.entries(DocOptions).reduce((set, [field, opts]) => (opts.filterable ? set.add(field) : set), new Set(reqdFields));
return (
<div style={{ width: dropdownWidth }}>
<div
- ref={action((r: any) => r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
+ ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
onPointerDown={action(e => (this._changingTitleField = true))}
- style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}>
+ style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
<Dropdown
activeChanged={action(isOpen => !isOpen && (this._changingTitleField = false))}
selectedVal={placeholder}
@@ -1094,7 +843,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
type={Type.TERT}
closeOnSelect={true}
dropdownType={DropdownType.SELECT}
- items={options}
+ items={Array.from(filteredFields).map(facet => ({ val: facet, text: facet }))}
width={100}
fillWidth
/>
@@ -1102,43 +851,24 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
};
- @computed get innards() {
- TraceMobx();
+ /**
+ * displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
+ * setting layout_showTitle using the format: field1[;field2[...][:hover]]
+ * from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
+ **/
+ titleView = () => {
const showTitle = this.layout_showTitle?.split(':')[0];
const showTitleHover = this.layout_showTitle?.includes(':hover');
- const captionView = !this.layout_showCaption ? null : (
- <div
- className="documentView-captionWrapper"
- style={{
- pointerEvents: this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
- background: StrCast(this.layoutDoc._backgroundColor, 'rgba(0,0,0,0.2)'),
- color: lightOrDark(StrCast(this.layoutDoc._backgroundColor, 'black')),
- }}>
- <FormattedTextBox
- {...this._props}
- yPadding={10}
- xPadding={10}
- fieldKey={this.layout_showCaption}
- styleProvider={this.captionStyleProvider}
- dontRegisterView={true}
- noSidebar={true}
- dontScale={true}
- renderDepth={this._props.renderDepth}
- isContentActive={this.isContentActive}
- />
- </div>
- );
+
const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document;
const background = StrCast(
this.layoutDoc.layout_headingColor,
StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor))
);
- const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0;
+ const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._titleDropDownInnerWidth * this.titleHeight) / 30) : 0;
const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
- // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
- // setting layout_showTitle using the format: field1[;field2[...][:hover]]
- // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
- const titleView = !showTitle ? null : (
+
+ return !showTitle ? null : (
<div
className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
key="title"
@@ -1154,7 +884,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{!dropdownWidth
? null
: this.fieldsDropdown(
- [],
+ [StrCast(this.layoutDoc.layout_showTitle)],
dropdownWidth,
StrCast(this.layoutDoc.layout_showTitle).split(':')[0],
action((field: string | number) => {
@@ -1200,19 +930,36 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
</div>
);
- return this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? (
- this.contents
- ) : (
- <div className="documentView-styleWrapper">
- {titleView}
- {this.contents}
- {captionView}
+ };
+
+ captionView = () => {
+ return !this.layout_showCaption ? null : (
+ <div
+ className="documentView-captionWrapper"
+ style={{
+ pointerEvents: this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
+ background: StrCast(this.layoutDoc._backgroundColor, 'rgba(0,0,0,0.2)'),
+ color: lightOrDark(StrCast(this.layoutDoc._backgroundColor, 'black')),
+ }}>
+ <FormattedTextBox
+ {...this._props}
+ yPadding={10}
+ xPadding={10}
+ fieldKey={this.layout_showCaption}
+ styleProvider={this.captionStyleProvider}
+ dontRegisterView={true}
+ noSidebar={true}
+ dontScale={true}
+ renderDepth={this._props.renderDepth}
+ isContentActive={this.isContentActive}
+ />
</div>
);
- }
+ };
renderDoc = (style: object) => {
TraceMobx();
+ const showTitle = this.layout_showTitle?.split(':')[0];
return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate
? null
: this.docContents ?? (
@@ -1228,59 +975,31 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
fontFamily: StrCast(this.Document._text_fontFamily, 'inherit'),
fontSize: Cast(this.Document._text_fontSize, 'string', null),
transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined,
- transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform ${this.animateScaleTime / 1000}s ease-${this._animateScalingTo < 1 ? 'in' : 'out'}`,
+ transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform ${this.animateScaleTime() / 1000}s ease-${this._animateScalingTo < 1 ? 'in' : 'out'}`,
}}>
- {this.innards}
+ {this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? (
+ this.viewBoxContents()
+ ) : (
+ <div className="documentView-styleWrapper">
+ {this.titleView()}
+ {this.viewBoxContents()}
+ {this.captionView()}
+ </div>
+ )}
{this.widgetDecorations ?? null}
</div>
);
};
- /**
- * returns an entrance animation effect function to wrap a JSX element
- * @param presEffectDoc presentation effects document that specifies the animation effect parameters
- * @returns a function that will wrap a JSX animation element wrapping any JSX element
- */
- public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
- const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection;
- const effectProps = {
- left: dir === PresEffectDirection.Left,
- right: dir === PresEffectDirection.Right,
- top: dir === PresEffectDirection.Top,
- bottom: dir === PresEffectDirection.Bottom,
- opposite: true,
- delay: 0,
- duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
- };
- //prettier-ignore
- switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
- default:
- case PresEffect.None: return renderDoc;
- case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
- case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade>;
- case PresEffect.Flip: return <Flip {...effectProps}>{renderDoc}</Flip>;
- case PresEffect.Rotate: return <Rotate {...effectProps}>{renderDoc}</Rotate>;
- case PresEffect.Bounce: return <Bounce {...effectProps}>{renderDoc}</Bounce>;
- case PresEffect.Roll: return <Roll {...effectProps}>{renderDoc}</Roll>;
- case PresEffect.Lightspeed: return <JackInTheBox {...effectProps}>{renderDoc}</JackInTheBox>;
- }
- }
- @computed get highlighting() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.Highlighting);
- }
- @computed get borderPath() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.BorderPath);
- }
render() {
TraceMobx();
const highlighting = this.highlighting;
const borderPath = this.borderPath;
- const boxShadow =
- this._props.treeViewDoc || !highlighting
- ? this.boxShadow
- : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed'
- ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}`
- : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
+ const boxShadow = !highlighting
+ ? this.boxShadow
+ : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed'
+ ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}`
+ : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
const renderDoc = this.renderDoc({
borderRadius: this.borderRounding,
outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px',
@@ -1298,10 +1017,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onClick={this.onClick}
onPointerEnter={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)}
onPointerOver={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)}
- onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)}
+ onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)}
style={{
borderRadius: this.borderRounding,
- pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here)
+ pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here)
}}>
<>
{this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)}
@@ -1310,157 +1029,124 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
}
-}
-@observer
-export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
- public static ROOT_DIV = 'documentView-effectsWrapper';
-
- constructor(props: any) {
- super(props);
- makeObservable(this);
+ /**
+ * returns an entrance animation effect function to wrap a JSX element
+ * @param presEffectDoc presentation effects document that specifies the animation effect parameters
+ * @returns a function that will wrap a JSX animation element wrapping any JSX element
+ */
+ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
+ const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection;
+ const effectProps = {
+ left: dir === PresEffectDirection.Left,
+ right: dir === PresEffectDirection.Right,
+ top: dir === PresEffectDirection.Top,
+ bottom: dir === PresEffectDirection.Bottom,
+ opposite: true,
+ delay: 0,
+ duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
+ };
+ //prettier-ignore
+ switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
+ default:
+ case PresEffect.None: return renderDoc;
+ case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
+ case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade>;
+ case PresEffect.Flip: return <Flip {...effectProps}>{renderDoc}</Flip>;
+ case PresEffect.Rotate: return <Rotate {...effectProps}>{renderDoc}</Rotate>;
+ case PresEffect.Bounce: return <Bounce {...effectProps}>{renderDoc}</Bounce>;
+ case PresEffect.Roll: return <Roll {...effectProps}>{renderDoc}</Roll>;
+ case PresEffect.Lightspeed: return <JackInTheBox {...effectProps}>{renderDoc}</JackInTheBox>;
+ }
}
+ public static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ let gumStream: any;
+ let recorder: any;
+ navigator.mediaDevices
+ .getUserMedia({
+ audio: true,
+ })
+ .then(function (stream) {
+ let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
+ if (audioTextAnnos) audioTextAnnos.push('');
+ else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
+ DictationManager.Controls.listen({
+ interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value),
+ continuous: { indefinite: false },
+ }).then(results => {
+ if (results && [DictationManager.Controls.Infringed].includes(results)) {
+ DictationManager.Controls.stop();
+ }
+ onEnd?.();
+ });
- @observable _selected = false;
- public get IsSelected() {
- return this._selected;
- }
- public set IsSelected(val) {
- runInAction(() => (this._selected = val));
- }
- @observable public static LongPress = false;
- @computed public static get exploreMode() {
- return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
+ gumStream = stream;
+ recorder = new MediaRecorder(stream);
+ recorder.ondataavailable = async (e: any) => {
+ const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
+ if (!(result instanceof Error)) {
+ const audioField = new AudioField(result.accessPaths.agnostic.client);
+ const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
+ if (audioAnnos === undefined) {
+ dataDoc[field + '_audioAnnotations'] = new List([audioField]);
+ } else {
+ audioAnnos.push(audioField);
+ }
+ }
+ };
+ //runInAction(() => (dataDoc.audioAnnoState = 'recording'));
+ recorder.start();
+ const stopFunc = () => {
+ recorder.stop();
+ DictationManager.Controls.stop(false);
+ runInAction(() => (dataDoc.audioAnnoState = 'stopped'));
+ gumStream.getAudioTracks()[0].stop();
+ };
+ if (onRecording) onRecording(stopFunc);
+ else setTimeout(stopFunc, 5000);
+ });
}
- @observable public docView: DocumentViewInternal | undefined | null = undefined;
- @observable public textHtmlOverlay: Opt<string> = undefined;
- @observable public textHtmlOverlayTime: Opt<number> = undefined;
- @observable private _isHovering = false;
+}
- public htmlOverlayEffect: Opt<Doc>;
- public get displayName() {
- return 'DocumentView(' + this._props.Document?.title + ')';
- } // this makes mobx trace() statements more descriptive
+@observer
+export class DocumentView extends DocComponent<DocumentViewProps>() {
+ public static ROOT_DIV = 'documentView-effectsWrapper';
+ public get displayName() { return 'DocumentView(' + this.Document?.title + ')'; } // prettier-ignore
public ContentRef = React.createRef<HTMLDivElement>();
- public ViewTimer: NodeJS.Timeout | undefined; // timer for res
- public AnimEffectTimer: NodeJS.Timeout | undefined; // timer for res
+ private _htmlOverlayEffect: Opt<Doc>;
private _disposers: { [name: string]: IReactionDisposer } = {};
- public clearViewTransition = () => {
- this.ViewTimer && clearTimeout(this.ViewTimer);
- this.layoutDoc._viewTransition = undefined;
- };
- public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
-
- public showContextMenu = (pageX: number, pageY: number) => this.docView?.onContextMenu(undefined, pageX, pageY);
+ private _viewTimer: NodeJS.Timeout | undefined;
+ private _animEffectTimer: NodeJS.Timeout | undefined;
- public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
- this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer);
- this.Document[Animation] = presEffect;
- this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs);
- };
- public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
- this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`;
- if (dataTrans) this.Document._dataTransition = `${transProp} ${timeInMs}ms`;
- this.ViewTimer && clearTimeout(this.ViewTimer);
- return (this.ViewTimer = setTimeout(() => {
- this.layoutDoc._viewTransition = undefined;
- this.Document._dataTransition = 'inherit';
- afterTrans?.();
- }, timeInMs + 10));
- };
- public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) {
- docs.forEach(doc => {
- doc._viewTransition = `${transProp} ${timeInMs}ms`;
- dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`);
- });
- return setTimeout(
- () =>
- docs.forEach(doc => {
- doc._viewTransition = undefined;
- dataTrans && (doc.dataTransition = 'inherit');
- afterTrans?.();
- }),
- timeInMs + 10
- );
+ @computed public static get exploreMode() {
+ return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
}
- // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
- public static showBackLinks(linkAnchor: Doc) {
- const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
- // prettier-ignore
- DocServer.GetRefField(docId).then(docx =>
- LightboxView.Instance.SetLightboxDoc(
- (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
- Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId)
- )
- );
+ constructor(props: DocumentViewProps) {
+ super(props);
+ makeObservable(this);
}
- get Document() {
- return this._props.Document;
- }
- get topMost() {
- return this._props.renderDepth === 0;
- }
- get dataDoc() {
- return this.docView?.dataDoc ?? this.Document;
- }
- get ContentDiv() {
- return this.docView?.ContentDiv;
- }
- get ComponentView() {
- return this.docView?._componentView;
- }
- get allLinks() {
- return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document);
- }
- get LayoutFieldKey() {
- return this.docView?.LayoutFieldKey || 'layout';
- }
- @computed get layout_fitWidth() {
- return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth;
- }
- @computed get anchorViewDoc() {
- return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined;
- }
- @computed get hideLinkButton() {
- return (
- this._props.hideLinkButton ||
- this._props.renderDepth === -1 || //
- (this.IsSelected && this._props.renderDepth) ||
- !this._isHovering ||
- (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) ||
- SnappingManager.IsDragging ||
- SnappingManager.IsResizing
- );
- }
- hideLinkCount = () => (this.hideLinkButton ? true : false);
+ // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed.
+ // unfortunately, CSS can't transition animate any properties for something that is display 'none'.
+ // so we need to first activate the div, then, after a render timeout, start the opacity transition.
+ @observable private _enableHtmlOverlayTransitions: boolean = false;
+ @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined;
+ @observable private _htmlOverlayText: Opt<string> = undefined;
+ @observable private _isHovering = false;
+ @observable private _selected = false;
+ @observable public static LongPress = false;
- @computed get linkCountView() {
- return <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.screenToLocalScale} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
- }
- @computed get docViewPath(): DocumentView[] {
- return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this];
- }
- @computed get layoutDoc() {
- return Doc.Layout(this.Document, this._props.LayoutTemplate?.());
- }
- @computed get nativeWidth() {
- return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
- }
- @computed get nativeHeight() {
- return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
- }
- @computed get shouldNotScale() {
+ @computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this._props.LayoutTemplateString?.includes(KeyValueBox.name) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
}
- @computed get effectiveNativeWidth() {
+ @computed private get effectiveNativeWidth() {
return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
}
- @computed get effectiveNativeHeight() {
+ @computed private get effectiveNativeHeight() {
return this.shouldNotScale ? 0 : this.nativeHeight || NumCast(this.layoutDoc.height);
}
- @computed get nativeScaling() {
+ @computed private get nativeScaling() {
if (this.shouldNotScale) return 1;
const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
if (this.layout_fitWidth || this._props.PanelHeight() / (this.effectiveNativeHeight || 1) > this._props.PanelWidth() / (this.effectiveNativeWidth || 1)) {
@@ -1468,19 +1154,19 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
}
return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
}
- @computed get panelWidth() {
+ @computed private get panelWidth() {
return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth();
}
- @computed get panelHeight() {
+ @computed private get panelHeight() {
if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) {
return Math.min(this._props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling);
}
return this._props.PanelHeight();
}
- @computed get Xshift() {
+ @computed private get Xshift() {
return this.effectiveNativeWidth ? Math.max(0, (this._props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0;
}
- @computed get Yshift() {
+ @computed private get Yshift() {
return this.effectiveNativeWidth &&
this.effectiveNativeHeight &&
Math.abs(this.Xshift) < 0.001 &&
@@ -1488,45 +1174,103 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
? Math.max(0, (this._props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2)
: 0;
}
- @computed get centeringX() {
- return this._props.dontCenter?.includes('x') ? 0 : this.Xshift;
+ @computed private get hideLinkButton() {
+ return (
+ this._props.hideLinkButton ||
+ this._props.renderDepth === -1 || //
+ (this.IsSelected && this._props.renderDepth) ||
+ !this._isHovering ||
+ (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) ||
+ SnappingManager.IsDragging ||
+ SnappingManager.IsResizing
+ );
}
- @computed get centeringY() {
- return this._props.dontCenter?.includes('y') ? 0 : this.Yshift;
+
+ componentDidMount() {
+ runInAction(() => this.Document[DocViews].add(this));
+ this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction);
+ !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this);
}
- @computed get CollectionFreeFormView() {
- return this.CollectionFreeFormDocumentView?.CollectionFreeFormView;
+ componentWillUnmount() {
+ runInAction(() => this.Document[DocViews].delete(this));
+ Object.values(this._disposers).forEach(disposer => disposer?.());
+ !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
}
- @computed get CollectionFreeFormDocumentView() {
- return this._props.CollectionFreeFormDocumentView?.();
+
+ public set IsSelected(val) { runInAction(() => (this._selected = val)); } // prettier-ignore
+ public get IsSelected() { return this._selected; } // prettier-ignore
+ public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore
+ public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore
+ public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore
+ public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore
+
+ get LayoutFieldKey() {
+ return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString);
}
- public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight());
- public getBounds = () => {
- if (!this.docView?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this._props.Document, Doc.UserDoc())) {
+ @computed get layout_fitWidth() {
+ return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth;
+ }
+ @computed get anchorViewDoc() {
+ return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined;
+ }
+
+ @computed get getBounds() {
+ if (!this._docViewInternal?._contentDiv || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) {
return undefined;
}
- if (this.docView._componentView?.screenBounds?.()) {
- return this.docView._componentView.screenBounds();
+ if (this._docViewInternal._componentView?.screenBounds?.()) {
+ return this._docViewInternal._componentView.screenBounds();
}
- const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse();
+ const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse();
const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)];
- if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
- const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont');
+ if (this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
+ const docuBox = this._docViewInternal._contentDiv.getElementsByClassName('linkAnchorBox-cont');
if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined };
}
return { left, top, right, bottom };
+ }
+
+ @computed get nativeWidth() {
+ return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
+ }
+ @computed get nativeHeight() {
+ return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
+ }
+ @computed public get centeringX() { return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; } // prettier-ignore
+ @computed public get centeringY() { return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; } // prettier-ignore
+
+ /**
+ * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg)
+ */
+ public get containerViewPath() { return this._props.containerViewPath; } // prettier-ignore
+ public get CollectionFreeFormView() { return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; } // prettier-ignore
+ public get CollectionFreeFormDocumentView() { return this._props.CollectionFreeFormDocumentView?.(); } // prettier-ignore
+
+ public clearViewTransition = () => {
+ this._viewTimer && clearTimeout(this._viewTimer);
+ this.layoutDoc._viewTransition = undefined;
};
+ public noOnClick = () => this._docViewInternal?.noOnClick();
+ public makeIntoPortal = () => this._docViewInternal?.makeIntoPortal();
+ public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
+ public setToggleDetail = () => this._docViewInternal?.setToggleDetail();
+ public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);
+ public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents();
+ public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource);
+ public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY);
+
+ public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight());
public iconify(finished?: () => void, animateTime?: number) {
this.ComponentView?.updateIcon?.();
- const animTime = this.docView?._animateScaleTime;
- runInAction(() => this.docView && animateTime !== undefined && (this.docView._animateScaleTime = animateTime));
+ const animTime = this._docViewInternal?.animateScaleTime();
+ runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime));
const finalFinished = action(() => {
finished?.();
- this.docView && (this.docView._animateScaleTime = animTime);
+ this._docViewInternal && (this._docViewInternal._animateScaleTime = animTime);
});
const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null);
if (layout_fieldKey !== 'layout_icon') {
@@ -1536,17 +1280,62 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null);
this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished);
this.Document.deiconifyLayout = undefined;
- this._props.bringToFront(this.Document);
+ this._props.bringToFront?.(this.Document);
}
}
- @undoBatch
- setCustomView = (custom: boolean, layout: string): void => {
- Doc.setNativeView(this._props.Document);
- custom && DocUtils.makeCustomViewClicked(this._props.Document, Docs.Create.StackingDocument, layout, undefined);
+
+ public playAnnotation = () => {
+ const self = this;
+ const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped';
+ const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
+ const anno = audioAnnos?.lastElement();
+ if (anno instanceof AudioField) {
+ switch (audioAnnoState) {
+ case 'stopped':
+ this.dataDoc[AudioPlay] = new Howl({
+ src: [anno.url.href],
+ format: ['mp3'],
+ autoplay: true,
+ loop: false,
+ volume: 0.5,
+ onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')),
+ });
+ this.dataDoc.audioAnnoState = 'playing';
+ break;
+ case 'playing':
+ this.dataDoc[AudioPlay]?.stop();
+ this.dataDoc.audioAnnoState = 'stopped';
+ break;
+ }
+ }
};
- switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
- runInAction(() => this.docView && (this.docView._animateScalingTo = 0.1)); // shrink doc
+ public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => {
+ this._htmlOverlayText = text;
+ this._htmlOverlayEffect = effect;
+ });
+ public setAnimateScaling = action((scale: number, time?: number) => {
+ if (this._docViewInternal) {
+ this._docViewInternal._animateScalingTo = scale;
+ this._docViewInternal._animateScaleTime = time;
+ }
+ });
+ public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
+ this._animEffectTimer && clearTimeout(this._animEffectTimer);
+ this.Document[Animation] = presEffect;
+ this._animEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs);
+ };
+ public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
+ this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans);
+ };
+
+ public setCustomView = undoable((custom: boolean, layout: string): void => {
+ Doc.setNativeView(this.Document);
+ custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined);
+ }, 'set custom view');
+
+ public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
+ runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc
setTimeout(
action(() => {
if (useExistingLayout && custom && this.Document['layout_' + view]) {
@@ -1554,22 +1343,25 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
} else {
this.setCustomView(custom, view);
}
- this.docView && (this.docView._animateScalingTo = 1); // expand it
+ this._docViewInternal && (this._docViewInternal._animateScalingTo = 1); // expand it
setTimeout(
action(() => {
- this.docView && (this.docView._animateScalingTo = 0);
+ this._docViewInternal && (this._docViewInternal._animateScalingTo = 0);
finished?.();
}),
- this.docView ? Math.max(0, this.docView.animateScaleTime - 10) : 0
+ Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
);
}),
- this.docView ? Math.max(0, this.docView?.animateScaleTime - 10) : 0
+ Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
);
};
+ /**
+ * @returns a hierarchy path through the nested DocumentViews that display this view. The last element of the path is this view.
+ */
+ public docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]);
layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth);
screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale;
- docViewPathFunc = () => this.docViewPath;
isSelected = () => this.IsSelected;
select = (extendSelection: boolean, focusSelection?: boolean) => {
if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this);
@@ -1590,6 +1382,7 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
PanelWidth = () => this.panelWidth;
PanelHeight = () => this.panelHeight;
NativeDimScaling = () => this.nativeScaling;
+ hideLinkCount = () => (this.hideLinkButton ? true : false);
selfView = () => this;
/**
* @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView)
@@ -1604,57 +1397,30 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
.translate(-this.centeringX, -this.centeringY)
.scale(1 / this.nativeScaling);
- componentDidMount() {
- runInAction(() => this.Document[DocViews].add(this));
- this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction);
- this._disposers.height = reaction(
- // increase max auto height if document has been resized to be greater than current max
- () => NumCast(this.layoutDoc._height),
- action(height => {
- const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight);
- if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height;
- })
- );
- !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this);
- }
-
- componentWillUnmount() {
- this.Document[DocViews].delete(this);
- Object.values(this._disposers).forEach(disposer => disposer?.());
- !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
- }
- // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed.
- // unfortunately, CSS can't transition animate any properties for something that is display 'none'.
- // so we need to first activate the div, then, after a render timeout, start the opacity transition.
- @observable enableHtmlOverlayTransitions: boolean = false;
- @computed get htmlOverlay() {
- const effect = StrCast(this.htmlOverlayEffect?.presentation_effect, StrCast(this.htmlOverlayEffect?.followLinkAnimEffect));
+ htmlOverlay = () => {
+ const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect));
return (
<div
className="documentView-htmlOverlay"
ref={r => {
const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition
- if (r && val !== this.enableHtmlOverlayTransitions) {
- setTimeout(action(() => (this.enableHtmlOverlayTransitions = val)));
+ if (r && val !== this._enableHtmlOverlayTransitions) {
+ setTimeout(action(() => (this._enableHtmlOverlayTransitions = val)));
}
}}
- style={{ display: !this.textHtmlOverlay ? 'none' : undefined }}>
- <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this.enableHtmlOverlayTransitions ? 0.9 : 0 }}>
+ style={{ display: !this._htmlOverlayText ? 'none' : undefined }}>
+ <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this._enableHtmlOverlayTransitions ? 0.9 : 0 }}>
{DocumentViewInternal.AnimationEffect(
<div className="webBox-textHighlight">
- <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
+ <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
</div>,
- { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc,
+ { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc,
this.Document
)}
</div>
</div>
);
- }
-
- @computed get infoUI() {
- return this.ComponentView?.infoUI?.();
- }
+ };
render() {
TraceMobx();
@@ -1663,20 +1429,20 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
return (
<div className="contentFittingDocumentView" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))}>
- {!this._props.Document || !this._props.PanelWidth() ? null : (
+ {!this.Document || !this._props.PanelWidth() ? null : (
<div
className="contentFittingDocumentView-previewDoc"
ref={this.ContentRef}
style={{
- transition: 'inherit', // this._props.dataTransition,
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`,
height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`),
}}>
<DocumentViewInternal
{...this._props}
+ fieldKey={this.LayoutFieldKey}
DocumentView={this.selfView}
- viewPath={this.docViewPathFunc}
+ docViewPath={this.docViewPath}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
NativeWidth={this.NativeWidth}
@@ -1687,17 +1453,46 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
layout_fitWidth={this.layout_fitWidthFunc}
ScreenToLocalTransform={this.screenToContentsTransform}
focus={this._props.focus || emptyFunction}
- ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))}
+ ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))}
/>
- {this.htmlOverlay}
- {this.infoUI}
+ {this.htmlOverlay()}
+ {this.ComponentView?.infoUI?.()}
</div>
)}
-
- {this.linkCountView}
+ {/* display link count button */}
+ <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.screenToLocalScale} OnHover={true} Bottom={this.topMost} ShowCount={true} />
</div>
);
}
+
+ public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) {
+ docs.forEach(doc => {
+ doc._viewTransition = `${transProp} ${timeInMs}ms`;
+ dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`);
+ });
+ timer && clearTimeout(timer);
+ return setTimeout(
+ () =>
+ docs.forEach(doc => {
+ doc._viewTransition = undefined;
+ dataTrans && (doc.dataTransition = 'inherit');
+ afterTrans?.();
+ }),
+ timeInMs + 10
+ );
+ }
+
+ // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
+ public static showBackLinks(linkAnchor: Doc) {
+ const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
+ // prettier-ignore
+ DocServer.GetRefField(docId).then(docx =>
+ LightboxView.Instance.SetLightboxDoc(
+ (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
+ Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId)
+ )
+ );
+ }
}
ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) {
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index ff92c701f..2e03a766a 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -20,14 +20,14 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static SelectOnLoad: string = '';
_ref: React.RefObject<EquationEditor> = React.createRef();
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
- if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) {
+ this._props.setContentViewBox?.(this);
+ if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) {
this._props.select(false);
this._ref.current!.mathField.focus();
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 008f10f26..8a49b4757 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,43 +1,119 @@
-import { computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../fields/DateField';
-import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc';
+import { Doc, Field, Opt } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ScriptField } from '../../../fields/ScriptField';
import { WebField } from '../../../fields/URLField';
-import { DocumentViewSharedProps } from './DocumentView';
+import { dropActionType } from '../../util/DragManager';
+import { Transform } from '../../util/Transform';
+import { ViewBoxInterface } from '../DocComponent';
+import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { PinProps } from './trails';
+export interface FocusViewOptions {
+ willPan?: boolean; // determines whether to pan to target document
+ willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document
+ zoomScale?: number; // percent of containing frame to zoom into document
+ zoomTime?: number;
+ didMove?: boolean; // whether a document was changed during the showDocument process
+ docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy
+ instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
+ preview?: boolean; // whether changes should be previewed by the componentView or written to the document
+ effect?: Doc; // animation effect for focus
+ noSelect?: boolean; // whether target should be selected after focusing
+ playAudio?: boolean; // whether to play audio annotation on focus
+ playMedia?: boolean; // whether to play start target videos
+ openLocation?: OpenWhere; // where to open a missing document
+ zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections
+ toggleTarget?: boolean; // whether to toggle target on and off
+ anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc
+ easeFunc?: 'linear' | 'ease'; // transition method for scrolling
+}
+export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>;
+export type StyleProviderFuncType = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => any;
//
// these properties get assigned through the render() method of the DocumentView when it creates this node.
// However, that only happens because the properties are "defined" in the markup for the field view.
// See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc.
//
-export interface FieldViewProps extends DocumentViewSharedProps {
- // FieldView specific props that are not part of DocumentView props
- fieldKey: string;
+export interface FieldViewSharedProps {
+ Document: Doc;
+ TemplateDataDocument?: Doc;
+ LayoutTemplateString?: string;
+ LayoutTemplate?: () => Opt<Doc>;
+ renderDepth: number;
+ scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
+ xPadding?: number;
+ yPadding?: number;
+ dontRegisterView?: boolean;
+ dropAction?: dropActionType;
+ dragAction?: dropActionType;
+ forceAutoHeight?: boolean;
+ ignoreAutoHeight?: boolean;
+ disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
+ hideClickBehaviors?: boolean; // whether to suppress menu item options for changing click behaviors
+ CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
+ containerViewPath?: () => DocumentView[];
+ fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
+ isGroupActive?: () => string | undefined; // is this document part of a group that is active
+ setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox
+ PanelWidth: () => number;
+ PanelHeight: () => number;
+ isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
+ isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
+ childFilters: () => string[];
+ childFiltersByRanges: () => string[];
+ styleProvider: Opt<StyleProviderFuncType>;
+ setTitleFocus?: () => void;
+ focus: FocusFuncType;
+ onClickScript?: () => ScriptField;
+ onDoubleClickScript?: () => ScriptField;
+ onPointerDownScript?: () => ScriptField;
+ onPointerUpScript?: () => ScriptField;
+ onBrowseClickScript?: () => ScriptField | undefined;
+ onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
+ layout_fitWidth?: (doc: Doc) => boolean | undefined;
+ searchFilterDocs: () => Doc[];
+ layout_showTitle?: () => string;
+ whenChildContentsActiveChanged: (isActive: boolean) => void;
+ rootSelected?: () => boolean; // whether the root of a template has been selected
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean;
+ filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+ removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+ moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean;
+ pinToPres: (document: Doc, pinProps: PinProps) => void;
+ ScreenToLocalTransform: () => Transform;
+ bringToFront?: (doc: Doc, sendToBack?: boolean) => void;
+ waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
+ defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
+ pointerEvents?: () => Opt<string>;
+}
- select: (isCtrlPressed: boolean) => void;
- isContentActive: (outsideReaction?: boolean) => boolean | undefined;
- isDocumentActive?: () => boolean | undefined;
+/**
+ * FieldView specific props that are not shared with DocumentView props
+ * */
+export interface FieldViewProps extends FieldViewSharedProps {
+ DocumentView?: () => DocumentView;
+ fieldKey: string;
isSelected: () => boolean;
+ select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
+ docViewPath: () => DocumentView[];
setHeight?: (height: number) => void;
- NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps
- onBrowseClick?: () => ScriptField | undefined;
- onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
- pointerEvents?: () => Opt<string>;
+ NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal
// properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
// See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields
// Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields
backgroundColor?: string;
- treeViewDoc?: Doc;
color?: string;
height?: number;
width?: number;
+ dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field)
noSidebar?: boolean;
dontScale?: boolean;
- dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field)
}
@observer
@@ -46,13 +122,8 @@ export class FieldView extends React.Component<FieldViewProps> {
return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={'data'} />"
}
- @computed
- get field(): FieldResult {
- const { Document, fieldKey: fieldKey } = this.props;
- return Document[fieldKey];
- }
render() {
- const field = this.field;
+ const field = this.props.Document[this.props.fieldKey];
// prettier-ignore
if (field instanceof Doc) return <p> <b>{field.title?.toString()}</b></p>;
if (field === undefined) return <p>{'<null>'}</p>;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 5a8665aaf..cf07d98be 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -46,7 +46,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
return FieldView.LayoutString(FontIconBox, fieldKey);
}
- constructor(props: any) {
+ constructor(props: ButtonProps) {
super(props);
makeObservable(this);
}
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index c26579e66..2e7a2120e 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -31,7 +31,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
reaction(
() => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange],
() => this.createGraph()
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a5853499f..923aead64 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -21,17 +21,17 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../../views/ContextMenu';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import './ImageBox.scss';
import { PinProps, PresBox } from './trails';
@observer
-export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ImageBox, fieldKey);
}
@@ -55,10 +55,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
private _marqueeref = React.createRef<MarqueeAnnotator>();
@observable _curSuffix = '';
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
protected createDropTarget = (ele: HTMLDivElement) => {
@@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@undoBatch
setNativeSize = action(() => {
- const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
+ const scaling = (this.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
const nscale = NumCast(this._props.PanelWidth()) / scaling;
const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
@@ -186,9 +186,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
this.addDocument(region);
const anchx = NumCast(cropping.x);
const anchy = NumCast(cropping.y);
@@ -201,7 +202,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
cropping._width = anchw * (this._props.NativeDimScaling?.() || 1);
cropping._height = anchh * (this._props.NativeDimScaling?.() || 1);
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.backgroundColor = undefined;
@@ -226,7 +227,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._props.addDocTab(cropping, OpenWhere.inParent);
}
DocumentManager.Instance.AddViewRenderedCb(cropping, dv => setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200));
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
return cropping;
};
@@ -368,7 +369,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale);
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -389,7 +390,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._marqueeref.current?.onTerminateSelection();
this._props.select(false);
};
- focus = (anchor: Doc, options: DocFocusOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
+ focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
_ffref = React.createRef<CollectionFreeFormView>();
savedAnnotations = () => this._savedAnnotations;
@@ -421,7 +422,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<CollectionFreeFormView
ref={this._ffref}
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
renderDepth={this._props.renderDepth + 1}
@@ -444,7 +445,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{this.content}
</CollectionFreeFormView>
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
Document={this.Document}
ref={this._marqueeref}
@@ -452,7 +453,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
annotationLayerScrollTop={0}
scaling={returnOne}
annotationLayerScaling={this._props.NativeDimScaling}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
addDocument={this.addDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 73fdc3a23..39a45693e 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -44,7 +44,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
private _valInput = React.createRef<HTMLInputElement>();
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
isKeyValueBox = returnTrue;
able = returnAlways;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 7bc9d3f85..f9e8ce4f3 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -12,8 +12,7 @@ import { ContextMenu } from '../ContextMenu';
import { EditableView } from '../EditableView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider } from '../StyleProvider';
-import { OpenWhere } from './DocumentView';
-import { FieldViewProps } from './FieldView';
+import { OpenWhere, returnEmptyDocViewList } from './DocumentView';
import { KeyValueBox } from './KeyValueBox';
import './KeyValueBox.scss';
import './KeyValuePair.scss';
@@ -61,33 +60,11 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
};
render() {
- const props: FieldViewProps = {
- Document: this._props.doc,
- childFilters: returnEmptyFilter,
- childFiltersByRanges: returnEmptyFilter,
- searchFilterDocs: returnEmptyDoclist,
- styleProvider: DefaultStyleProvider,
- docViewPath: returnEmptyDoclist,
- fieldKey: this._props.keyName,
- isSelected: returnFalse,
- setHeight: returnFalse,
- select: emptyFunction,
- bringToFront: emptyFunction,
- renderDepth: 1,
- isContentActive: returnFalse,
- whenChildContentsActiveChanged: emptyFunction,
- ScreenToLocalTransform: Transform.Identity,
- focus: emptyFunction,
- PanelWidth: this._props.PanelWidth,
- PanelHeight: this._props.PanelHeight,
- addDocTab: returnFalse,
- pinToPres: returnZero,
- };
// let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")";
let protoCount = 0;
- let doc: Doc | undefined = props.Document;
+ let doc = this._props.doc;
while (doc) {
- if (Object.keys(doc).includes(props.fieldKey)) {
+ if (Object.keys(doc).includes(this._props.keyName)) {
break;
}
protoCount++;
@@ -106,17 +83,17 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
style={hover}
className="keyValuePair-td-key-delete"
onClick={undoBatch(() => {
- if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) {
- delete props.Document[props.fieldKey];
- } else delete DocCast(props.Document.proto)?.[props.fieldKey];
+ if (Object.keys(this._props.doc).indexOf(this._props.keyName) !== -1) {
+ delete this._props.doc[this._props.keyName];
+ } else delete DocCast(this._props.doc.proto)?.[this._props.keyName];
})}>
X
</button>
<input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
- <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description ?? ''}>
- <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
+ <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === this._props.keyName)?.[1].description ?? ''}>
+ <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (this._props.keyName.match(/_/g)?.length || 0), color: keyStyle }}>
{'('.repeat(parenCount)}
- {props.fieldKey}
+ {this._props.keyName}
{')'.repeat(parenCount)}
</div>
</Tooltip>
@@ -124,7 +101,32 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
</td>
<td className="keyValuePair-td-value" style={{ width: `${100 - this._props.keyWidth}%` }} onContextMenu={this.onContextMenu}>
<div className="keyValuePair-td-value-container">
- <EditableView contents={undefined} fieldContents={props} GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} />
+ <EditableView
+ contents={undefined}
+ fieldContents={{
+ Document: this._props.doc,
+ childFilters: returnEmptyFilter,
+ childFiltersByRanges: returnEmptyFilter,
+ searchFilterDocs: returnEmptyDoclist,
+ styleProvider: DefaultStyleProvider,
+ docViewPath: returnEmptyDocViewList,
+ fieldKey: this._props.keyName,
+ isSelected: returnFalse,
+ setHeight: returnFalse,
+ select: emptyFunction,
+ renderDepth: 1,
+ isContentActive: returnFalse,
+ whenChildContentsActiveChanged: emptyFunction,
+ ScreenToLocalTransform: Transform.Identity,
+ focus: emptyFunction,
+ PanelWidth: this._props.PanelWidth,
+ PanelHeight: this._props.PanelHeight,
+ addDocTab: returnFalse,
+ pinToPres: returnZero,
+ }}
+ GetValue={() => Field.toKeyValueString(this._props.doc, this._props.keyName)}
+ SetValue={(value: string) => KeyValueBox.SetField(this._props.doc, this._props.keyName, value)}
+ />
</div>
</td>
</tr>
diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss
index 42e158584..0b195713d 100644
--- a/src/client/views/nodes/LabelBox.scss
+++ b/src/client/views/nodes/LabelBox.scss
@@ -18,6 +18,9 @@
display: inline-block;
margin: auto;
text-overflow: ellipsis;
+ > span {
+ max-height: 100%; // make sure top of text is in view, otherwise it would center on middle of large text span
+ }
}
.labelBox-params {
@@ -29,4 +32,4 @@
width: 100%;
background: lightgray;
border: dimgray solid 1px;
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 934bce448..10eeff08d 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,7 +1,7 @@
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Field } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
@@ -14,13 +14,15 @@ import { StyleProp } from '../StyleProvider';
import { FieldView, FieldViewProps } from './FieldView';
import BigText from './LabelBigText';
import './LabelBox.scss';
+import { PinProps, PresBox } from './trails';
+import { Docs } from '../../documents/Documents';
-export interface LabelBoxProps {
+export interface LabelBoxProps extends FieldViewProps {
label?: string;
}
@observer
-export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProps>() {
+export class LabelBox extends ViewBoxBaseComponent<LabelBoxProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LabelBox, fieldKey);
}
@@ -30,20 +32,20 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
private dropDisposer?: DragManager.DragDropDisposer;
private _timeout: any;
- constructor(props: any) {
+ constructor(props: LabelBoxProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
componentWillUnMount() {
this._timeout && clearTimeout(this._timeout);
}
@computed get Title() {
- return this.dataDoc.title_custom ? StrCast(this.Document.title) : this._props.label ? this._props.label : typeof this.dataDoc[this.fieldKey] === 'string' ? StrCast(this.dataDoc[this.fieldKey]) : StrCast(this.Document.title);
+ return this.dataDoc.title_custom ? StrCast(this.Document.title) : this._props.label ? this._props.label : Field.toString(this.dataDoc[this.fieldKey] as Field);
}
protected createDropTarget = (ele: HTMLDivElement) => {
@@ -89,6 +91,19 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor);
}
+ getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
+ if (!pinProps) return this.Document;
+ const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });
+
+ if (anchor) {
+ if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
+ // addAsAnnotation && this.addDocument(anchor);
+ PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document);
+ return anchor;
+ }
+ return anchor;
+ };
+
fitTextToBox = (
r: any
):
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index b86ba72a0..00e1f04c5 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -1,4 +1,5 @@
import { action, computed, makeObservable } from 'mobx';
+import { observer } from 'mobx-react';
import * as React from 'react';
import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
@@ -13,6 +14,7 @@ import { FieldView, FieldViewProps } from './FieldView';
import './LinkAnchorBox.scss';
import { LinkInfo } from './LinkDocPreview';
const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore
+@observer
export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LinkAnchorBox, fieldKey);
@@ -23,24 +25,26 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
_isOpen = false;
_timeout: NodeJS.Timeout | undefined;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
@computed get linkSource() {
- return this._props.docViewPath()[this._props.docViewPath().length - 2].Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource);
+ return this.DocumentView?.().containerViewPath?.().lastElement().Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource);
}
onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => {
- if (doubleTap) LinkFollower.FollowLink(this.Document, this.linkSource, false);
- else this._props.select(false);
- });
+ const linkSource = this.linkSource;
+ linkSource &&
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => {
+ if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false);
+ else this._props.select(false);
+ });
};
onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
const cdiv = this._ref?.current?.parentElement;
@@ -86,7 +90,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
className={`linkAnchorBox-cont${small ? '-small' : ''}`}
onPointerEnter={e =>
LinkInfo.SetLinkInfo({
- docProps: this._props,
+ DocumentView: this.DocumentView,
+ styleProvider: this._props.styleProvider,
linkSrc: this.linkSource,
linkDoc: this.Document,
showHeader: true,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 7f1d41547..8b6293806 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -20,7 +20,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(LinkBox, fieldKey);
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get anchor1() {
const anchor1 = DocCast(this.dataDoc.link_anchor_1);
const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1;
- return DocumentManager.Instance.getDocumentView(anchor_1, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement());
+ return DocumentManager.Instance.getDocumentView(anchor_1, this.DocumentView?.().containerViewPath?.().lastElement());
}
@computed get anchor2() {
const anchor2 = DocCast(this.dataDoc.link_anchor_2);
const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2;
- return DocumentManager.Instance.getDocumentView(anchor_2, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement());
+ return DocumentManager.Instance.getDocumentView(anchor_2, this.DocumentView?.().containerViewPath?.().lastElement());
}
screenBounds = () => {
if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) {
@@ -59,14 +59,14 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
disposer: IReactionDisposer | undefined;
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this.disposer = reaction(
() => {
if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) {
const a = (this.anchor1 ?? this.anchor2)!;
const b = (this.anchor2 ?? this.anchor1)!;
- const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView;
+ const parxf = this.DocumentView?.().containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView;
const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform();
const a_invXf = a.screenToViewTransform().inverse();
const b_invXf = b.screenToViewTransform().inverse();
@@ -100,6 +100,9 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc._width = params.rx - params?.lx;
this.layoutDoc._height = params?.by - params?.ty;
}
+ } else {
+ this.layoutDoc._width = Math.max(50, NumCast(this.layoutDoc._width));
+ this.layoutDoc._height = Math.max(50, NumCast(this.layoutDoc._height));
}
},
{ fireImmediately: true }
@@ -161,12 +164,11 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
return (
<div className={`linkBox-container${this._props.isContentActive() ? '-interactive' : ''}`} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) }}>
<ComparisonBox
- {...this._props}
+ {...this._props} //
fieldKey="link_anchor"
setHeight={emptyFunction}
dontRegisterView={true}
renderDepth={this._props.renderDepth + 1}
- isContentActive={this._props.isContentActive}
addDocument={returnFalse}
removeDocument={returnFalse}
moveDocument={returnFalse}
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index 8ad0b7dde..13f0ac4fc 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -1,20 +1,27 @@
-import { action, observable } from 'mobx';
+import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { LinkManager } from '../../util/LinkManager';
import './LinkDescriptionPopup.scss';
import { TaskCompletionBox } from './TaskCompletedBox';
@observer
export class LinkDescriptionPopup extends React.Component<{}> {
- @observable public static descriptionPopup: boolean = false;
- @observable public static showDescriptions: string = 'ON';
- @observable public static popupX: number = 700;
- @observable public static popupY: number = 350;
+ public static Instance: LinkDescriptionPopup;
+ @observable public display: boolean = false;
+ @observable public showDescriptions: string = 'ON';
+ @observable public popupX: number = 700;
+ @observable public popupY: number = 350;
@observable description: string = '';
@observable popupRef = React.createRef<HTMLDivElement>();
+ constructor(props: any) {
+ super(props);
+ makeObservable(this);
+ LinkDescriptionPopup.Instance = this;
+ }
+
@action
descriptionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
this.description = e.currentTarget.value;
@@ -22,16 +29,16 @@ export class LinkDescriptionPopup extends React.Component<{}> {
@action
onDismiss = (add: boolean) => {
- LinkDescriptionPopup.descriptionPopup = false;
+ this.display = false;
if (add) {
- LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description);
+ LinkManager.currentLink && (LinkManager.currentLink[DocData].link_description = this.description);
}
};
@action
onClick = (e: PointerEvent) => {
if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) {
- LinkDescriptionPopup.descriptionPopup = false;
+ this.display = false;
TaskCompletionBox.taskCompleted = false;
}
};
@@ -46,13 +53,13 @@ export class LinkDescriptionPopup extends React.Component<{}> {
}
render() {
- return (
+ return !this.display ? null : (
<div
className="linkDescriptionPopup"
ref={this.popupRef}
style={{
- left: LinkDescriptionPopup.popupX ? LinkDescriptionPopup.popupX : 700,
- top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350,
+ left: this.popupX ? this.popupX : 700,
+ top: this.popupY ? this.popupY : 350,
}}>
<input
className="linkDescriptionPopup-input"
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index ea23ecbea..4b242649a 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -18,7 +18,8 @@ import { SearchUtil } from '../../util/SearchUtil';
import { SettingsManager } from '../../util/SettingsManager';
import { Transform } from '../../util/Transform';
import { ObservableReactComponent } from '../ObservableReactComponent';
-import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { StyleProviderFuncType } from './FieldView';
import './LinkDocPreview.scss';
export class LinkInfo {
@@ -43,7 +44,8 @@ export class LinkInfo {
interface LinkDocPreviewProps {
linkDoc?: Doc;
linkSrc?: Doc;
- docProps: DocumentViewSharedProps;
+ DocumentView?: () => DocumentView;
+ styleProvider?: StyleProviderFuncType;
location: number[];
hrefs?: string[];
showHeader?: boolean;
@@ -152,7 +154,7 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
action(() => {
LinkManager.currentLink = this._linkDoc;
LinkManager.currentLinkAnchor = this._linkSrc;
- this._props.docProps.DocumentView?.().select(false);
+ this._props.DocumentView?.().select(false);
if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
SettingsManager.Instance.propertiesWidth = 250;
}
@@ -269,8 +271,8 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
}}
Document={this._targetDoc!}
moveDocument={returnFalse}
- styleProvider={this._props.docProps?.styleProvider}
- docViewPath={returnEmptyDoclist}
+ styleProvider={this._props.styleProvider}
+ containerViewPath={returnEmptyDoclist}
ScreenToLocalTransform={Transform.Identity}
isDocumentActive={returnFalse}
isContentActive={returnFalse}
@@ -291,7 +293,6 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
focus={emptyFunction}
whenChildContentsActiveChanged={returnFalse}
ignoreAutoHeight={true} // need to ignore layout_autoHeight otherwise layout_autoHeight text boxes will expand beyond the preview panel size.
- bringToFront={returnFalse}
NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined}
NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined}
/>
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 3575b21e4..c185c66fc 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -23,12 +23,12 @@ import { DragManager } from '../../../util/DragManager';
import { LinkManager } from '../../../util/LinkManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons';
@@ -96,7 +96,7 @@ type MapMarker = {
// });
@observer
-export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(MapBox, fieldKey);
}
@@ -107,7 +107,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _disposers: { [key: string]: IReactionDisposer } = {};
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -248,7 +248,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
componentDidMount() {
this._unmounting = false;
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
_unmounting = false;
@@ -379,16 +379,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
const targetCreator = (annotationOn: Doc | undefined) => {
- const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow');
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
docView &&
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
dragComplete: e => {
if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
- e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document;
+ e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document;
e.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
@@ -504,7 +504,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 9734d9db1..9825824bd 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -12,7 +12,7 @@
// import { SnappingManager } from '../../../util/SnappingManager';
// import { UndoManager } from '../../../util/UndoManager';
// import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
-// import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+// import { ViewBoxAnnotatableComponent } from '../../DocComponent';
// import { Colors } from '../../global/globalEnums';
// import { AnchorMenu } from '../../pdf/AnchorMenu';
// import { Annotation } from '../../pdf/Annotation';
@@ -83,7 +83,7 @@
// } as google.maps.places.AutocompleteOptions;
// @observer
-// export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
+// export class MapBox2 extends ViewBoxAnnotatableComponent<FieldViewProps & Partial<GoogleMapProps>>() {
// private _dropDisposer?: DragManager.DragDropDisposer;
// private _disposers: { [name: string]: IReactionDisposer } = {};
// private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -137,7 +137,7 @@
// // iterate allMarkers to size, center, and zoom map to contain all markers
// private fitBounds = (map: google.maps.Map) => {
-// const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
+// const curBounds = map.getBounds ?? new window.google.maps.LatLngBounds();
// const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
// !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
// };
@@ -257,7 +257,7 @@
// map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5));
// map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
// setTimeout(() => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
@@ -272,7 +272,7 @@
// @action
// centered = () => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
@@ -282,7 +282,7 @@
// @action
// zoomChanged = () => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index a9c6ba22c..6ccbbbe1c 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -9,19 +9,18 @@
// import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
// import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
// import { CollectionStackingView } from '../../collections/CollectionStackingView';
-// import { ViewBoxAnnotatableProps } from '../../DocComponent';
// import { FieldViewProps } from '../FieldView';
// import { FormattedTextBox } from '../formattedText/FormattedTextBox';
// import './MapBox.scss';
-// interface MapBoxInfoWindowProps {
+// interface MapBoxInfoWindowProps extends FieldViewProps {
// place: Doc;
// renderDepth: number;
// markerMap: { [id: string]: google.maps.Marker };
// isAnyChildContentActive: () => boolean;
// }
// @observer
-// export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & ViewBoxAnnotatableProps & FieldViewProps> {
+// export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps> {
// @action
// private handleInfoWindowClose = () => {
// if (this.props.place.infoWindowOpen) {
diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
index 34e237007..fc5b4dd18 100644
--- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx
+++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
@@ -18,10 +18,10 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
get mapBoxView() {
- return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox;
+ return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox;
}
get mapBox() {
- return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.Document;
}
render() {
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index ea8496c99..8a5bd7ce6 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, EditableText, IconButton, Type } from 'browndash-components';
-import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { MapProvider, Map as MapboxMap } from 'react-map-gl';
@@ -16,18 +16,17 @@ import { LinkManager } from '../../../util/LinkManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { MapAnchorMenu } from '../MapBox/MapAnchorMenu';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
import './MapBox.scss';
-// amongus
/**
* MapBox architecture:
* Main component: MapBox.tsx
@@ -61,7 +60,7 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing
// });
@observer
-export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(MapBoxContainer, fieldKey);
}
@@ -71,6 +70,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
private _disposers: { [key: string]: IReactionDisposer } = {};
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@computed get allSidebarDocs() {
return DocListCast(this.dataDoc[this.SidebarKey]);
@@ -97,7 +101,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
componentDidMount() {
this._unmounting = false;
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
_unmounting = false;
@@ -228,16 +232,16 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
});
const targetCreator = (annotationOn: Doc | undefined) => {
- const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow');
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
docView &&
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
dragComplete: e => {
if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
- e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document;
+ e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document;
e.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
@@ -374,7 +378,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
}
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
@@ -787,8 +791,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
NativeWidth={returnOne}
NativeHeight={returnOne}
onKey={undefined}
- onDoubleClick={undefined}
- onBrowseClick={undefined}
+ onDoubleClickScript={undefined}
+ onBrowseClickScript={undefined}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 959d5d88d..1274220b6 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -5,6 +5,7 @@ import * as Pdfjs from 'pdfjs-dist';
import 'pdfjs-dist/web/pdf_viewer.css';
import * as React from 'react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { ComputedField } from '../../../fields/ScriptField';
@@ -22,19 +23,19 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm';
import { CollectionStackingView } from '../collections/CollectionStackingView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { Colors } from '../global/globalEnums';
import { CreateImage } from '../nodes/WebBoxRenderer';
import { PDFViewer } from '../pdf/PDFViewer';
import { SidebarAnnos } from '../SidebarAnnos';
-import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { ImageBox } from './ImageBox';
import './PDFBox.scss';
import { PinProps, PresBox } from './trails';
@observer
-export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(PDFBox, fieldKey);
}
@@ -58,7 +59,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url;
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
const nw = Doc.NativeWidth(this.Document, this.dataDoc) || 927;
@@ -97,12 +98,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
this.addDocument(region);
- const docViewContent = this._props.docViewPath().lastElement().ContentDiv!;
+ const docViewContent = this.DocumentView?.().ContentDiv!;
const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
newDiv.style.width = NumCast(this.layoutDoc._width).toString();
newDiv.style.height = NumCast(this.layoutDoc._height).toString();
@@ -120,7 +122,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
cropping._width = anchw;
cropping._height = anchh;
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
@@ -132,7 +134,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (addCrop) {
DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
}
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
CreateImage(
'',
@@ -163,7 +165,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
updateIcon = () => {
// currently we render pdf icons as text labels
- const docViewContent = this._props.docViewPath().lastElement().ContentDiv!;
+ const docViewContent = this.DocumentView?.().ContentDiv!;
const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime();
this._pdfViewer?._mainCont.current &&
CollectionFreeFormView.UpdateIcon(
@@ -191,7 +193,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
Object.values(this._disposers).forEach(disposer => disposer?.());
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this._disposers.select = reaction(
() => this._props.isSelected(),
() => {
@@ -219,12 +221,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return this._props.addDocTab(doc, where);
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
this._initialScrollTarget = anchor;
return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options);
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar(false);
@@ -304,7 +306,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
setPdfViewer = (pdfViewer: PDFViewer) => {
this._pdfViewer = pdfViewer;
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (this._initialScrollTarget && docView) {
this.focus(this._initialScrollTarget, { instant: true });
this._initialScrollTarget = undefined;
@@ -525,10 +527,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
removeDocument={this.removeDocument}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}>
<ComponentTag
{...this._props}
- setContentView={emptyFunction} // override setContentView to do nothing
+ setContentViewBox={emptyFunction} // override setContentView to do nothing
NativeWidth={this.sidebarNativeWidthFunc}
NativeHeight={this.sidebarNativeHeightFunc}
PanelHeight={this._props.PanelHeight}
@@ -581,6 +583,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}}>
<PDFViewer
{...this._props}
+ pdfBox={this}
sidebarAddDoc={this.sidebarAddDocument}
addDocTab={this.sidebarAddDocTab}
layoutDoc={this.layoutDoc}
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index c04a81f7d..f6d94ce05 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,4 +1,4 @@
-import { action, observable } from 'mobx';
+import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../../fields/DateField';
@@ -21,6 +21,7 @@ import { media_state } from '../AudioBox';
import { FieldView, FieldViewProps } from '../FieldView';
import { VideoBox } from '../VideoBox';
import { RecordingView } from './RecordingView';
+import { DocData } from '../../../../fields/DocSymbols';
@observer
export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -30,8 +31,13 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
Doc.SetNativeWidth(this.dataDoc, 1280);
Doc.SetNativeHeight(this.dataDoc, 720);
}
@@ -100,7 +106,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
screengrabber.overlayX = 70; //was -400
screengrabber.overlayY = 590; //was 0
- Doc.GetProto(screengrabber)[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
+ screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index f74e6fb2b..1e3933ac3 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -21,12 +21,13 @@ import { TrackMovements } from '../../util/TrackMovements';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline';
import { ContextMenu } from '../ContextMenu';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { media_state } from './AudioBox';
import { FieldView, FieldViewProps } from './FieldView';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import './ScreenshotBox.scss';
import { VideoBox } from './VideoBox';
+import { DocData } from '../../../fields/DocSymbols';
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
@@ -109,7 +110,7 @@ declare class MediaRecorder {
// }
@observer
-export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ScreenshotBox, fieldKey);
}
@@ -121,7 +122,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
return Cast(this.dataDoc[this._props.fieldKey + '_recordingStart'], DateField)?.date.getTime();
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
this.setupDictation();
@@ -144,7 +145,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
componentDidMount() {
this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
- this._props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
// this.layoutDoc.videoWall && reaction(() => ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }),
// ({ width, height }) => {
// if (this._camera) {
@@ -281,7 +282,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
const textField = Doc.LayoutFieldKey(dictationText);
dictationText._layout_autoHeight = false;
- const dictationTextProto = Doc.GetProto(dictationText);
+ const dictationTextProto = dictationText[DocData];
dictationTextProto[`${textField}_recordingSource`] = this.dataDoc;
dictationTextProto[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
dictationTextProto.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
@@ -297,7 +298,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
<div style={{ position: 'relative', height: this.videoPanelHeight() }}>
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
PanelHeight={this.videoPanelHeight}
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 73ad3a004..89650889d 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -14,7 +14,7 @@ import { ScriptManager } from '../../util/ScriptManager';
import { CompileScript, ScriptParam } from '../../util/Scripting';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { ContextMenu } from '../ContextMenu';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { EditableView } from '../EditableView';
import { OverlayView } from '../OverlayView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -23,7 +23,7 @@ import './ScriptingBox.scss';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
-export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private dropDisposer?: DragManager.DragDropDisposer;
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(ScriptingBox, fieldStr);
@@ -56,7 +56,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
@observable private _scriptSuggestedParams: any = '';
@observable private _scriptParamsText: any = '';
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
if (!this.compileParams.length) {
@@ -116,7 +116,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
@action
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this.rawText = this.rawScript;
const observer = new _global.ResizeObserver(
action((entries: any) => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fb42286af..40647feff 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -4,10 +4,11 @@ import { observer } from 'mobx-react';
import { basename } from 'path';
import * as React from 'react';
import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { AudioField, ImageField, VideoField } from '../../../fields/URLField';
import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
@@ -21,12 +22,12 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec
import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { RecordingBox } from './RecordingBox';
import { PinProps, PresBox } from './trails';
import './VideoBox.scss';
@@ -44,7 +45,7 @@ import './VideoBox.scss';
*/
@observer
-export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(VideoBox, fieldKey);
}
@@ -61,10 +62,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _playRegionTimer: any = null; // timeout for playback
private _controlsFadeTimer: any = null; // timeout for controls fade
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
@observable _stackedTimeline: CollectionStackedTimeline | undefined = undefined; // CollectionStackedTimeline ref
@@ -115,7 +116,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
componentDidMount() {
this.unmounting = false;
- this._props.setContentView?.(this); // this tells the DocumentView that this VideoBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the VideoBox when making a link.
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this VideoBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the VideoBox when making a link.
this.player && this.setPlayheadTime(this.timeline?.clipStart || 0);
document.addEventListener('keydown', this.keyEvents, true);
@@ -329,11 +330,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
_height: (height / width) * 150,
title: '--snapshot' + NumCast(this.layoutDoc._layout_currentTimecode) + ' image-',
});
- Doc.SetNativeWidth(Doc.GetProto(imageSnapshot), Doc.NativeWidth(this.layoutDoc));
- Doc.SetNativeHeight(Doc.GetProto(imageSnapshot), Doc.NativeHeight(this.layoutDoc));
+ Doc.SetNativeWidth(imageSnapshot[DocData], Doc.NativeWidth(this.layoutDoc));
+ Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(this.layoutDoc));
this._props.addDocument?.(imageSnapshot);
const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
- link && (Doc.GetProto(link.link_anchor_2 as Doc).timecodeToHide = NumCast((link.link_anchor_2 as Doc).timecodeToShow) + 3);
+ link && (DocCast(link.link_anchor_2)[DocData].timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3);
setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true));
};
@@ -368,7 +369,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
!this.unmounting && this.player && (this.layoutDoc._layout_currentTimecode = this.player.currentTime);
};
- getView = (doc: Doc, options: DocFocusOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._stackedTimeline?.makeDocUnfiltered(doc)) {
if (this.heightPercent === 100) {
this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent;
@@ -608,7 +609,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// removes from currently playing display
@action
removeCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (CollectionStackedTimeline.CurrentlyPlaying && docView) {
const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView);
index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1);
@@ -617,7 +618,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// adds doc to currently playing display
@action
addCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (!CollectionStackedTimeline.CurrentlyPlaying) {
CollectionStackedTimeline.CurrentlyPlaying = [];
}
@@ -738,7 +739,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
zoom = (zoom: number) => this.timeline?.setZoom(zoom);
// plays link
- playLink = (doc: Doc, options: DocFocusOptions) => {
+ playLink = (doc: Doc, options: FocusViewOptions) => {
const startTime = Math.max(0, NumCast(doc.config_clipStart, this._stackedTimeline?.anchorStart(doc) || 0));
const endTime = this.timeline?.anchorEnd(doc);
if (startTime !== undefined) {
@@ -749,7 +750,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// starts marquee selection
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -854,7 +855,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
renderDepth={this._props.renderDepth + 1}
startTag={'_timecodeToShow' /* videoStart */}
endTag={'_timecodeToHide' /* videoEnd */}
- bringToFront={emptyFunction}
playFrom={this.playFrom}
setTime={this.setPlayheadTime}
playing={this.playing}
@@ -885,10 +885,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).backgroundColor = 'transparent';
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.backgroundColor = 'transparent';
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
this.addDocument(region);
const anchx = NumCast(cropping.x);
@@ -904,7 +905,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
cropping.timecodeToHide = undefined;
cropping.timecodeToShow = undefined;
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
@@ -926,7 +927,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (addCrop) {
DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
}
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
return cropping;
};
savedAnnotations = () => this._savedAnnotations;
@@ -941,7 +942,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
style={{
pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
borderRadius,
- overflow: this._props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined,
+ overflow: this.DocumentView?.().layout_fitWidth ? 'auto' : undefined,
}}>
<div className="videoBox-viewer" onPointerDown={this.marqueeDown}>
<div
@@ -955,7 +956,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}}>
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
renderDepth={this._props.renderDepth + 1}
@@ -978,7 +979,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</CollectionFreeFormView>
</div>
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
ref={this._marqueeref}
Document={this.Document}
@@ -986,7 +987,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
annotationLayerScrollTop={0}
scaling={returnOne}
annotationLayerScaling={this._props.NativeDimScaling}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
containerOffset={this.marqueeOffset}
addDocument={this.addDocWithTimecode}
finishMarquee={this.finishMarquee}
@@ -1004,7 +1005,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
@computed get UIButtons() {
- const bounds = this._props.docViewPath().lastElement().getBounds();
+ const bounds = this.DocumentView?.().getBounds;
const width = (bounds?.right || 0) - (bounds?.left || 0);
const curTime = NumCast(this.layoutDoc._layout_currentTimecode);
return (
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c3be2b390..5a07540da 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -24,7 +24,7 @@ import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { Colors } from '../global/globalEnums';
import { LightboxView } from '../LightboxView';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
@@ -33,15 +33,15 @@ import { Annotation } from '../pdf/Annotation';
import { GPTPopup } from '../pdf/GPTPopup/GPTPopup';
import { SidebarAnnos } from '../SidebarAnnos';
import { StyleProp } from '../StyleProvider';
-import { DocComponentView, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { LinkInfo } from './LinkDocPreview';
import { PinProps, PresBox } from './trails';
import './WebBox.scss';
const { CreateImage } = require('./WebBoxRenderer');
const _global = (window /* browser */ || global) /* node */ as any;
@observer
-export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(WebBox, fieldKey);
}
@@ -98,7 +98,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return Cast(this.Document[this._props.fieldKey], WebField)?.url;
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
this._webUrl = this._url; // setting the weburl will change the src parameter of the embedded iframe and force a navigation to it.
@@ -172,7 +172,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
componentDidMount() {
- this._props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
runInAction(() => {
this._annotationKeySuffix = () => (this._urlHash ? this._urlHash + '_' : '') + 'annotations';
@@ -250,7 +250,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
createTextAnnotation = (sel: Selection, selRange: Range | undefined) => {
if (this._mainCont.current && selRange) {
- if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`;
+ if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`;
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
const rect = clientRects.item(i);
@@ -274,12 +274,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// clear selection
this._textAnnotationCreator = undefined;
- if (sel.empty) sel.empty(); // Chrome
+ if (sel.empty)
+ sel.empty(); // Chrome
else if (sel.removeAllRanges) sel.removeAllRanges(); // Firefox
return this._savedAnnotations;
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
if (anchor !== this.Document && this._outerRef.current) {
const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), NumCast(anchor._height), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + NumCast(anchor._height), this._scrollHeight));
@@ -296,9 +297,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
@action
- getView = (doc: Doc, options: DocFocusOptions) => {
- if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this._props.DocumentView?.()));
- if (this.Document.layout_fieldKey === 'layout_icon') this._props.DocumentView?.().iconify();
+ getView = (doc: Doc, options: FocusViewOptions) => {
+ if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this.DocumentView?.()));
+ if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify();
const webUrl = WebCast(doc.config_data)?.url;
if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href);
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false);
@@ -343,7 +344,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
iframeUp = (e: PointerEvent) => {
this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value
this._textAnnotationCreator = undefined;
- this._props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
+ this.DocumentView?.()?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) {
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this._props.NativeDimScaling?.() || 1) * mainContBounds.scale;
@@ -364,7 +365,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
e.stopPropagation();
const sel = window.getSelection();
this._textAnnotationCreator = undefined;
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
// bcz: NEED TO unrotate e.clientX and e.clientY
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
@@ -556,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
clearStyleSheetRules(WebBox.webStyleSheet);
this._scrollTimer = undefined;
const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
- if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) {
+ if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) {
this.layoutDoc.thumb = undefined;
this.layoutDoc.thumbScrollTop = undefined;
this.layoutDoc.thumbNativeWidth = undefined;
@@ -723,10 +725,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onMarqueeDown = (e: React.PointerEvent) => {
const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
this._textAnnotationCreator = undefined;
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
this.marqueeing = [e.clientX, e.clientY];
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -750,7 +753,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.marqueeing = undefined;
this._textAnnotationCreator = undefined;
const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
this._setPreviewCursor?.(x ?? 0, y ?? 0, false, !this._marqueeref.current?.isEmpty, this.Document);
if (x !== undefined && y !== undefined) {
@@ -762,7 +766,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
setTimeout(() => {
// if menu comes up right away, the down event can still be active causing a menu item to be selected
this.specificContextMenu(undefined as any);
- this._props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y);
+ this.DocumentView?.().onContextMenu(undefined, x, y);
});
}
}
@@ -908,7 +912,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
@action
onZoomWheel = (e: React.WheelEvent) => {
- if (this._props.isContentActive(true)) {
+ if (this._props.isContentActive()) {
e.stopPropagation();
}
};
@@ -920,7 +924,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
_innerCollectionView: CollectionFreeFormView | undefined;
zoomScaling = () => this._innerCollectionView?.zoomScaling() ?? 1;
- setInnerContent = (component: DocComponentView) => (this._innerCollectionView = component as CollectionFreeFormView);
+ setInnerContent = (component: ViewBoxInterface) => (this._innerCollectionView = component as CollectionFreeFormView);
@computed get content() {
const interactive = this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None;
@@ -962,7 +966,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
renderAnnotations = (childFilters: () => string[]) => (
<CollectionFreeFormView
{...this._props}
- setContentView={this.setInnerContent}
+ setContentViewBox={this.setInnerContent}
NativeWidth={returnZero}
NativeHeight={returnZero}
originTopLeft={false}
@@ -979,7 +983,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
childFilters={childFilters}
select={emptyFunction}
isAnyChildContentActive={returnFalse}
- bringToFront={emptyFunction}
styleProvider={this.childStyleProvider}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
removeDocument={this.removeDocument}
@@ -1065,7 +1068,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter];
opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])];
- childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc)) return 'none';
}
@@ -1099,7 +1102,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onContextMenu={this.specificContextMenu}>
{this.webpage}
</div>
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<div style={{ position: 'absolute', height: '100%', width: '100%', pointerEvents: this.marqueeing ? 'all' : 'none' }}>
<MarqueeAnnotator
ref={this._marqueeref}
@@ -1109,7 +1112,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
annotationLayerScrollTop={0}
scaling={this._props.NativeDimScaling}
addDocument={this.addDocumentWrapper}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotationsCreator}
selectionText={this.selectionText}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 4fb1a7f17..748c3322e 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -18,6 +18,11 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(CalendarBox, fieldKey);
}
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
componentDidMount(): void {}
componentWillUnmount(): void {}
@@ -105,11 +110,6 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
}
- constructor(props: any) {
- super(props);
- makeObservable(this);
- }
-
render() {
return (
<div className="calendar-box-conatiner">
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 6a2cd359c..7335c9286 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -11,7 +11,8 @@ import { DocServer } from '../../../DocServer';
import { Docs, DocUtils } from '../../../documents/Documents';
import { Transform } from '../../../util/Transform';
import { ObservableReactComponent } from '../../ObservableReactComponent';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions } from '../FieldView';
import { FormattedTextBox } from './FormattedTextBox';
var horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side.
@@ -159,7 +160,7 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
return new Transform(-translateX, -translateY, 1).scale(1 / scale);
};
- outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
+ outerFocus = (target: Doc, options: FocusViewOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
onKeyDown = (e: any) => {
e.stopPropagation();
@@ -207,7 +208,7 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
isDocumentActive={returnFalse}
isContentActive={this.isContentActive}
styleProvider={this._textBox._props.styleProvider}
- docViewPath={this._textBox._props.docViewPath}
+ containerViewPath={this._textBox.DocumentView?.().docViewPath}
ScreenToLocalTransform={this.getDocTransform}
addDocTab={this._textBox._props.addDocTab}
pinToPres={returnFalse}
@@ -216,7 +217,6 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
PanelHeight={this._dashDoc[Height]}
focus={this.outerFocus}
whenChildContentsActiveChanged={this._props.tbox.whenChildContentsActiveChanged}
- bringToFront={emptyFunction}
dontRegisterView={false}
childFilters={this._props.tbox?._props.childFilters}
childFiltersByRanges={this._props.tbox?._props.childFiltersByRanges}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 555b752f0..dc9914637 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -148,7 +148,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
}
createPivotForField = (e: React.MouseEvent) => {
- let container = this._props.tbox._props.DocumentView?.()._props.docViewPath().lastElement();
+ let container = this._props.tbox.DocumentView?.().containerViewPath?.().lastElement();
if (container) {
const embedding = Doc.MakeEmbedding(container.Document);
embedding._type_collection = CollectionViewType.Time;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ae26f170b..731ab1d53 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -14,7 +14,7 @@ import * as React from 'react';
import { BsMarkdownFill } from 'react-icons/bs';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -42,7 +42,7 @@ import { CollectionStackingView } from '../../collections/CollectionStackingView
import { CollectionTreeView } from '../../collections/CollectionTreeView';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
import { AnchorMenu } from '../../pdf/AnchorMenu';
@@ -50,8 +50,8 @@ import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
import { SidebarAnnos } from '../../SidebarAnnos';
import { StyleProp } from '../../StyleProvider';
import { media_state } from '../AudioBox';
-import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { LinkInfo } from '../LinkDocPreview';
import { PinProps, PresBox } from '../trails';
import { DashDocCommentView } from './DashDocCommentView';
@@ -68,10 +68,8 @@ import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
// import * as applyDevTools from 'prosemirror-dev-tools';
-
-export interface FormattedTextBoxProps {}
@observer
-export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps & FormattedTextBoxProps>() {
+export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
@@ -91,6 +89,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
private _editorView: Opt<EditorView>;
public _applyingChange: string = '';
+ private _inDrop = false;
private _finishingLink = false;
private _searchIndex = 0;
private _lastTimedMark: Mark | undefined = undefined;
@@ -123,7 +122,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
@computed get noSidebar() {
- return this._props.docViewPath().lastElement()?._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar;
+ return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar;
}
@computed get layout_sidebarWidthPercent() {
return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
@@ -202,7 +201,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return url.startsWith(document.location.origin) ? new URL(url).pathname.split('doc/').lastElement() : ''; // docId
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
FormattedTextBox.Instance = this;
@@ -271,14 +270,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (target) {
anchor.followLinkAudio = true;
let stopFunc: any;
- Doc.GetProto(target).mediaState = media_state.Recording;
- Doc.GetProto(target).audioAnnoState = 'recording';
- DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
+ const targetData = target[DocData];
+ targetData.mediaState = media_state.Recording;
+ targetData.audioAnnoState = 'recording';
+ DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
let reactionDisposer = reaction(
() => target.mediaState,
action(dictation => {
if (!dictation) {
- Doc.GetProto(target).audioAnnoState = 'stopped';
+ targetData.audioAnnoState = 'stopped';
stopFunc();
reactionDisposer();
}
@@ -310,7 +310,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this._props.docViewPath().lastElement(), () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.DocumentView?.()!, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
});
const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
this._props.rootSelected?.() && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom);
@@ -356,7 +356,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
// if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if ((this._finishingLink || this._props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+ if ((this._finishingLink || this._props.isContentActive() || this._inDrop) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
const numstring = NumCast(dataDoc[this.fieldKey], null);
dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -433,7 +433,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
autoLink = () => {
const newAutoLinks = new Set<Doc>();
- const oldAutoLinks = LinkManager.Links(this._props.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
+ const oldAutoLinks = LinkManager.Links(this.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
if (this._editorView?.state.doc.textContent) {
const isNodeSel = this._editorView.state.selection instanceof NodeSelection;
const f = this._editorView.state.selection.from;
@@ -451,7 +451,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
updateTitle = () => {
const title = StrCast(this.dataDoc.title, Cast(this.dataDoc.title, RichTextField, null)?.Text);
if (
- !this._props.dontRegisterView && // (this._props.Document.isTemplateForField === "text" || !this._props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
+ !this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing
(title.startsWith('-') || title.startsWith('@')) &&
this._editorView &&
!this.dataDoc.title_custom &&
@@ -494,7 +494,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
DocUtils.MakeLink(this.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
newAutoLinks.add(alink);
// DocCast(alink.link_anchor_1).followLinkLocation = 'add:right';
- const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this._props.Document[Id] }];
+ const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.Document[Id] }];
allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term' });
tr = tr.addMark(pos, pos + node.nodeSize, link);
@@ -572,18 +572,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (dragData) {
const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
const effectiveAcl = GetEffectiveAcl(dataDoc);
- const draggedDoc = dragData.draggedDocuments.lastElement();
+ const draggedDoc = dragData.droppedDocuments.lastElement();
let added: Opt<boolean>;
+ const dropAction = dragData.dropAction || dragData.userDropAction;
if ([AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl)) {
// replace text contents when dragging with Alt
if (de.altKey) {
const fieldKey = Doc.LayoutFieldKey(draggedDoc);
- if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this._props.Document)) {
+ if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.Document)) {
Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]);
}
// embed document when drag marked as embed
- } else if (de.embedKey) {
+ } else if (de.embedKey || dropAction) {
const node = schema.nodes.dashDoc.create({
width: NumCast(draggedDoc._width),
height: NumCast(draggedDoc._height),
@@ -591,20 +592,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
docId: draggedDoc[Id],
float: 'unset',
});
- if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
+ if (!['embed', 'copy'].includes((dropAction ?? '') as any)) {
added = dragData.removeDocument?.(draggedDoc) ? true : false;
+ } else {
+ added = true;
}
if (added) {
draggedDoc._freeform_fitContentsToBox = true;
Doc.SetContainer(draggedDoc, this.Document);
const view = this._editorView!;
try {
+ this._inDrop = true;
const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
pos && view.dispatch(view.state.tr.insert(pos, node));
added = pos ? true : false; // pos will be null if you don't drop onto an actual text location
} catch (e) {
console.log('Drop failed', e);
added = false;
+ } finally {
+ this._inDrop = false;
}
}
}
@@ -991,7 +997,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
};
const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
if (link) {
- Doc.GetProto(link).isDictation = true;
+ link[DocData].isDictation = true;
const audioanchor = Cast(link.link_anchor_2, Doc, null);
const textanchor = Cast(link.link_anchor_1, Doc, null);
if (audioanchor) {
@@ -1001,7 +1007,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
audioId: audioanchor[Id],
textId: textanchor[Id],
});
- Doc.GetProto(textanchor).title = 'dictation:' + audiotag.attrs.timeCode;
+ textanchor[DocData].title = 'dictation:' + audiotag.attrs.timeCode;
const tr = this._editorView.state.tr.insert(this._editorView.state.doc.content.size, audiotag);
const tr2 = tr.setSelection(TextSelection.create(tr.doc, tr.doc.content.size));
this._editorView.dispatch(tr.setSelection(TextSelection.create(tr2.doc, tr2.doc.content.size)));
@@ -1056,7 +1062,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return anchorDoc ?? this.Document;
}
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
if (!this.SidebarShown) {
this.toggleSidebar(false);
@@ -1066,7 +1072,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
- focus = (textAnchor: Doc, options: DocFocusOptions) => {
+ focus = (textAnchor: Doc, options: FocusViewOptions) => {
const focusSpeed = options.zoomTime ?? 500;
const textAnchorId = textAnchor[Id];
const findAnchorFrag = (frag: Fragment, editor: EditorView) => {
@@ -1141,7 +1147,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return Doc.NativeAspect(this.Document, this.dataDoc, false) ? this._props.NativeDimScaling?.() || 1 : 1;
}
componentDidMount() {
- !this._props.dontSelectOnLoad && this._props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ !this._props.dontSelectOnLoad && this._props.setContentViewBox?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
this._cachedLinks = LinkManager.Links(this.Document);
this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
this._disposers.layout_autoHeight = reaction(
@@ -1410,7 +1416,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
(this._editorView as any).TextView = this;
}
- const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()));
+ const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()));
if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
const selLoadChar = FormattedTextBox.SelectOnLoadChar;
FormattedTextBox.SelectOnLoad = undefined;
@@ -1531,7 +1537,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (!state || !editor || !this.ProseRef?.children[0].className.includes('-focused')) return;
if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
- else if (this._props.isContentActive(true)) {
+ else if (this._props.isContentActive()) {
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
let xpos = pcords?.pos || 0;
while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) {
@@ -1764,7 +1770,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
};
const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
- const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
+ const scrollHeight = this.ProseRef && proseHeight;
if (this._props.setHeight && scrollHeight && !this._props.dontRegisterView) {
// if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
@@ -1777,7 +1783,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
}
};
- fitContentsToBox = () => BoolCast(this._props.Document._freeform_fitContentsToBox);
+ fitContentsToBox = () => BoolCast(this.Document._freeform_fitContentsToBox);
sidebarContentScaling = () => (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
@@ -1852,7 +1858,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
setHeight={this.setSidebarHeight}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}>
<ComponentTag
{...this._props}
ref={this._sidebarTagRef as any}
@@ -2011,7 +2017,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
cursor: this._props.isContentActive() ? 'text' : undefined,
height: this._props.height ? 'max-content' : undefined,
overflow: this.layout_autoHeight ? 'hidden' : undefined,
- pointerEvents: Doc.ActiveTool === InkTool.None && !this._props.onBrowseClick?.() ? undefined : 'none',
+ pointerEvents: Doc.ActiveTool === InkTool.None && !this._props.onBrowseClickScript?.() ? undefined : 'none',
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyDown}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index be8736525..ce17af6ca 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -134,7 +134,8 @@ export class FormattedTextBoxComment {
//nbef &&
naft &&
LinkInfo.SetLinkInfo({
- docProps: textBox.props,
+ DocumentView: textBox.DocumentView,
+ styleProvider: textBox._props.styleProvider,
linkSrc: textBox.Document,
linkDoc: linkDoc ? (DocServer.GetCachedRefField(linkDoc) as Doc) : undefined,
location: (pos => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - Math.max(0, nbef - 1))),
diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx
index 7d0086c0c..6e7c3e612 100644
--- a/src/client/views/nodes/importBox/ImportElementBox.tsx
+++ b/src/client/views/nodes/importBox/ImportElementBox.tsx
@@ -1,4 +1,4 @@
-import { computed } from 'mobx';
+import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse } from '../../../../Utils';
@@ -12,6 +12,10 @@ export class ImportElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ImportElementBox, fieldKey);
}
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1));
@computed get mainItem() {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 6fa64a765..9e5ea9524 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, makeObservable, observable, Observ
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
-import { Animation } from '../../../../fields/DocSymbols';
+import { Animation, DocData } from '../../../../fields/DocSymbols';
import { Copy, Id } from '../../../../fields/FieldSymbols';
import { InkField } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -31,8 +31,8 @@ import { TreeView } from '../../collections/TreeView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
-import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
@@ -70,7 +70,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
static navigateToDocScript: ScriptField;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
if (!PresBox.navigateToDocScript) {
@@ -184,7 +184,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
},
{ fireImmediately: true }
);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this._unmounting = false;
this.turnOffEdit(true);
this._disposers.selection = reaction(
@@ -294,13 +294,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
listItemDoc.presentation_effect = this.activeItem.presBulletEffect;
listItemDoc.presentation_transition = 500;
targetView?.setAnimEffect(listItemDoc, 500);
- if (targetView?.docView && this.activeItem.presBulletExpand) {
- targetView.docView._animateScalingTo = 1.2;
- targetView.docView._animateScaleTime = 400;
- Doc.AddUnHighlightWatcher(() => {
- targetView.docView!._animateScaleTime = undefined;
- targetView!.docView!._animateScalingTo = 0;
- });
+ if (targetView && this.activeItem.presBulletExpand) {
+ targetView.setAnimateScaling(1.2, 400);
+ Doc.AddUnHighlightWatcher(() => targetView?.setAnimateScaling(0, undefined));
}
listItemDoc.opacity = undefined;
this.activeItem.presentation_indexed = presIndexed + 1;
@@ -442,9 +438,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const setData = bestTargetView?.ComponentView?.setData;
if (setData) setData(activeItem.config_data);
else {
- const current = Doc.GetProto(bestTarget)[fkey];
- Doc.GetProto(bestTarget)[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current;
- Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
+ const bestTargetData = bestTarget[DocData];
+ const current = bestTargetData[fkey];
+ bestTargetData[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current;
+ bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
}
bestTarget[fkey + '_usePath'] = activeItem.config_usePath;
setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
@@ -502,11 +499,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) {
if (bestTarget.fillColor !== activeItem.config_fillColor) {
- Doc.GetProto(bestTarget).fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor));
+ bestTarget[DocData].fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor));
changed = true;
}
if (bestTarget.color !== activeItem.config_color) {
- Doc.GetProto(bestTarget).color = StrCast(activeItem.config_color, StrCast(bestTarget.color));
+ bestTarget[DocData].color = StrCast(activeItem.config_color, StrCast(bestTarget.color));
changed = true;
}
if (bestTarget.width !== activeItem.width) {
@@ -563,7 +560,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return doc;
});
const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]);
- Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList;
+ bestTarget[DocData][fkey + '_annotations'] = newList;
}
if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) {
changed = true;
@@ -584,9 +581,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
data.fill && (doc._fillColor = data.fill);
doc._width = data.w;
doc._height = data.h;
- data.data && (Doc.GetProto(doc).data = field);
- data.text && (Doc.GetProto(doc).text = tfield);
- Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc);
+ data.data && (doc[DocData].data = field);
+ data.text && (doc[DocData].text = tfield);
+ Doc.AddDocToList(bestTarget[DocData], layoutField, doc);
}
});
setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10);
@@ -652,7 +649,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinProps.pinData.dataannos) {
const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.config_annotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered));
+ pinDoc.config_annotations = new List<Doc>(DocListCast(targetDoc[DocData][fkey + '_annotations']).filter(doc => !doc.layout_unrendered));
}
if (pinProps.pinData.inkable) {
pinDoc.config_fillColor = targetDoc.fillColor;
@@ -767,7 +764,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined;
const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500);
- const options: DocFocusOptions = {
+ const options: FocusViewOptions = {
willPan: activeItem.presentation_movement !== PresMovement.None,
willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center,
zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.config_zoom, 1),
@@ -1119,7 +1116,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
presDocView && SelectionManager.SelectView(presDocView, false);
};
- focusElement = (doc: Doc, options: DocFocusOptions) => {
+ focusElement = (doc: Doc, options: FocusViewOptions) => {
this.selectElement(doc);
return undefined;
};
@@ -2609,7 +2606,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
moveDocument={returnFalse}
ignoreUnrendered={true}
childDragAction="move"
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
//childLayoutFitWidth={returnTrue}
childOpacity={returnOne}
childClickScript={PresBox.navigateToDocScript}
@@ -2622,7 +2619,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
ScreenToLocalTransform={this.getTransform}
AddToMap={this.AddToMap}
RemFromMap={this.RemFromMap}
- hierarchyIndex={emptyPath}
+ hierarchyIndex={emptyPath as any as number[]}
/>
) : null}
</div>
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 4945d66c8..5b2aa1cde 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../../nodes/FieldView';
import { StyleProp } from '../../StyleProvider';
import { PresBox } from './PresBox';
@@ -41,7 +41,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
readonly expandViewHeight = 100;
readonly collapsedHeight = 35;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
// the presentation view that renders this slide
@computed get presBoxView() {
- return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as PresBox;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as PresBox;
}
// the presentation view document that renders this slide
@@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton);
embedHeight = () => this.collapsedHeight + this.expandViewHeight;
embedWidth = () => this._props.PanelWidth() / 2;
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property);
};
/**
@@ -116,7 +116,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
hideLinkButton={true}
ScreenToLocalTransform={Transform.Identity}
renderDepth={this._props.renderDepth + 1}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -128,7 +128,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
whenChildContentsActiveChanged={returnFalse}
addDocTab={returnFalse}
pinToPres={returnFalse}
- bringToFront={returnFalse}
/>
</div>
);
@@ -196,7 +195,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const dragArray = this.presBoxView?._dragArray ?? [];
const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.slideDoc);
- dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this._props.DocumentView?.()?._props.treeViewDoc;
+ dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.DocumentView?.()?._props.treeViewDoc;
dragData.moveDocument = this._props.moveDocument;
const dragItem: HTMLElement[] = [];
const classesToRestore = new Map<HTMLElement, string>();