aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-08-20 19:11:00 -0400
committerbobzel <zzzman@gmail.com>2024-08-20 19:11:00 -0400
commit5196009ec6bcb673fd2a4519c54442df218841f7 (patch)
tree79f4b1d559c20a6bfd9b4759a5cbe9d8f8c00fe1 /src/client/views/nodes/DocumentView.tsx
parent0e975569e5686138e52bdc554b3f0391f42aeead (diff)
parente57584a1be9d428fb40fc789494a7ac0ac14fb84 (diff)
fixed up a bunch of things in face recognition
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx300
1 files changed, 176 insertions, 124 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9ff96c692..c807d99ac 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,13 +1,13 @@
/* eslint-disable no-use-before-define */
/* eslint-disable react/jsx-props-no-spreading */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { Property } from 'csstype';
import { Howl } from 'howler';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Fade, JackInTheBox } from 'react-awesome-reveal';
-import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simulateMouseClick } from '../../../ClientUtils';
+import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simMouseEvent, simulateMouseClick } from '../../../ClientUtils';
import { Utils, emptyFunction } from '../../../Utils';
import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../fields/Doc';
import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
@@ -33,7 +33,7 @@ import { UPDATE_SERVER_CACHE } from '../../util/LinkManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SearchUtil } from '../../util/SearchUtil';
import { SnappingManager } from '../../util/SnappingManager';
-import { UndoManager, undoBatch, undoable } from '../../util/UndoManager';
+import { UndoManager, undoable } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from '../DocComponent';
@@ -43,6 +43,7 @@ import { ObserverJsxParser } from '../ObservableReactComponent';
import { PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { ViewBoxInterface } from '../ViewBoxInterface';
+import { GroupActive } from './CollectionFreeFormDocumentView';
import { DocumentContentsView } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
import './DocumentView.scss';
@@ -52,14 +53,7 @@ import { OpenWhere, OpenWhereMod } from './OpenWhere';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails/PresEnums';
import SpringAnimation from './trails/SlideEffect';
-import { SpringSettings, SpringType, springMappings } from './trails/SpringUtils';
-
-interface Window {
- MediaRecorder: MediaRecorder;
-}
-declare class MediaRecorder {
- constructor(e: any); // whatever MediaRecorder has
-}
+import { SpringType, springMappings } from './trails/SpringUtils';
export interface DocumentViewProps extends FieldViewSharedProps {
hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected
@@ -72,7 +66,7 @@ export interface DocumentViewProps extends FieldViewSharedProps {
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
+ contentPointerEvents?: Property.PointerEvents | 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
dontCenter?: 'x' | 'y' | 'xy';
childHideDecorationTitle?: boolean;
childHideResizeHandles?: boolean;
@@ -88,7 +82,7 @@ export interface DocumentViewProps extends FieldViewSharedProps {
dragStarting?: () => void;
dragEnding?: () => void;
- parent?: any; // parent React component view (see CollectionFreeFormDocumentView)
+ reactParent?: React.Component; // parent React component view (see CollectionFreeFormDocumentView)
}
@observer
export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps>() {
@@ -104,7 +98,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
private _disposers: { [name: string]: IReactionDisposer } = {};
private _doubleClickTimeout: NodeJS.Timeout | undefined;
- private _singleClickFunc: undefined | (() => any);
+ private _singleClickFunc: undefined | (() => void);
private _longPressSelector: NodeJS.Timeout | undefined;
private _downX: number = 0;
private _downY: number = 0;
@@ -123,7 +117,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
@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 _pointerEvents: Property.PointerEvents | undefined = undefined;
@observable _componentView: Opt<ViewBoxInterface<FieldViewProps>> = 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;
@@ -133,16 +127,16 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
animateScaleTime = () => this._animateScaleTime ?? 100;
style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop);
- @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 + ':docView'); } // prettier-ignore
+ @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity) as number; } // prettier-ignore
+ @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow) as string; } // prettier-ignore
+ @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding) as string; } // prettier-ignore
+ @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations) as JSX.Element; } // prettier-ignore
+ @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore
@computed get showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore
- @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore
- @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 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 showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore
+ @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore
+ @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore
+ @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // 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
@@ -153,7 +147,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
@computed get disableClickScriptFunc() {
const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
- return (DocumentView.LongPress ||
+ return (SnappingManager.LongPress ||
onScriptDisable === 'always' ||
(onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))); // prettier-ignore
}
@@ -163,13 +157,13 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
/// disable pointer events on content when there's an enabled onClick script (and not in explore mode) and the contents aren't forced active, or if contents are marked inactive
@computed get _contentPointerEvents() {
TraceMobx();
- return this._props.contentPointerEvents ??
+ return (this._props.contentPointerEvents ??
((!this.disableClickScriptFunc && //
this.onClickHdlr &&
!SnappingManager.ExploreMode &&
!this.layoutDoc.layout_isSvg &&
this.isContentActive() !== true) ||
- this.isContentActive() === false)
+ this.isContentActive() === false))
? 'none'
: this._pointerEvents;
}
@@ -223,7 +217,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
{ fireImmediately: true }
);
this._disposers.pointerevents = reaction(
- () => this.style(this.Document, StyleProp.PointerEvents),
+ () => this.style(this.Document, StyleProp.PointerEvents) as Property.PointerEvents | undefined,
pointerevents => {
this._pointerEvents = pointerevents;
},
@@ -250,7 +244,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
Object.values(this._disposers).forEach(disposer => disposer?.());
}
- startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
+ startDragging(x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) {
const docView = this._docView;
if (this._mainCont.current && docView) {
const views = DocumentView.Selected().filter(dv => dv.ContentDiv);
@@ -297,17 +291,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
e.stopPropagation();
};
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- const documentView = this._docView;
- if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
+ if (this._docView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.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);
const scriptProps = {
this: this.Document,
_readOnly_: false,
scriptContext: this._props.scriptContext,
- documentView,
+ documentView: this._docView,
clientX: e.clientX,
clientY: e.clientY,
shiftKey: e.shiftKey,
@@ -317,44 +309,40 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
};
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
- if (this.onDoubleClickHdlr?.script) {
- UndoManager.RunInBatch(() => this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
- } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
- UndoManager.RunInBatch(() => this._props.addDocTab(this.Document, OpenWhere.lightboxAlways), 'double tap');
- DocumentView.DeselectAll();
- Doc.UnBrushDoc(this.Document);
- } else {
- this._singleClickFunc?.();
- }
+ undoable(() => {
+ if (this.onDoubleClickHdlr?.script) {
+ const res = this.onDoubleClickHdlr.script.run(scriptProps, console.log).result as { select: boolean };
+ res.select && this._props.select(false);
+ } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
+ this._props.addDocTab(this.Document, OpenWhere.lightboxAlways);
+ DocumentView.DeselectAll();
+ Doc.UnBrushDoc(this.Document);
+ } else this._singleClickFunc?.();
+ }, 'on double click: ' + this.Document.title)();
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = undefined;
this._singleClickFunc = undefined;
} else {
- let clickFunc: undefined | (() => any);
- if (!this.disableClickScriptFunc && this.onClickHdlr?.script) {
- clickFunc = undoable(() => {
- this.onClickHdlr?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
- }, '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 && !(e.ctrlKey || e.button > 0)) {
- stopPropagate = false;
- }
- preventDefault = false;
- }
- const sendToBack = e.altKey ? () => documentView._props.bringToFront?.(this.Document, true) : undefined;
+ const sendToBack = e.altKey ? () => this._props.bringToFront?.(this.Document, true) : undefined;
const selectFunc = () => {
+ !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
// selecting a view that is part of a template proxies the selection back to the root of the template
const templateRoot = !(e.ctrlKey || e.button > 0) && this._props.docViewPath?.().reverse().find(dv => !dv._props.TemplateDataDocument); // prettier-ignore
(templateRoot || this._docView)?.select(e.ctrlKey || e.shiftKey, e.metaKey);
};
- this._singleClickFunc = clickFunc ?? sendToBack ?? selectFunc;
- const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
- if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
+ const clickFunc = this.onClickFunc?.()?.script ? () => (this.onClickFunc?.()?.script.run(scriptProps, console.log).result as Opt<{ select: boolean }>)?.select && this._props.select(false) : undefined;
+ if (!clickFunc) {
+ // 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 && !(e.ctrlKey || e.button > 0)) stopPropagate = false;
+ preventDefault = false;
+ }
+ this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.title);
+ const waitForDblClick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
+ if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') {
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300);
// eslint-disable-next-line no-use-before-define
- } else if (!DocumentView.LongPress) {
+ } else if (!SnappingManager.LongPress) {
this._singleClickFunc();
this._singleClickFunc = undefined;
}
@@ -365,9 +353,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
});
onPointerDown = (e: React.PointerEvent): void => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
// eslint-disable-next-line no-use-before-define
- this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000);
+ this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000);
if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView;
this._downX = e.clientX;
@@ -418,7 +406,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
}
// eslint-disable-next-line no-use-before-define
- if (DocumentView.LongPress) e.preventDefault();
+ if (SnappingManager.LongPress) e.preventDefault();
};
toggleFollowLink = undoable((): void => {
@@ -456,7 +444,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (this.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
- alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document." : 'Linking to document tabs not yet supported.');
+ alert(
+ (e.target as HTMLElement)?.closest?.('*.lm_content')
+ ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document."
+ : 'Linking to document tabs not yet supported.'
+ );
return true;
}
const annoData = de.complete.annoDragData;
@@ -538,9 +530,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
}
const cm = ContextMenu.Instance;
- if (!cm || (e as any)?.nativeEvent?.SchemaHandled || SnappingManager.ExploreMode) return;
+ if (!cm || SnappingManager.ExploreMode) return;
- if (e && !(e.nativeEvent as any).dash) {
+ if (e && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) {
const onDisplay = () => {
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));
@@ -568,7 +560,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
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 : [];
+ const appearanceItems = appearance?.subitems ?? [];
if (this._props.renderDepth === 0) {
appearanceItems.splice(0, 0, { description: 'Open in Lightbox', event: () => DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' });
@@ -584,7 +576,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
// creates menu for the user to select how to reveal the flashcards
if (this.Document._layout_isFlashcard) {
const revealOptions = cm.findByDescription('Reveal Options');
- const revealItems: ContextMenuProps[] = revealOptions && 'subitems' in revealOptions ? revealOptions.subitems : [];
+ const revealItems = revealOptions?.subitems ?? [];
revealItems.push({ description: 'Hover', event: () => { this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'; }, icon: 'hand-point-up' }); // prettier-ignore
revealItems.push({ description: 'Flip', event: () => { this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip'; }, icon: 'rotate' }); // prettier-ignore
!revealOptions && cm.addItem({ description: 'Reveal Options', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
@@ -592,15 +584,16 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (this._props.bringToFront) {
const zorders = cm.findByDescription('ZOrder...');
- const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
+ const zorderItems = zorders?.subitems ?? [];
zorderItems.push({ description: 'Bring to Front', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' });
zorderItems.push({ description: 'Send to Back', event: () => DocumentView.Selected().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(
+ event: undoable(
action(() => {
this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged;
- })
+ }),
+ 'set zIndex drag'
),
icon: 'hand-point-up',
});
@@ -609,7 +602,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
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 : [];
+ const onClicks = existingOnClick?.subitems ?? [];
onClicks.push({ description: 'Enter Portal', event: undoable(() => DocUtils.makeIntoPortal(this.Document, this.layoutDoc, this._allLinks), 'make into portal'), icon: 'window-restore' });
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
@@ -634,7 +627,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
}
const more = cm.findByDescription('More...');
- const moreItems = more && 'subitems' in more ? more.subitems : [];
+ const moreItems = more?.subitems ?? [];
if (!Doc.IsSystem(this.Document)) {
if (!Doc.noviceMode) {
moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
@@ -658,7 +651,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' });
const help = cm.findByDescription('Help...');
- const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : [];
+ const helpItems = help?.subitems ?? [];
!Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this._props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' });
!Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' });
!Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' });
@@ -728,7 +721,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
anchorPanelWidth = () => this._props.PanelWidth() || 1;
anchorPanelHeight = () => this._props.PanelHeight() || 1;
- anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
+ anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
// prettier-ignore
switch (property.split(':')[0]) {
case StyleProp.ShowTitle: return '';
@@ -776,7 +769,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
fieldsDropdown = (placeholder: string) => (
<div
- ref={action((r: any) => { r && (this._titleDropDownInnerWidth = DivWidth(r));} )} // prettier-ignore
+ ref={r => { r && runInAction(() => (this._titleDropDownInnerWidth = DivWidth(r)));}} // prettier-ignore
onPointerDown={action(() => { this._changingTitleField = true; })} // prettier-ignore
style={{ width: 'max-content', background: SnappingManager.userBackgroundColor, color: SnappingManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
<FieldsDropdown
@@ -854,7 +847,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
.map(field => Field.toKeyValueString(this.Document, field))
.join('\\')
}
- SetValue={undoBatch((input: string) => {
+ SetValue={undoable((input: string) => {
if (input?.startsWith('$')) {
if (this.layoutDoc.layout_showTitle) {
this.layoutDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined;
@@ -865,7 +858,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
Doc.SetField(targetDoc, showTitle, input);
}
return true;
- })}
+ }, 'set title')}
/>
</div>
</div>
@@ -903,7 +896,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
const showTitle = this.showTitle?.split(':')[0];
return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate
? null
- : this.docContents ?? (
+ : (this.docContents ?? (
<div
className="documentView-node"
id={this.Document.type !== DocumentType.LINK ? this._docView?.DocUniqueId : undefined}
@@ -929,27 +922,33 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
)}
{this.widgetDecorations ?? null}
</div>
- );
+ ));
};
render() {
TraceMobx();
const { highlighting, borderPath } = this;
+ const { highlightIndex, highlightStyle, highlightColor, highlightStroke } = (highlighting as { highlightIndex: number; highlightStyle: string; highlightColor: string; highlightStroke: boolean }) ?? {
+ highlightIndex: undefined,
+ highlightStyle: undefined,
+ highlightColor: undefined,
+ highlightStroke: undefined,
+ };
+ const { clipPath, jsx } = (borderPath as { clipPath: string; jsx: JSX.Element }) ?? { clipPath: undefined, jsx: undefined };
const boxShadow = !highlighting
? this.boxShadow
- : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed'
- ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}`
+ : highlighting && this.borderRounding && highlightStyle !== 'dashed'
+ ? `0 0 0 ${highlightIndex}px ${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',
- border: highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined,
+ outline: highlighting && !this.borderRounding && !highlightStroke ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px',
+ border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
boxShadow,
- clipPath: borderPath?.clipPath,
+ clipPath,
});
return (
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events
<div
className={`${DocumentView.ROOT_DIV} docView-hack`}
ref={this._mainCont}
@@ -963,8 +962,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
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)
}}>
- {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)}
- {borderPath?.jsx}
+ {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)}
+ {jsx}
</div>
);
}
@@ -974,9 +973,24 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
* @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) {
- let dir = (presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) as PresEffectDirection;
- const transitionTime = presEffectDoc?.presentation_transition ? NumCast(presEffectDoc?.presentation_transition) : 500;
+ public static AnimationEffect(
+ renderDoc: JSX.Element,
+ presEffectDoc: Opt<
+ | Doc
+ | {
+ presentation_effectDirection?: string;
+ followLinkAnimDirection?: string;
+ presentation_transition?: number;
+ followLinkTransitionTime?: number;
+ presentation_effectTiming?: number;
+ presentation_effect?: string;
+ followLinkAnimEffect?: string;
+ }
+ >,
+ root: Doc
+ ) {
+ const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection;
+ const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null));
const effectProps = {
left: dir === PresEffectDirection.Left,
right: dir === PresEffectDirection.Right,
@@ -984,26 +998,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
bottom: dir === PresEffectDirection.Bottom,
opposite: true,
delay: 0,
- duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
+ duration,
};
const timing = StrCast(presEffectDoc?.presentation_effectTiming);
- let timingConfig: SpringSettings | undefined;
- if (timing) {
- timingConfig = JSON.parse(timing);
- }
-
- if (!timingConfig) {
- timingConfig = {
- type: SpringType.GENTLE,
- ...springMappings.gentle,
- };
- }
-
- if (!dir) {
- dir = PresEffectDirection.Center;
- }
-
+ const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? {
+ type: SpringType.GENTLE,
+ ...springMappings.gentle,
+ };
switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
case PresEffect.Expand: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Expand} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
case PresEffect.Flip: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Flip} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
@@ -1072,7 +1074,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
public static allViews: () => DocumentView[];
public static addView: (dv: DocumentView) => void | undefined;
public static removeView: (dv: DocumentView) => void | undefined;
- public static addViewRenderedCb: (doc: Opt<Doc>, func: (dv: DocumentView) => any) => boolean;
+ public static addViewRenderedCb: (doc: Opt<Doc>, func: (dv: DocumentView) => void) => boolean;
public static getViews = (doc?: Doc) => Array.from(doc?.[DocViews] ?? []) as DocumentView[];
public static getFirstDocumentView: (toFind: Doc) => DocumentView | undefined;
public static getDocumentView: (target: Doc | undefined, preferredCollection?: DocumentView) => Opt<DocumentView>;
@@ -1085,15 +1087,16 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => Promise<void>;
public static linkCommonAncestor: (link: Doc) => DocumentView | undefined;
- // pin func
+ /**
+ * Pins a Doc to the current presentation trail. (see TabDocView for implementation)
+ */
public static PinDoc: (docIn: Doc | Doc[], pinProps: PinProps) => void;
- // gesture
- public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to.
- // media playing
- @observable public static CurrentlyPlaying: DocumentView[] = [];
+ /**
+ * The DocumentView below the cursor at the start of a gesture (that receives the pointerDown event). Used by GestureOverlay to determine the doc a gesture should apply to.
+ */
+ public static DownDocView: DocumentView | undefined;
public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore
- public ContentRef = React.createRef<HTMLDivElement>();
private _htmlOverlayEffect: Opt<Doc>;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _viewTimer: NodeJS.Timeout | undefined;
@@ -1124,7 +1127,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
@observable private _htmlOverlayText: Opt<string> = undefined;
@observable private _isHovering = false;
@observable private _selected = false;
- @observable public static LongPress = false;
+ @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing
@computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.();
@@ -1245,7 +1248,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
public setToggleDetail = (scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(scriptFieldKey);
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 startDragging = (x: number, y: number, dropAction: dropActionType | undefined, 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());
@@ -1271,7 +1274,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
}
public playAnnotation = () => {
- const self = this;
const audioAnnoState = this.dataDoc.audioAnnoState ?? AudioAnnoState.stopped;
const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
const anno = audioAnnos?.lastElement();
@@ -1284,12 +1286,12 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
autoplay: true,
loop: false,
volume: 0.5,
- onend: action(() => { self.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore
+ onend: action(() => { this.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore
});
this.dataDoc.audioAnnoState = AudioAnnoState.playing;
break;
case AudioAnnoState.playing:
- this.dataDoc[AudioPlay]?.stop();
+ (this.dataDoc[AudioPlay] as Howl)?.stop();
this.dataDoc.audioAnnoState = AudioAnnoState.stopped;
break;
default:
@@ -1443,9 +1445,10 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
<div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this._enableHtmlOverlayTransitions ? 0.9 : 0 }}>
{DocumentViewInternal.AnimationEffect(
<div className="webBox-textHighlight">
+ {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
<ObserverJsxParser autoCloseVoidElements key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
</div>,
- { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand } as any as Doc,
+ { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand },
this.Document
)}
</div>
@@ -1471,15 +1474,14 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
{!this.Document || !this._props.PanelWidth() ? null : (
<div
className="contentFittingDocumentView-previewDoc"
- ref={this.ContentRef}
style={{
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`),
+ height: this._props.forceAutoHeight ? undefined : (yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`)),
}}>
<DocumentViewInternal
{...this._props}
- parent={undefined}
+ reactParent={undefined}
isHovering={this.isHovering}
fieldKey={this.LayoutFieldKey}
DataTransition={this.DataTransition}
@@ -1568,6 +1570,56 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
}
}
+export function ActiveFillColor(): string {
+ const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined;
+ return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, ""));
+} // prettier-ignore
+export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore
+export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore
+export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore
+export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore
+export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore
+export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore
+export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore
+export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore
+export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore
+export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore
+export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth); } // prettier-ignore
+
+export function SetActiveInkWidth(width: string): void {
+ !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
+}
+export function SetActiveBezierApprox(bezier: string): void {
+ ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
+}
+export function SetActiveInkColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
+}
+export function SetActiveIsInkMask(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
+}
+export function SetActiveInkHideTextLabels(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
+}
+export function SetActiveFillColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
+}
+export function SetActiveArrowStart(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
+}
+export function SetActiveArrowEnd(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
+}
+export function SetActiveArrowScale(value: number) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
+}
+export function SetActiveDash(dash: string): void {
+ !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
+}
+export function SetEraserWidth(width: number): void {
+ ActiveInkPen() && (ActiveInkPen().eraserWidth = width);
+}
+
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function DocFocusOrOpen(docIn: Doc, optionsIn?: FocusViewOptions, containingDoc?: Doc) {
return DocumentView.FocusOrOpen(docIn, optionsIn, containingDoc);