aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx104
1 files changed, 41 insertions, 63 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f665c69ab..40ae1459f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
-import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
+import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
@@ -109,8 +109,10 @@ export interface DocFocusOptions {
easeFunc?: 'linear' | 'ease'; // transition method for scrolling
}
export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt<number>;
-export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
+export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps | 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;
@@ -119,10 +121,8 @@ export interface DocComponentView {
getView?: (doc: Doc) => 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)
- ignoreNativeDimScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling.
select?: (ctrlKey: boolean, shiftKey: boolean) => void;
focus?: (textAnchor: Doc, options: DocFocusOptions) => Opt<number>;
- menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected.
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)
@@ -136,12 +136,7 @@ export interface DocComponentView {
componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set<Doc>) => void;
incrementalRendering?: () => void;
- layout_fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox)
- overridePointerEvents?: () => 'all' | 'none' | undefined; // if the conmponent overrides the pointer events for the document (e.g, KeyValueBox always allows pointer events)
- fieldKey?: string;
- annotationKey?: string;
infoUI?: () => JSX.Element;
- getTitle?: () => string;
getCenter?: (xf: Transform) => { X: number; Y: number };
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 };
@@ -151,33 +146,28 @@ export interface DocComponentView {
}
// These props are passed to both FieldViews and DocumentViews
export interface DocumentViewSharedProps {
- fieldKey?: string; // only used by FieldViews but helpful here to allow styleProviders to access fieldKey of FieldViewProps. In priniciple, passing a fieldKey to a documentView could override or be the default fieldKey for fieldViews
- DocumentView?: () => DocumentView;
renderDepth: number;
Document: Doc;
- DataDoc?: 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
- suppressSetHeight?: boolean;
setContentView?: (view: DocComponentView) => any;
- CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
PanelWidth: () => number;
PanelHeight: () => number;
- shouldNotScale?: () => boolean;
docViewPath: () => DocumentView[];
- 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.
+ childFilters: () => string[];
+ childFiltersByRanges: () => string[];
styleProvider: Opt<StyleProviderFunc>;
setTitleFocus?: () => void;
focus: DocFocusFunc;
layout_fitWidth?: (doc: Doc) => boolean | undefined;
- childFilters: () => string[];
- childFiltersByRanges: () => string[];
searchFilterDocs: () => Doc[];
layout_showTitle?: () => string;
whenChildContentsActiveChanged: (isActive: boolean) => void;
- rootSelected: () => boolean; // whether the root of a template has been selected
+ 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;
@@ -186,26 +176,27 @@ export interface DocumentViewSharedProps {
pinToPres: (document: Doc, pinProps: PinProps) => void;
ScreenToLocalTransform: () => Transform;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
- dragAction?: dropActionType;
+ waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
+ defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
+ pointerEvents?: () => Opt<string>;
treeViewDoc?: Doc;
xPadding?: number;
yPadding?: number;
- dropAction?: dropActionType;
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
- waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
- defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
- pointerEvents?: () => Opt<string>;
- scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
- createNewFilterDoc?: () => void;
- updateFilterDoc?: (doc: Doc) => void;
- dontHideOnDrag?: boolean;
}
// these props are specific to DocuentViews
@@ -219,12 +210,11 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
hideOpenButton?: boolean;
hideDeleteButton?: boolean;
hideLinkAnchors?: boolean;
- isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
- isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
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
- radialMenu?: String[];
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
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
@@ -242,8 +232,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
// these props are only available in DocumentViewIntenral
export interface DocumentViewInternalProps extends DocumentViewProps {
- NativeWidth: () => number;
- NativeHeight: () => number;
isSelected: () => boolean;
select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
DocumentView: () => DocumentView;
@@ -327,12 +315,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@computed get finalLayoutKey() {
return StrCast(this.Document.layout_fieldKey, 'layout');
}
- @computed get nativeWidth() {
- return this.props.NativeWidth();
- }
- @computed get nativeHeight() {
- return this.props.NativeHeight();
- }
@computed get disableClickScriptFunc() {
const onScriptDisable = this.props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
// prettier-ignore
@@ -507,7 +489,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.Document.title);
} else {
// onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
- if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {
+ if ((this.layoutDoc.onDragStart || this.props.TemplateDataDocument) && !(e.ctrlKey || e.button > 0)) {
stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
}
preventDefault = false;
@@ -549,7 +531,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._downX = e.clientX;
this._downY = e.clientY;
this._downTime = Date.now();
- if ((Doc.ActiveTool === InkTool.None || this.props.addDocTab === returnFalse) && !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
+ if ((Doc.ActiveTool === InkTool.None || this.props.addDocTab === returnFalse) && !(this.props.TemplateDataDocument && !(e.ctrlKey || e.button > 0))) {
// click events stop here if the document is active and no modes are overriding it
// if this is part of a template, let the event go up to the template root unless right/ctrl clicking
if (
@@ -762,7 +744,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.props.renderDepth === 0) {
appearanceItems.splice(0, 0, { description: 'Open in Lightbox', event: () => LightboxView.Instance.SetLightboxDoc(this.Document), icon: 'external-link-alt' });
}
- this.Document.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.Document, {}), icon: 'eye' });
+ appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.Document, {}), icon: 'eye' });
!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' });
@@ -815,7 +797,7 @@ 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.DataDoc), icon: 'concierge-bell' });
+ moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.props.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))) {
@@ -899,13 +881,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
};
@computed get _rootSelected() {
- return this.props.isSelected() || BoolCast(this.Document.rootDocument && this.props.rootSelected?.());
+ return this.props.isSelected() || BoolCast(this.props.TemplateDataDocument && this.props.rootSelected?.());
}
rootSelected = () => this._rootSelected;
panelHeight = () => this.props.PanelHeight() - this.headerMargin;
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler);
- setHeight = (height: number) => (this.layoutDoc._height = height);
+ 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;
@@ -939,17 +921,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<DocumentContentsView
key={1}
{...this.props}
+ fieldKey=""
pointerEvents={this.contentPointerEvents}
docViewPath={this.props.viewPath}
setContentView={this.setContentView}
childFilters={this.childFilters}
PanelHeight={this.panelHeight}
- setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
+ setHeight={this.setHeight}
isContentActive={this.isContentActive}
ScreenToLocalTransform={this.screenToLocal}
rootSelected={this.rootSelected}
onClick={this.onClickFunc}
- focus={this.props.focus}
setTitleFocus={this.setTitleFocus}
layout_fieldKey={this.finalLayoutKey}
/>
@@ -1386,11 +1368,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
};
public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`;
- if (dataTrans) this.rootDoc._dataTransition = `${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.rootDoc._dataTransition = 'inherit';
+ this.Document._dataTransition = 'inherit';
afterTrans?.();
}, timeInMs + 10));
};
@@ -1428,9 +1410,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
get topMost() {
return this.props.renderDepth === 0;
}
- get rootDoc() {
- return this.Document;
- }
get dataDoc() {
return this.docView?.dataDoc ?? this.Document;
}
@@ -1441,21 +1420,21 @@ export class DocumentView extends React.Component<DocumentViewProps> {
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.rootDoc);
+ 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.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.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.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkBtn + (this.isSelected() ? ':selected' : ''));
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkBtn + (this.SELECTED ? ':selected' : ''));
}
- hideLinkCount = () => this.props.renderDepth === -1 || (this.isSelected() && this.props.renderDepth) || !this._isHovering || this.hideLinkButton;
+ hideLinkCount = () => this.props.renderDepth === -1 || (this.SELECTED && this.props.renderDepth) || !this._isHovering || this.hideLinkButton;
@computed get linkCountView() {
return <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.scaleToScreenSpace} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
}
@@ -1466,13 +1445,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return Doc.Layout(this.Document, this.props.LayoutTemplate?.());
}
@computed get nativeWidth() {
- return this.docView?._componentView?.ignoreNativeDimScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth));
+ 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.docView?._componentView?.ignoreNativeDimScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth));
+ 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() {
- return this.props.shouldNotScale?.() || (this.layout_fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
+ return (this.layout_fitWidth && !this.nativeWidth) || this.props.LayoutTemplateString?.includes(KeyValueBox.name) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
}
@computed get effectiveNativeWidth() {
return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
@@ -1593,7 +1572,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
docViewPathFunc = () => this.docViewPath;
isSelected = () => this.SELECTED;
select = (extendSelection: boolean, focusSelection?: boolean) => {
- if (this.isSelected() && SelectionManager.Views().length > 1) SelectionManager.DeselectView(this);
+ if (this.SELECTED && SelectionManager.Views().length > 1) SelectionManager.DeselectView(this);
else {
SelectionManager.SelectView(this, extendSelection);
if (focusSelection) {
@@ -1692,7 +1671,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
{...this.props}
DocumentView={this.selfView}
viewPath={this.docViewPathFunc}
- shouldNotScale={this.ShouldNotScale}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
NativeWidth={this.NativeWidth}