aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-07-08 00:17:26 -0400
committerbobzel <zzzman@gmail.com>2022-07-08 00:17:26 -0400
commit146f8622d5bac2edc6b09f57c173bd057dfbcfad (patch)
treef871089c438a476543ca96bac163c0532b9557c7 /src/client/views/nodes/DocumentView.tsx
parentb7e66da6b23cdb41c127000dfe13843d35f7d0cc (diff)
restructured currentUserUtils to avoid having import cycles.
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx1460
1 files changed, 863 insertions, 597 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7569b209d..f89c65052 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,56 +1,57 @@
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, StrListCast, WidthSym } from "../../../fields/Doc";
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
-import { List } from "../../../fields/List";
-import { ObjectField } from "../../../fields/ObjectField";
-import { listSpec } from "../../../fields/Schema";
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
-import { AudioField } from "../../../fields/URLField";
+import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { AudioField } from '../../../fields/URLField';
import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
-import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnTrue, returnFalse, returnVal, simulateMouseClick, Utils } from "../../../Utils";
+import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
-import { Docs, DocUtils } from "../../documents/Documents";
-import { DocumentType } from '../../documents/DocumentTypes';
-import { Networking } from "../../Network";
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager, dropActionType } from "../../util/DragManager";
+import { DocServer } from '../../DocServer';
+import { Docs, DocUtils } from '../../documents/Documents';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { Networking } from '../../Network';
+import { DocumentManager } from '../../util/DocumentManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
import { InteractionUtils } from '../../util/InteractionUtils';
+import { LinkFollower } from '../../util/LinkFollower';
import { LinkManager } from '../../util/LinkManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
-import { SelectionManager } from "../../util/SelectionManager";
+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 { undoBatch, UndoManager } from "../../util/UndoManager";
-import { CollectionView, CollectionViewType } from '../collections/CollectionView';
-import { ContextMenu } from "../ContextMenu";
+import { Transform } from '../../util/Transform';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { CollectionView } from '../collections/CollectionView';
+import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocComponent } from "../DocComponent";
+import { DocComponent } from '../DocComponent';
import { EditableView } from '../EditableView';
-import { InkingStroke } from "../InkingStroke";
-import { LightboxView } from "../LightboxView";
-import { StyleProp } from "../StyleProvider";
-import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
-import { DocumentContentsView } from "./DocumentContentsView";
+import { InkingStroke } from '../InkingStroke';
+import { LightboxView } from '../LightboxView';
+import { StyleProp } from '../StyleProvider';
+import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
+import { DocumentContentsView } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
-import "./DocumentView.scss";
-import { FormattedTextBox } from "./formattedText/FormattedTextBox";
+import './DocumentView.scss';
+import { FieldViewProps } from './FieldView';
+import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { LinkAnchorBox } from './LinkAnchorBox';
-import { LinkDocPreview } from "./LinkDocPreview";
+import { LinkDocPreview } from './LinkDocPreview';
import { RadialMenu } from './RadialMenu';
-import { ScriptingBox } from "./ScriptingBox";
+import { ScriptingBox } from './ScriptingBox';
import { PresBox } from './trails/PresBox';
-import React = require("react");
-import { DocServer } from "../../DocServer";
-import { FieldViewProps } from "./FieldView";
+import React = require('react');
const { Howl } = require('howler');
interface Window {
@@ -64,16 +65,16 @@ declare class MediaRecorder {
export enum ViewAdjustment {
resetView = 1,
- doNothing = 0
+ doNothing = 0,
}
-export const ViewSpecPrefix = "viewSpec"; // field prefix for anchor fields that are immediately copied over to the target document when link is followed. Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document)
+export const ViewSpecPrefix = 'viewSpec'; // field prefix for anchor fields that are immediately copied over to the target document when link is followed. Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document)
export interface DocFocusOptions {
originalTarget?: Doc; // set in JumpToDocument, used by TabDocView to determine whether to fit contents to tab
- willZoom?: boolean; // determines whether to zoom in on target document
- scale?: number; // percent of containing frame to zoom into document
- afterFocus?: DocAfterFocusFunc; // function to call after focusing on a document
+ willZoom?: boolean; // determines whether to zoom in on target document
+ scale?: number; // percent of containing frame to zoom into document
+ afterFocus?: DocAfterFocusFunc; // function to call after focusing on a document
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)
}
@@ -84,9 +85,9 @@ export interface DocComponentView {
updateIcon?: () => void; // updates the icon representation of the document
getAnchor?: () => 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)
scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus
- setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
+ setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
reverseNativeScaling?: () => 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.
- shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views
+ shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views
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
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)
@@ -99,20 +100,20 @@ export interface DocComponentView {
annotationKey?: string;
getTitle?: () => string;
getScrollHeight?: () => number;
- getCenter?: (xf: Transform) => { 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 };
+ getCenter?: (xf: Transform) => { 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
+// 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;
- contentBounds?: () => (undefined|{x:number, y:number, r:number, b:number});
+ contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document
ContainingCollectionView: Opt<CollectionView>;
ContainingCollectionDoc: Opt<Doc>;
@@ -137,7 +138,7 @@ export interface DocumentViewSharedProps {
whenChildContentsActiveChanged: (isActive: boolean) => void;
rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
addDocTab: (doc: Doc, where: string) => 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)
+ 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[]) => boolean;
removeDocument?: (doc: Doc | Doc[]) => boolean;
moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
@@ -161,8 +162,8 @@ export interface DocumentViewSharedProps {
export interface DocumentViewProps extends DocumentViewSharedProps {
// properties specific to DocumentViews but not to FieldView
hideResizeHandles?: boolean; // whether to suppress DocumentDecorations 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
- hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
+ hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
+ hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
hideDocumentButtonBar?: boolean;
hideOpenButton?: boolean;
hideDeleteButton?: boolean;
@@ -172,19 +173,19 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
contentPointerEvents?: string; // 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";
+ dontCenter?: 'x' | 'y' | 'xy';
dontScaleFilter?: (doc: Doc) => boolean; // decides whether a document can be scaled to fit its container vs native size with scrolling
ContentScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal
NativeWidth?: () => number;
NativeHeight?: () => number;
LayoutTemplate?: () => Opt<Doc>;
- contextMenuItems?: () => { script: ScriptField, filter?: ScriptField, label: string, icon: string }[];
+ 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);
+ onBrowseClick?: () => ScriptField | undefined;
+ onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
}
// these props are only available in DocumentViewIntenral
@@ -219,34 +220,88 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
@observable _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
- private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; }
- public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
- public get ContentDiv() { return this._mainCont.current; }
- public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); }
- @computed get ShowTitle() { return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.ShowTitle) as (Opt<string>); }
- @computed get ContentScale() { return this.props.ContentScaling?.() || 1; }
- @computed get thumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url.href.replace(".png", "_m.png"); }
- @computed get hidden() { return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Hidden); }
- @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 hideLinkButton() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.props.isSelected() ? ":selected" : "")); }
- @computed get widgetDecorations() { return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Decorations + (this.props.isSelected() ? ":selected" : "")); }
- @computed get backgroundColor() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); }
- @computed get docContents() { return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.DocContents); }
- @computed get headerMargin() { return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
- @computed get titleHeight() { return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0; }
- @computed get pointerEvents() { return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ":selected" : "")); }
- @computed get finalLayoutKey() { return StrCast(this.Document.layoutKey, "layout"); }
- @computed get nativeWidth() { return this.props.NativeWidth(); }
- @computed get nativeHeight() { return this.props.NativeHeight(); }
- @computed get onClickHandler() { return this.props.onClick?.() ?? (this.props.onBrowseClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null))); }
- @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); }
- @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
- @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
-
- componentWillUnmount() { this.cleanupHandlers(true); }
- componentDidMount() { this.setupHandlers(); }
+ private get topMost() {
+ return this.props.renderDepth === 0 && !LightboxView.LightboxDoc;
+ }
+ public get displayName() {
+ return 'DocumentView(' + this.props.Document.title + ')';
+ } // this makes mobx trace() statements more descriptive
+ public get ContentDiv() {
+ return this._mainCont.current;
+ }
+ public get LayoutFieldKey() {
+ return Doc.LayoutFieldKey(this.layoutDoc);
+ }
+ @computed get ShowTitle() {
+ return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.ShowTitle) as Opt<string>;
+ }
+ @computed get ContentScale() {
+ return this.props.ContentScaling?.() || 1;
+ }
+ @computed get thumb() {
+ return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url.href.replace('.png', '_m.png');
+ }
+ @computed get hidden() {
+ return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Hidden);
+ }
+ @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 hideLinkButton() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.props.isSelected() ? ':selected' : ''));
+ }
+ @computed get widgetDecorations() {
+ return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Decorations + (this.props.isSelected() ? ':selected' : ''));
+ }
+ @computed get backgroundColor() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor);
+ }
+ @computed get docContents() {
+ return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.DocContents);
+ }
+ @computed get headerMargin() {
+ return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0;
+ }
+ @computed get titleHeight() {
+ return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
+ }
+ @computed get pointerEvents() {
+ return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
+ }
+ @computed get finalLayoutKey() {
+ return StrCast(this.Document.layoutKey, 'layout');
+ }
+ @computed get nativeWidth() {
+ return this.props.NativeWidth();
+ }
+ @computed get nativeHeight() {
+ return this.props.NativeHeight();
+ }
+ @computed get onClickHandler() {
+ return this.props.onClick?.() ?? this.props.onBrowseClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null));
+ }
+ @computed get onDoubleClickHandler() {
+ return this.props.onDoubleClick?.() ?? Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick;
+ }
+ @computed get onPointerDownHandler() {
+ return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown);
+ }
+ @computed get onPointerUpHandler() {
+ return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp);
+ }
+
+ componentWillUnmount() {
+ this.cleanupHandlers(true);
+ }
+ componentDidMount() {
+ this.setupHandlers();
+ }
//componentDidUpdate() { this.setupHandlers(); }
setupHandlers() {
this.cleanupHandlers(false);
@@ -268,8 +323,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
this.removeMoveListeners();
this.removeEndListeners();
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
+ document.removeEventListener('pointermove', this.onPointerMove);
+ document.removeEventListener('pointerup', this.onPointerUp);
if (RadialMenu.Instance._display === false) {
this.addHoldMoveListeners();
this.addHoldEndListeners();
@@ -278,7 +333,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._firstX = pt.pageX;
this._firstY = pt.pageY;
}
- }
+ };
handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
@@ -289,7 +344,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) {
this.handle1PointerHoldEnd(e, me);
}
- }
+ };
handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
this.removeHoldMoveListeners();
@@ -304,7 +359,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (RadialMenu.Instance.used) {
this.onContextMenu(undefined, me.touches[0].pageX, me.touches[0].pageY);
}
- }
+ };
handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
if (!e.nativeEvent.cancelBubble && !this.props.isSelected()) {
@@ -316,7 +371,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this.removeEndListeners();
this.addEndListeners();
}
- }
+ };
handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
SelectionManager.DeselectAll();
@@ -326,7 +381,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._downX = touch.clientX;
this._downY = touch.clientY;
if (!e.nativeEvent.cancelBubble) {
- if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) e.stopPropagation();
+ if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) e.stopPropagation();
this.removeMoveListeners();
this.addMoveListeners();
this.removeEndListeners();
@@ -334,24 +389,23 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
e.stopPropagation();
}
}
- }
+ };
handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
if (e.cancelBubble && this.props.isDocumentActive?.()) {
this.removeMoveListeners();
- }
- else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) {
+ } else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
const touch = me.touchEvent.changedTouches.item(0);
if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) {
this.cleanUpInteractions();
- this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
+ this.startDragging(this._downX, this._downY, this.Document.dropAction ? (this.Document.dropAction as any) : e.ctrlKey || e.altKey ? 'alias' : undefined);
}
}
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
e.preventDefault();
}
- }
+ };
@action
handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
@@ -362,8 +416,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const oldPoint2 = this.prevPoints.get(pt2.identifier);
const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
if (pinching !== 0 && oldPoint1 && oldPoint2) {
- const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX));
- const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY));
+ const dW = Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX);
+ const dH = Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY);
const dX = -1 * Math.sign(dW);
const dY = -1 * Math.sign(dH);
@@ -372,33 +426,32 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const layoutDoc = Document(Doc.Layout(this.props.Document));
let nwidth = Doc.NativeWidth(layoutDoc);
let nheight = Doc.NativeHeight(layoutDoc);
- const width = (layoutDoc._width || 0);
- const height = (layoutDoc._height || (nheight / nwidth * width));
+ const width = layoutDoc._width || 0;
+ const height = layoutDoc._height || (nheight / nwidth) * width;
const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale;
- const actualdW = Math.max(width + (dW * scale), 20);
- const actualdH = Math.max(height + (dH * scale), 20);
+ const actualdW = Math.max(width + dW * scale, 20);
+ const actualdH = Math.max(height + dH * scale, 20);
doc.x = (doc.x || 0) + dX * (actualdW - width);
doc.y = (doc.y || 0) + dY * (actualdH - height);
const fixedAspect = e.ctrlKey || (nwidth && nheight);
if (fixedAspect && (!nwidth || !nheight)) {
- Doc.SetNativeWidth(layoutDoc, nwidth = layoutDoc._width || 0);
- Doc.SetNativeHeight(layoutDoc, nheight = layoutDoc._height || 0);
+ Doc.SetNativeWidth(layoutDoc, (nwidth = layoutDoc._width || 0));
+ Doc.SetNativeHeight(layoutDoc, (nheight = layoutDoc._height || 0));
}
if (nwidth > 0 && nheight > 0) {
if (Math.abs(dW) > Math.abs(dH)) {
if (!fixedAspect) {
- Doc.SetNativeWidth(layoutDoc, actualdW / (layoutDoc._width || 1) * Doc.NativeWidth(layoutDoc));
+ Doc.SetNativeWidth(layoutDoc, (actualdW / (layoutDoc._width || 1)) * Doc.NativeWidth(layoutDoc));
}
layoutDoc._width = actualdW;
- if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width;
+ if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._height = (nheight / nwidth) * layoutDoc._width;
else layoutDoc._height = actualdH;
- }
- else {
+ } else {
if (!fixedAspect) {
- Doc.SetNativeHeight(layoutDoc, actualdH / (layoutDoc._height || 1) * Doc.NativeHeight(doc));
+ Doc.SetNativeHeight(layoutDoc, (actualdH / (layoutDoc._height || 1)) * Doc.NativeHeight(doc));
}
layoutDoc._height = actualdH;
- if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height;
+ if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._width = (nwidth / nheight) * layoutDoc._height;
else layoutDoc._width = actualdW;
}
} else {
@@ -410,7 +463,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
e.stopPropagation();
e.preventDefault();
}
- }
+ };
@action
onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
@@ -419,19 +472,30 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
// RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "map-pin", selected: -1 });
const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
- (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && RadialMenu.Instance.addItem({ description: "Delete", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "external-link-square-alt", selected: -1 });
+ (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) &&
+ RadialMenu.Instance.addItem({
+ description: 'Delete',
+ event: () => {
+ this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu();
+ },
+ icon: 'external-link-square-alt',
+ selected: -1,
+ });
// RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 });
- RadialMenu.Instance.addItem({ description: "Pin", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
- RadialMenu.Instance.addItem({ description: "Open", event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: "trash", selected: -1 });
+ RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document), icon: 'map-pin', selected: -1 });
+ RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 });
SelectionManager.DeselectAll();
- }
+ };
startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
if (this._mainCont.current) {
const dragData = new DragManager.DocumentDragData([this.props.Document]);
const [left, top] = this.props.ScreenToLocalTransform().scale(this.ContentScale).inverse().transformPoint(0, 0);
- dragData.offset = this.props.ScreenToLocalTransform().scale(this.ContentScale).transformDirection(x - left, y - top);
+ dragData.offset = this.props
+ .ScreenToLocalTransform()
+ .scale(this.ContentScale)
+ .transformDirection(x - left, y - top);
dragData.offset[0] = Math.min(this.rootDoc[WidthSym](), dragData.offset[0]);
dragData.offset[1] = Math.min(this.rootDoc[HeightSym](), dragData.offset[1]);
dragData.dropAction = dropAction;
@@ -440,8 +504,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
dragData.moveDocument = this.props.moveDocument;
const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
- DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart) },
- () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))); // this needs to happen after the drop event is processed.
+ DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart) }, () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))); // this needs to happen after the drop event is processed.
ffview?.setupDragLines(false);
}
}
@@ -450,91 +513,114 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e.altKey && !e.nativeEvent.cancelBubble) {
e.stopPropagation();
e.preventDefault();
- if (e.key === "†" || e.key === "t") {
- if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = "title";
+ if (e.key === '†' || e.key === 't') {
+ if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = 'title';
if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0);
- else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text...
+ else if (!this._titleRef.current.setIsFocused(true)) {
+ // if focus didn't change, focus on interior text...
this._titleRef.current?.setIsFocused(false);
this._componentView?.setFocus?.();
}
}
}
- }
+ };
focus = (anchor: Doc, options?: DocFocusOptions) => {
- LightboxView.SetCookie(StrCast(anchor["cookies-set"]));
+ LightboxView.SetCookie(StrCast(anchor['cookies-set']));
// copying over VIEW fields immediately allows the view type to switch to create the right _componentView
- Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => {
- this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec]);
- });
+ Array.from(Object.keys(Doc.GetProto(anchor)))
+ .filter(key => key.startsWith(ViewSpecPrefix))
+ .forEach(spec => {
+ this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec]);
+ });
// after a timeout, the right _componentView should have been created, so call it to update its view spec values
setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false));
const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant === false || !LinkDocPreview.LinkInfo); // bcz: smooth parameter should really be passed into focus() instead of inferred here
- const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => (options?.afterFocus?.(true) ?? ViewAdjustment.doNothing);
+ const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing;
this.props.focus(options?.docTransform ? anchor : this.rootDoc, {
- ...options, afterFocus: (didFocus: boolean) =>
- new Promise<ViewAdjustment>(res => setTimeout(async () => res(endFocus ?
- await endFocus(didFocus||focusSpeed !== undefined) :
- ViewAdjustment.doNothing), focusSpeed ?? 0)
- )
+ ...options,
+ afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(endFocus ? await endFocus(didFocus || focusSpeed !== undefined) : ViewAdjustment.doNothing), focusSpeed ?? 0)),
});
-
- }
+ };
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
- if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && this.props.renderDepth >= 0 &&
- (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
+ if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && this.props.renderDepth >= 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
let stopPropagate = true;
let preventDefault = true;
const isScriptBox = () => StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name);
(this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
- if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
+ if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {
+ // && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
if (this._timeout) {
clearTimeout(this._timeout);
this._pendingDoubleClick = false;
this._timeout = undefined;
}
- if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
+ if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) {
+ // bcz: hack? don't execute script if you're clicking on a scripting box itself
const { clientX, clientY, shiftKey } = e;
- const func = () => this.onDoubleClickHandler.script.run({
- this: this.layoutDoc,
- self: this.rootDoc,
- scriptContext: this.props.scriptContext,
- thisContainer: this.props.ContainingCollectionDoc,
- documentView: this.props.DocumentView(),
- clientX, clientY, shiftKey
- }, console.log);
- UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click");
+ const func = () =>
+ this.onDoubleClickHandler.script.run(
+ {
+ this: this.layoutDoc,
+ self: this.rootDoc,
+ scriptContext: this.props.scriptContext,
+ thisContainer: this.props.ContainingCollectionDoc,
+ documentView: this.props.DocumentView(),
+ clientX,
+ clientY,
+ shiftKey,
+ },
+ console.log
+ );
+ UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click');
} else if (!Doc.IsSystem(this.rootDoc)) {
- UndoManager.RunInBatch(() =>
- LightboxView.AddDocTab(this.rootDoc, "lightbox", this.props.LayoutTemplate?.(), this.props.addDocTab)
- , "double tap");
+ UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, 'lightbox', this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap');
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
}
- } else if (this.onClickHandler?.script && !isScriptBox()) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
+ } else if (this.onClickHandler?.script && !isScriptBox()) {
+ // bcz: hack? don't execute script if you're clicking on a scripting box itself
const { clientX, clientY, shiftKey } = e;
- const func = () => this.onClickHandler.script.run({
- this: this.layoutDoc,
- self: this.rootDoc,
- _readOnly_: false,
- scriptContext: this.props.scriptContext,
- thisContainer: this.props.ContainingCollectionDoc,
- documentView: this.props.DocumentView(),
- clientX, clientY, shiftKey
- }, console.log).result?.select === true ? this.props.select(false) : "";
- const clickFunc = () => this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, "on click");
+ const func = () =>
+ this.onClickHandler.script.run(
+ {
+ this: this.layoutDoc,
+ self: this.rootDoc,
+ _readOnly_: false,
+ scriptContext: this.props.scriptContext,
+ thisContainer: this.props.ContainingCollectionDoc,
+ documentView: this.props.DocumentView(),
+ clientX,
+ clientY,
+ shiftKey,
+ },
+ console.log
+ ).result?.select === true
+ ? this.props.select(false)
+ : '';
+ const clickFunc = () => (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'on click'));
if (this.onDoubleClickHandler) {
- runInAction(() => this._pendingDoubleClick = true);
- this._timeout = setTimeout(() => { this._timeout = undefined; clickFunc(); }, 350);
+ runInAction(() => (this._pendingDoubleClick = true));
+ this._timeout = setTimeout(() => {
+ this._timeout = undefined;
+ clickFunc();
+ }, 350);
} else clickFunc();
} else if (this.allLinks && this.Document.type !== DocumentType.LINK && !isScriptBox() && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
- this.allLinks.length && LinkManager.FollowLink(undefined, this.props.Document, this.props, e.altKey);
+ this.allLinks.length && LinkFollower.FollowLink(undefined, this.props.Document, this.props, e.altKey);
} else {
- if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField 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)) {
+ // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
} else {
- runInAction(() => this._pendingDoubleClick = true);
- this._timeout = setTimeout(action(() => { this._pendingDoubleClick = false; this._timeout = undefined; }), 350);
+ runInAction(() => (this._pendingDoubleClick = true));
+ this._timeout = setTimeout(
+ action(() => {
+ this._pendingDoubleClick = false;
+ this._timeout = undefined;
+ }),
+ 350
+ );
this.props.select(e.ctrlKey || e.shiftKey);
}
preventDefault = false;
@@ -545,9 +631,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
});
onPointerDown = (e: React.PointerEvent): void => {
- if (this.rootDoc.type === DocumentType.INK && CurrentUserUtils.ActiveTool === InkTool.Eraser) return;
+ if (this.rootDoc.type === DocumentType.INK && Doc.ActiveTool === InkTool.Eraser) return;
// continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document)
- if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) {
+ if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool))) {
if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
e.stopPropagation();
if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it
@@ -557,50 +643,54 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
this._downX = e.clientX;
this._downY = e.clientY;
- if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) &&
+ if (
+ (!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) &&
// if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
- !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
- if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) &&
+ !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))
+ ) {
+ if (
+ (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) &&
!this.props.onBrowseClick?.() &&
!this.Document.ignoreClick &&
!e.ctrlKey &&
(e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
- !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) {
+ !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)
+ ) {
e.stopPropagation();
// don't preventDefault anymore. Goldenlayout, PDF text selection and RTF text selection all need it to go though
//if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._viewType !== CollectionViewType.Docking) e.preventDefault();
}
if (this.props.isDocumentActive?.()) {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener('pointermove', this.onPointerMove);
+ document.addEventListener('pointermove', this.onPointerMove);
}
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
+ document.removeEventListener('pointerup', this.onPointerUp);
+ document.addEventListener('pointerup', this.onPointerUp);
}
- }
+ };
onPointerMove = (e: PointerEvent): void => {
if (e.cancelBubble) return;
- if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) return;
+ if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return;
- if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) {
+ if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && "alias") || (this.props.dropAction || this.Document.dropAction || undefined) as dropActionType);
+ document.removeEventListener('pointermove', this.onPointerMove);
+ document.removeEventListener('pointerup', this.onPointerUp);
+ this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'alias') || ((this.props.dropAction || this.Document.dropAction || undefined) as dropActionType));
}
}
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
e.preventDefault();
}
- }
+ };
cleanupPointerEvents = () => {
this.cleanUpInteractions();
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
+ document.removeEventListener('pointermove', this.onPointerMove);
+ document.removeEventListener('pointerup', this.onPointerUp);
+ };
onPointerUp = (e: PointerEvent): void => {
this.cleanupPointerEvents();
@@ -608,13 +698,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
} else {
- this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
+ this._doubleTap = Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2;
// bcz: this is a placeholder. documents, when selected, should stopPropagation on doubleClicks if they want to keep the DocumentView from getting them
- if (!this.props.isSelected(true) || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this.rootDoc.type) as any)) this._lastTap = Date.now();// don't want to process the start of a double tap if the doucment is selected
+ if (!this.props.isSelected(true) || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this.rootDoc.type) as any)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
}
- }
+ };
- @undoBatch @action
+ @undoBatch
+ @action
toggleFollowLink = (location: Opt<string>, zoom?: boolean, setPushpin?: boolean): void => {
this.Document.ignoreClick = false;
if (setPushpin) {
@@ -628,46 +719,48 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this.Document.followLinkLocation = location;
} else if (this.Document._isLinkButton && this.onClickHandler) {
this.Document._isLinkButton = false;
- this.Document["onClick-rawScript"] = this.dataDoc["onClick-rawScript"] = this.dataDoc.onClick = this.Document.onClick = this.layoutDoc.onClick = undefined;
+ this.Document['onClick-rawScript'] = this.dataDoc['onClick-rawScript'] = this.dataDoc.onClick = this.Document.onClick = this.layoutDoc.onClick = undefined;
}
- }
- @undoBatch @action
+ };
+ @undoBatch
+ @action
toggleTargetOnClick = (): void => {
this.Document.ignoreClick = false;
this.Document._isLinkButton = true;
this.Document.isPushpin = true;
- }
- @undoBatch @action
- followLinkOnClick = (location: Opt<string>, zoom: boolean,): void => {
+ };
+ @undoBatch
+ @action
+ followLinkOnClick = (location: Opt<string>, zoom: boolean): void => {
this.Document.ignoreClick = false;
this.Document._isLinkButton = true;
this.Document.isPushpin = false;
this.Document.followLinkZoom = zoom;
this.Document.followLinkLocation = location;
- }
- @undoBatch @action
+ };
+ @undoBatch
+ @action
selectOnClick = (): void => {
this.Document.ignoreClick = false;
this.Document._isLinkButton = false;
this.Document.isPushpin = false;
this.Document.onClick = this.layoutDoc.onClick = undefined;
- }
+ };
@undoBatch
noOnClick = (): void => {
this.Document.ignoreClick = false;
this.Document._isLinkButton = false;
- }
+ };
@undoBatch deleteClicked = () => this.props.removeDocument?.(this.props.Document);
- @undoBatch setToggleDetail = () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(documentView, "${StrCast(this.Document.layoutKey).replace("layout_", "")}")`, { documentView: "any" });
+ @undoBatch setToggleDetail = () => (this.Document.onClick = ScriptField.MakeScript(`toggleDetail(documentView, "${StrCast(this.Document.layoutKey).replace('layout_', '')}")`, { documentView: 'any' }));
- @undoBatch @action
+ @undoBatch
+ @action
drop = async (e: Event, de: DragManager.DropEvent) => {
if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return;
- if (this.props.Document === CurrentUserUtils.ActiveDashboard) {
- alert((e.target as any)?.closest?.("*.lm_content") ?
- "You can't perform this move most likely because you don't have permission to modify the destination." :
- "Linking to document tabs not yet supported. Drop link on document content.");
+ if (this.props.Document === Doc.ActiveDashboard) {
+ alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
return;
}
const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
@@ -682,20 +775,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y - 50]);
}
}
- }
+ };
@undoBatch
@action
makeIntoPortal = async () => {
const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);
if (!portalLink) {
- const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _fitWidth: true, title: StrCast(this.props.Document.title) + " [Portal]" });
- DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to:portal from");
+ const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' });
+ DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, 'portal to:portal from');
}
- this.Document.followLinkLocation = "inPlace";
+ this.Document.followLinkLocation = 'inPlace';
this.Document.followLinkZoom = true;
this.Document._isLinkButton = true;
- }
+ };
@action
onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
@@ -707,7 +800,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
if (e) {
- if (e.button === 0 && !e.ctrlKey || e.isDefaultPrevented()) {
+ if ((e.button === 0 && !e.ctrlKey) || e.isDefaultPrevented()) {
e.preventDefault();
return;
}
@@ -715,7 +808,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
e.stopPropagation();
e.persist();
- if (!navigator.userAgent.includes("Mozilla") && (Math.abs(this._downX - e?.clientX) > 3 || Math.abs(this._downY - e?.clientY) > 3)) {
+ if (!navigator.userAgent.includes('Mozilla') && (Math.abs(this._downX - e?.clientX) > 3 || Math.abs(this._downY - e?.clientY) > 3)) {
return;
}
}
@@ -724,17 +817,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (!cm || (e as any)?.nativeEvent?.SchemaHandled) return;
if (e && !(e.nativeEvent as any).dash) {
- const onDisplay = () => setTimeout(() => {
- DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected(true) && 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.
+ const onDisplay = () =>
setTimeout(() => {
- const ele = document.elementFromPoint(e.clientX, e.clientY);
- simulateMouseClick(ele, e.clientX, e.clientY, e.screenX, e.screenY);
+ DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected(true) && 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.
+ setTimeout(() => {
+ const ele = document.elementFromPoint(e.clientX, e.clientY);
+ simulateMouseClick(ele, e.clientX, e.clientY, e.screenX, e.screenY);
+ });
});
- });
- if (navigator.userAgent.includes("Macintosh")) {
+ if (navigator.userAgent.includes('Macintosh')) {
cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15, undefined, undefined, onDisplay);
- }
- else {
+ } else {
onDisplay();
}
return;
@@ -742,232 +835,291 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []);
StrListCast(this.Document.contextMenuLabels).forEach((label, i) =>
- cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: "sticky-note" }));
- this.props.contextMenuItems?.().forEach(item =>
- item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp }));
+ cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: 'sticky-note' })
+ );
+ this.props
+ .contextMenuItems?.()
+ .forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp }));
if (!this.props.Document.isFolder) {
const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
- const appearance = cm.findByDescription("UI Controls...");
- const appearanceItems: ContextMenuProps[] = appearance && "subitems" in appearance ? appearance.subitems : [];
- !Doc.noviceMode && templateDoc && appearanceItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" });
- !Doc.noviceMode && appearanceItems.push({
- description: "Add a Field", event: () => {
- const alias = Doc.MakeAlias(this.rootDoc);
- alias.layout = FormattedTextBox.LayoutString("newfield");
- alias.title = "newfield";
- alias._height = 35;
- alias._width = 100;
- alias.syncLayoutFieldWithTitle = true;
- alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width);
- alias.y = NumCast(this.rootDoc.y);
- this.props.addDocument?.(alias);
- }, icon: "eye"
- });
- DocListCast(this.Document.links).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? "Show" : "Hide"} Link Button`, event: action(() => this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton), icon: "eye" });
- !appearance && cm.addItem({ description: "UI Controls...", subitems: appearanceItems, icon: "compass" });
+ const appearance = cm.findByDescription('UI Controls...');
+ const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
+ !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, 'add:right'), icon: 'eye' });
+ !Doc.noviceMode &&
+ appearanceItems.push({
+ description: 'Add a Field',
+ event: () => {
+ const alias = Doc.MakeAlias(this.rootDoc);
+ alias.layout = FormattedTextBox.LayoutString('newfield');
+ alias.title = 'newfield';
+ alias._height = 35;
+ alias._width = 100;
+ alias.syncLayoutFieldWithTitle = true;
+ alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width);
+ alias.y = NumCast(this.rootDoc.y);
+ this.props.addDocument?.(alias);
+ },
+ icon: 'eye',
+ });
+ DocListCast(this.Document.links).length &&
+ appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' });
+ !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
- !Doc.noviceMode && appearanceItems.splice(0, 0, { description: `${!this.layoutDoc._showAudio ? "Show" : "Hide"} Audio Button`, event: action(() => this.layoutDoc._showAudio = !this.layoutDoc._showAudio), icon: "microphone" });
- const existingOnClick = cm.findByDescription("OnClick...");
- const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
+ !Doc.noviceMode && appearanceItems.splice(0, 0, { description: `${!this.layoutDoc._showAudio ? 'Show' : 'Hide'} Audio Button`, event: action(() => (this.layoutDoc._showAudio = !this.layoutDoc._showAudio)), icon: 'microphone' });
+ const existingOnClick = cm.findByDescription('OnClick...');
+ const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
- const zorders = cm.findByDescription("ZOrder...");
- const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : [];
+ const zorders = cm.findByDescription('ZOrder...');
+ const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
if (this.props.bringToFront !== emptyFunction) {
- zorderItems.push({ description: "Bring to Front", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" });
- zorderItems.push({ description: "Send to Back", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" });
- zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: undoBatch(action(() => this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined)), icon: "expand-arrows-alt" });
+ zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'expand-arrows-alt' });
+ zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'expand-arrows-alt' });
+ zorderItems.push({
+ description: this.rootDoc._raiseWhenDragged !== false ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged',
+ event: undoBatch(action(() => (this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined))),
+ icon: 'expand-arrows-alt',
+ });
}
- !zorders && cm.addItem({ description: "ZOrder...", noexpand: true, subitems: zorderItems, icon: "compass" });
+ !zorders && cm.addItem({ description: 'ZOrder...', noexpand: true, subitems: zorderItems, icon: 'compass' });
- !Doc.noviceMode && onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
- !Doc.noviceMode && onClicks.push({ description: "Toggle Detail", event: this.setToggleDetail, icon: "concierge-bell" });
- this.props.CollectionFreeFormDocumentView && onClicks.push({ description: (this.Document.followLinkZoom ? "Don't" : "") + " zoom following link", event: () => this.Document.followLinkZoom = !this.Document.followLinkZoom, icon: this.Document.ignoreClick ? "unlock" : "lock" });
+ !Doc.noviceMode && onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' });
+ !Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
+ this.props.CollectionFreeFormDocumentView &&
+ onClicks.push({
+ description: (this.Document.followLinkZoom ? "Don't" : '') + ' zoom following link',
+ event: () => (this.Document.followLinkZoom = !this.Document.followLinkZoom),
+ icon: this.Document.ignoreClick ? 'unlock' : 'lock',
+ });
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.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
- onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "link" });
- !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("add:right", false, false), icon: "link" });
- onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "link" });
- onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "map-pin" });
- 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...", addDivider: true, noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
+ 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.Document.ignoreClick ? 'Select' : 'Do Nothing', event: () => (this.Document.ignoreClick = !this.Document.ignoreClick), icon: this.Document.ignoreClick ? 'unlock' : 'lock' });
+ onClicks.push({ description: this.Document.isLinkButton ? 'Remove Follow Behavior' : 'Follow Link in Place', event: () => this.toggleFollowLink('inPlace', true, false), icon: 'link' });
+ !this.Document.isLinkButton && onClicks.push({ description: 'Follow Link on Right', event: () => this.toggleFollowLink('add:right', false, false), icon: 'link' });
+ onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(undefined, false, false), icon: 'link' });
+ onClicks.push({ description: (this.Document.isPushpin ? 'Remove' : 'Make') + ' Pushpin', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' });
+ 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...', addDivider: true, noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
} else if (DocListCast(this.Document.links).length) {
- onClicks.push({ description: "Select on Click", event: () => this.selectOnClick(), icon: "link" });
- onClicks.push({ description: "Follow Link on Click", event: () => this.followLinkOnClick(undefined, false), icon: "link" });
- onClicks.push({ description: "Toggle Link Target on Click", event: () => this.toggleTargetOnClick(), icon: "map-pin" });
- !existingOnClick && cm.addItem({ description: "OnClick...", addDivider: true, subitems: onClicks, icon: "mouse-pointer" });
+ onClicks.push({ description: 'Select on Click', event: () => this.selectOnClick(), icon: 'link' });
+ onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(undefined, false), icon: 'link' });
+ onClicks.push({ description: 'Toggle Link Target on Click', event: () => this.toggleTargetOnClick(), icon: 'map-pin' });
+ !existingOnClick && cm.addItem({ description: 'OnClick...', addDivider: true, subitems: onClicks, icon: 'mouse-pointer' });
}
}
const funcs: ContextMenuProps[] = [];
if (!Doc.noviceMode && this.layoutDoc.onDragStart) {
- funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
- funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
- funcs.push({ description: "Drag Document", icon: "edit", event: () => this.layoutDoc.onDragStart = undefined });
- cm.addItem({ description: "OnDrag...", noexpand: true, subitems: funcs, icon: "asterisk" });
+ funcs.push({ description: 'Drag an Alias', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
+ funcs.push({ description: 'Drag a Copy', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
+ funcs.push({ description: 'Drag Document', icon: 'edit', event: () => (this.layoutDoc.onDragStart = undefined) });
+ cm.addItem({ description: 'OnDrag...', noexpand: true, subitems: funcs, icon: 'asterisk' });
}
- const more = cm.findByDescription("More...");
- const moreItems = more && "subitems" in more ? more.subitems : [];
+ const more = cm.findByDescription('More...');
+ const moreItems = more && 'subitems' in more ? more.subitems : [];
if (!Doc.IsSystem(this.rootDoc)) {
- (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: "users" });
+ (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' });
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: `${this.Document._chromeHidden ? "Show" : "Hide"} Chrome`, event: () => this.Document._chromeHidden = !this.Document._chromeHidden, icon: "project-diagram" });
+ moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), 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" });
+ 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' });
}
- 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.props.Document)), icon: 'fingerprint' });
}
}
- if (this.props.removeDocument && !Doc.IsSystem(this.rootDoc) && CurrentUserUtils.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
- moreItems.push({ description: "Close", event: this.deleteClicked, icon: "times" });
+ if (this.props.removeDocument && !Doc.IsSystem(this.rootDoc) && Doc.ActiveDashboard !== this.props.Document) {
+ // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
+ moreItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' });
}
- !more && moreItems.length && cm.addItem({ description: "More...", subitems: moreItems, icon: "compass" });
-
- const help = cm.findByDescription("Help...");
- const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
- helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" });
- !Doc.noviceMode && helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" });
- !Doc.noviceMode && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
- !Doc.noviceMode && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" });
- cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
+ !more && moreItems.length && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'compass' });
+
+ const help = cm.findByDescription('Help...');
+ const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : [];
+ helpItems.push({ description: 'Show Fields ', event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), 'add:right'), icon: 'layer-group' });
+ !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), 'add:right'), icon: 'keyboard' });
+ !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' });
+ !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DataSym]), icon: 'hand-point-right' });
+ cm.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'question' });
}
if (!this.topMost) e?.stopPropagation(); // DocumentViews should stop propagation of this event
cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15);
- }
+ };
collectionFilters = () => StrListCast(this.props.Document._docFilters);
collectionRangeDocFilters = () => StrListCast(this.props.Document._docRangeFilters);
@computed get showFilterIcon() {
- return this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
- this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined;
+ return this.collectionFilters().length || this.collectionRangeDocFilters().length ? 'hasFilter' : this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? 'inheritsFilter' : undefined;
}
rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
panelHeight = () => this.props.PanelHeight() - this.headerMargin;
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
contentScaling = () => this.ContentScale;
onClickFunc = () => this.onClickHandler;
- setHeight = (height: number) => this.layoutDoc._height = height;
- setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view);
+ setHeight = (height: number) => (this.layoutDoc._height = height);
+ setContentView = action((view: { getAnchor?: () => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
isContentActive = (outsideReaction?: boolean) => {
- return this.props.isContentActive() === false ? false : (
- CurrentUserUtils.ActiveTool !== InkTool.None ||
- SnappingManager.GetIsDragging() ||
- this.rootSelected() ||
- this.props.Document.forceActive ||
- this.props.isSelected(outsideReaction) ||
- this._componentView?.isAnyChildContentActive?.() ||
- this.props.isContentActive()) ? true : undefined;
- }
+ return this.props.isContentActive() === false
+ ? false
+ : Doc.ActiveTool !== InkTool.None ||
+ SnappingManager.GetIsDragging() ||
+ this.rootSelected() ||
+ this.props.Document.forceActive ||
+ this.props.isSelected(outsideReaction) ||
+ this._componentView?.isAnyChildContentActive?.() ||
+ this.props.isContentActive()
+ ? true
+ : undefined;
+ };
@observable _retryThumb = 1;
thumbShown = () => {
- return !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
+ return !this.props.isSelected() &&
+ LightboxView.LightboxDoc !== this.rootDoc &&
+ this.thumb &&
!Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
!Doc.isBrushedHighlightedDegree(this.props.Document) &&
- !this._componentView?.isAnyChildContentActive?.() ? true : false;
- }
+ !this._componentView?.isAnyChildContentActive?.()
+ ? true
+ : false;
+ };
@computed get contents() {
TraceMobx();
- const audioView = !this.layoutDoc._showAudio ? (null) :
- <div className="documentView-audioBackground" onPointerDown={this.recordAudioAnnotation} onPointerEnter={this.onPointerEnter} >
- <FontAwesomeIcon className="documentView-audioFont"
- style={{ color: [DocListCast(this.dataDoc[this.LayoutFieldKey + "-audioAnnotations"]).length ? "blue" : "gray", "green", "red"][this._mediaState] }}
- icon={!DocListCast(this.dataDoc[this.LayoutFieldKey + "-audioAnnotations"]).length ? "microphone" : "file-audio"} size="sm" />
- </div>;
-
- return <div className="documentView-contentsView"
- style={{
- pointerEvents: this.props.pointerEvents?.() as any ?? this.rootDoc.layoutKey === "layout_icon" ? "none" :
- this.props.contentPointerEvents as any ? this.props.contentPointerEvents as any :
- this.rootDoc.type !== DocumentType.INK && this.isContentActive() ? "all" :
- "none",
- height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
- }}>
- {!this._retryThumb || !this.thumbShown() ? (null) :
- <img style={{ background: "white", top: 0, position: "relative" }} src={this.thumb} // + '?d=' + (new Date()).getTime()}
- width={this.props.PanelWidth()} height={this.props.PanelHeight()}
- onError={(e: any) => {
- setTimeout(action(() => this._retryThumb = 0), 0);
- setTimeout(action(() => this._retryThumb = 1), 150);
- }} />}
- <DocumentContentsView key={1}
- {...this.props}
- docViewPath={this.props.viewPath}
- thumbShown={this.thumbShown}
- isHovering={this.isHovering}
- setContentView={this.setContentView}
- scaling={this.contentScaling}
- PanelHeight={this.panelHeight}
- setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
- isContentActive={this.isContentActive}
- ScreenToLocalTransform={this.screenToLocal}
- rootSelected={this.rootSelected}
- onClick={this.onClickFunc}
- focus={this.focus}
- layoutKey={this.finalLayoutKey} />
- {this.layoutDoc.hideAllLinks ? (null) : this.allLinkEndpoints}
- {(!this.props.isSelected() && !this._isHovering) || this.hideLinkButton || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() ? (null) :
- <DocumentLinksButton View={this.props.DocumentView()}
- ContentScaling={this.props.ContentScaling}
- Offset={[this.topMost ? 0 : !this.props.isSelected() ? - 15 : -30, undefined, undefined, this.topMost ? 10 : !this.props.isSelected() ? - 15 : -30]} />
- }
- {audioView}
- </div>;
+ const audioView = !this.layoutDoc._showAudio ? null : (
+ <div className="documentView-audioBackground" onPointerDown={this.recordAudioAnnotation} onPointerEnter={this.onPointerEnter}>
+ <FontAwesomeIcon
+ className="documentView-audioFont"
+ style={{ color: [DocListCast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations']).length ? 'blue' : 'gray', 'green', 'red'][this._mediaState] }}
+ icon={!DocListCast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations']).length ? 'microphone' : 'file-audio'}
+ size="sm"
+ />
+ </div>
+ );
+
+ return (
+ <div
+ className="documentView-contentsView"
+ style={{
+ pointerEvents:
+ (this.props.pointerEvents?.() as any) ?? this.rootDoc.layoutKey === 'layout_icon'
+ ? 'none'
+ : (this.props.contentPointerEvents as any)
+ ? (this.props.contentPointerEvents as any)
+ : this.rootDoc.type !== DocumentType.INK && this.isContentActive()
+ ? 'all'
+ : 'none',
+ height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
+ }}>
+ {!this._retryThumb || !this.thumbShown() ? null : (
+ <img
+ style={{ background: 'white', top: 0, position: 'relative' }}
+ src={this.thumb} // + '?d=' + (new Date()).getTime()}
+ width={this.props.PanelWidth()}
+ height={this.props.PanelHeight()}
+ onError={(e: any) => {
+ setTimeout(
+ action(() => (this._retryThumb = 0)),
+ 0
+ );
+ setTimeout(
+ action(() => (this._retryThumb = 1)),
+ 150
+ );
+ }}
+ />
+ )}
+ <DocumentContentsView
+ key={1}
+ {...this.props}
+ docViewPath={this.props.viewPath}
+ thumbShown={this.thumbShown}
+ isHovering={this.isHovering}
+ setContentView={this.setContentView}
+ scaling={this.contentScaling}
+ PanelHeight={this.panelHeight}
+ setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
+ isContentActive={this.isContentActive}
+ ScreenToLocalTransform={this.screenToLocal}
+ rootSelected={this.rootSelected}
+ onClick={this.onClickFunc}
+ focus={this.focus}
+ layoutKey={this.finalLayoutKey}
+ />
+ {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
+ {(!this.props.isSelected() && !this._isHovering) || this.hideLinkButton || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() ? null : (
+ <DocumentLinksButton
+ View={this.props.DocumentView()}
+ ContentScaling={this.props.ContentScaling}
+ Offset={[this.topMost ? 0 : !this.props.isSelected() ? -15 : -30, undefined, undefined, this.topMost ? 10 : !this.props.isSelected() ? -15 : -30]}
+ />
+ )}
+ {audioView}
+ </div>
+ );
}
get indicatorIcon() {
- if (this.props.Document["acl-Public"] !== SharingPermissions.None) return "globe-americas";
- else if (this.props.Document.numGroupsShared || NumCast(this.props.Document.numUsersShared, 0) > 1) return "users";
- else return "user";
+ if (this.props.Document['acl-Public'] !== SharingPermissions.None) return 'globe-americas';
+ else if (this.props.Document.numGroupsShared || NumCast(this.props.Document.numUsersShared, 0) > 1) return 'users';
+ else return 'user';
}
@undoBatch
- hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true)
+ hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true);
anchorPanelWidth = () => this.props.PanelWidth() || 1;
anchorPanelHeight = () => this.props.PanelHeight() || 1;
anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
switch (property) {
- case StyleProp.ShowTitle: return "";
- case StyleProp.PointerEvents: return "none";
- case StyleProp.LinkSource: return this.props.Document;// pass the LinkSource to the LinkAnchorBox
- default: return this.props.styleProvider?.(doc, props, property);
+ case StyleProp.ShowTitle:
+ return '';
+ case StyleProp.PointerEvents:
+ return 'none';
+ case StyleProp.LinkSource:
+ return this.props.Document; // pass the LinkSource to the LinkAnchorBox
+ default:
+ 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 'unrendered' with their 'annotationOn' set to this document). e.g.,
+ };
+ // 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 '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.rootDoc).filter(link =>
- Doc.AreProtosEqual(link.anchor1 as Doc, this.rootDoc) ||
- Doc.AreProtosEqual(link.anchor2 as Doc, this.rootDoc) ||
- ((link.anchor1 as Doc).unrendered && Doc.AreProtosEqual((link.anchor1 as Doc).annotationOn as Doc, this.rootDoc)) ||
- ((link.anchor2 as Doc).unrendered && Doc.AreProtosEqual((link.anchor2 as Doc).annotationOn as Doc, this.rootDoc))
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.rootDoc).filter(
+ link =>
+ Doc.AreProtosEqual(link.anchor1 as Doc, this.rootDoc) ||
+ Doc.AreProtosEqual(link.anchor2 as Doc, this.rootDoc) ||
+ ((link.anchor1 as Doc).unrendered && Doc.AreProtosEqual((link.anchor1 as Doc).annotationOn as Doc, this.rootDoc)) ||
+ ((link.anchor2 as Doc).unrendered && Doc.AreProtosEqual((link.anchor2 as Doc).annotationOn as Doc, this.rootDoc))
);
}
- @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); }
- @computed get allLinkEndpoints() { // the small blue dots that mark the endpoints of links
+ @computed get allLinks() {
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
+ }
+ @computed get allLinkEndpoints() {
+ // the small blue dots that mark the endpoints of links
TraceMobx();
if (this.layoutDoc.unrendered || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null;
- if (this.rootDoc.type=== DocumentType.PRES || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return (null);
+ if (this.rootDoc.type === DocumentType.PRES || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return null;
const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => !d.hidden);
- return filtered.map((link, i) =>
+ return filtered.map((link, i) => (
<div className="documentView-anchorCont" key={link[Id]}>
- <DocumentView {...this.props}
+ <DocumentView
+ {...this.props}
isContentActive={returnFalse}
Document={link}
PanelWidth={this.anchorPanelWidth}
@@ -979,80 +1131,87 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
styleProvider={this.anchorStyleProvider}
removeDocument={this.hideLinkAnchor}
LayoutTemplate={undefined}
- LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(link, this.rootDoc)}`)} />
- </div >);
+ LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(link, this.rootDoc)}`)}
+ />
+ </div>
+ ));
}
@action
onPointerEnter = () => {
const self = this;
- const audioAnnos = DocListCast(this.dataDoc[this.LayoutFieldKey + "-audioAnnotations"]);
+ const audioAnnos = DocListCast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations']);
if (audioAnnos && audioAnnos.length && this._mediaState === 0) {
const anno = audioAnnos[Math.floor(Math.random() * audioAnnos.length)];
- anno.data instanceof AudioField && new Howl({
- src: [anno.data.url.href],
- format: ["mp3"],
- autoplay: true,
- loop: false,
- volume: 0.5,
- onend: function () {
- runInAction(() => self._mediaState = 0);
- }
- });
+ anno.data instanceof AudioField &&
+ new Howl({
+ src: [anno.data.url.href],
+ format: ['mp3'],
+ autoplay: true,
+ loop: false,
+ volume: 0.5,
+ onend: function () {
+ runInAction(() => (self._mediaState = 0));
+ },
+ });
this._mediaState = 1;
}
- }
+ };
recordAudioAnnotation = () => {
let gumStream: any;
let recorder: any;
const self = this;
- navigator.mediaDevices.getUserMedia({
- audio: true
- }).then(function (stream) {
- gumStream = stream;
- recorder = new MediaRecorder(stream);
- recorder.ondataavailable = async (e: any) => {
- const [{ result }] = await Networking.UploadFilesToServer(e.data);
- if (!(result instanceof Error)) {
- const audioDoc = Docs.Create.AudioDocument(result.accessPaths.agnostic.client, { title: "audio test", _width: 200, _height: 32 });
- audioDoc.treeViewExpandedView = "layout";
- const audioAnnos = Cast(self.dataDoc[self.LayoutFieldKey + "-audioAnnotations"], listSpec(Doc));
- if (audioAnnos === undefined) {
- self.dataDoc[self.LayoutFieldKey + "-audioAnnotations"] = new List([audioDoc]);
- } else {
- audioAnnos.push(audioDoc);
+ navigator.mediaDevices
+ .getUserMedia({
+ audio: true,
+ })
+ .then(function (stream) {
+ gumStream = stream;
+ recorder = new MediaRecorder(stream);
+ recorder.ondataavailable = async (e: any) => {
+ const [{ result }] = await Networking.UploadFilesToServer(e.data);
+ if (!(result instanceof Error)) {
+ const audioDoc = Docs.Create.AudioDocument(result.accessPaths.agnostic.client, { title: 'audio test', _width: 200, _height: 32 });
+ audioDoc.treeViewExpandedView = 'layout';
+ const audioAnnos = Cast(self.dataDoc[self.LayoutFieldKey + '-audioAnnotations'], listSpec(Doc));
+ if (audioAnnos === undefined) {
+ self.dataDoc[self.LayoutFieldKey + '-audioAnnotations'] = new List([audioDoc]);
+ } else {
+ audioAnnos.push(audioDoc);
+ }
}
- }
- };
- runInAction(() => self._mediaState = 2);
- recorder.start();
- setTimeout(() => {
- recorder.stop();
- runInAction(() => self._mediaState = 0);
- gumStream.getAudioTracks()[0].stop();
- }, 5000);
- });
- }
+ };
+ runInAction(() => (self._mediaState = 2));
+ recorder.start();
+ setTimeout(() => {
+ recorder.stop();
+ runInAction(() => (self._mediaState = 0));
+ gumStream.getAudioTracks()[0].stop();
+ }, 5000);
+ });
+ };
- captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ":caption");
+ captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
@computed get innards() {
TraceMobx();
- const ffscale = () => (this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1);
- const showTitle = this.ShowTitle?.split(":")[0];
- const showTitleHover = this.ShowTitle?.includes(":hover");
+ const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1;
+ const showTitle = this.ShowTitle?.split(':')[0];
+ const showTitleHover = this.ShowTitle?.includes(':hover');
const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined;
- const captionView = !showCaption ? (null) :
- <div className="documentView-captionWrapper"
+ const captionView = !showCaption ? null : (
+ <div
+ className="documentView-captionWrapper"
style={{
- pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : this.isContentActive() || this.props.isDocumentActive?.() ? "all" : undefined,
+ pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
minWidth: 50 * ffscale(),
- maxHeight: `max(100%, ${20 * ffscale()}px)`
+ maxHeight: `max(100%, ${20 * ffscale()}px)`,
}}>
- <FormattedTextBox {...OmitKeys(this.props, ['children']).omit}
+ <FormattedTextBox
+ {...OmitKeys(this.props, ['children']).omit}
yPadding={10}
xPadding={10}
fieldKey={showCaption}
- fontSize={12 * Math.max(1, 2 * ffscale() / 3)}
+ fontSize={12 * Math.max(1, (2 * ffscale()) / 3)}
styleProvider={this.captionStyleProvider}
dontRegisterView={true}
noSidebar={true}
@@ -1060,192 +1219,272 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
isContentActive={this.isContentActive}
onClick={this.onClickFunc}
/>
- </div>;
- const targetDoc = (showTitle?.startsWith("_") ? this.layoutDoc : this.rootDoc);
- const background = StrCast(SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor,
- Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)");
- const titleView = !showTitle ? (null) :
- <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
- position: this.headerMargin ? "relative" : "absolute",
- height: this.titleHeight,
- color: lightOrDark(background),
- background,
- pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : this.isContentActive() || this.props.isDocumentActive?.() ? "all" : undefined,
- }}>
- <EditableView ref={this._titleRef}
- contents={showTitle.split(";").map(field => field.trim()).map(field => targetDoc[field]?.toString()).join("\\")}
- display={"block"}
+ </div>
+ );
+ const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
+ const background = StrCast(
+ SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor,
+ Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
+ );
+ const titleView = !showTitle ? null : (
+ <div
+ className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
+ key="title"
+ style={{
+ position: this.headerMargin ? 'relative' : 'absolute',
+ height: this.titleHeight,
+ color: lightOrDark(background),
+ background,
+ pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
+ }}>
+ <EditableView
+ ref={this._titleRef}
+ contents={showTitle
+ .split(';')
+ .map(field => field.trim())
+ .map(field => targetDoc[field]?.toString())
+ .join('\\')}
+ display={'block'}
fontSize={10}
- GetValue={() => showTitle.split(";").length === 1 ? showTitle + "=" + Field.toString(targetDoc[showTitle.split(";")[0]] as any as Field) : "#" + showTitle}
+ GetValue={() => (showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle)}
SetValue={undoBatch((input: string) => {
- if (input?.startsWith("#")) {
+ if (input?.startsWith('#')) {
if (this.props.showTitle) {
this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
} else {
- Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : "creationDate";
+ Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
}
} else {
- var value = input.replace(new RegExp(showTitle + "="), "") as string | number;
- if (showTitle !== "title" && Number(value).toString() === value) value = Number(value);
- if (showTitle.includes("Date") || showTitle === "author") return true;
+ var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
+ if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
+ if (showTitle.includes('Date') || showTitle === 'author') return true;
Doc.SetInPlace(targetDoc, showTitle, value, true);
}
return true;
})}
/>
- </div>;
- return this.props.hideTitle || (!showTitle && !showCaption) ?
- this.contents :
- <div className="documentView-styleWrapper" >
- {!this.headerMargin ? <> {this.contents} {titleView} </> : <> {titleView} {this.contents} </>}
+ </div>
+ );
+ return this.props.hideTitle || (!showTitle && !showCaption) ? (
+ this.contents
+ ) : (
+ <div className="documentView-styleWrapper">
+ {!this.headerMargin ? (
+ <>
+ {' '}
+ {this.contents} {titleView}{' '}
+ </>
+ ) : (
+ <>
+ {' '}
+ {titleView} {this.contents}{' '}
+ </>
+ )}
{captionView}
- </div>;
+ </div>
+ );
}
isHovering = () => this._isHovering;
@observable _isHovering = false;
- @observable _: string = "";
+ @observable _: string = '';
@computed get renderDoc() {
TraceMobx();
- const thumb = ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url.href.replace(".png", "_m.png");
+ const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url.href.replace('.png', '_m.png');
const isButton = this.props.Document.type === DocumentType.FONTICON;
if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || (this.hidden && !this.props.treeViewDoc)) return null;
- return this.docContents ??
- <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
- id={this.props.Document[Id]}
- onPointerEnter={action(() => this._isHovering = true)}
- onPointerLeave={action(() => this._isHovering = false)}
- style={{
- background: isButton || thumb ? undefined : this.backgroundColor,
- opacity: this.opacity,
- color: StrCast(this.layoutDoc.color, "inherit"),
- fontFamily: StrCast(this.Document._fontFamily, "inherit"),
- fontSize: Cast(this.Document._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"}`,
- }}>
-
- {this.innards}
- {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <div className="documentView-contentBlocker" /> : (null)}
- {this.widgetDecorations ?? null}
- </div>;
+ return (
+ this.docContents ?? (
+ <div
+ className={`documentView-node${this.topMost ? '-topmost' : ''}`}
+ id={this.props.Document[Id]}
+ onPointerEnter={action(() => (this._isHovering = true))}
+ onPointerLeave={action(() => (this._isHovering = false))}
+ style={{
+ background: isButton || thumb ? undefined : this.backgroundColor,
+ opacity: this.opacity,
+ color: StrCast(this.layoutDoc.color, 'inherit'),
+ fontFamily: StrCast(this.Document._fontFamily, 'inherit'),
+ fontSize: Cast(this.Document._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'}`,
+ }}>
+ {this.innards}
+ {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <div className="documentView-contentBlocker" /> : null}
+ {this.widgetDecorations ?? null}
+ </div>
+ )
+ );
}
render() {
TraceMobx();
const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : Doc.DocBrushStatus.unbrushed) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
- const highlightColor = ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "orange", "lightBlue"][highlightIndex];
- const highlightStyle = ["solid", "dashed", "solid", "solid", "solid"][highlightIndex];
+ const highlightColor = ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
+ const highlightStyle = ['solid', 'dashed', 'solid', 'solid', 'solid'][highlightIndex];
const excludeTypes = !this.props.treeViewDoc ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON];
let highlighting = !this.props.disableDocBrushing && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
- highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
+ highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== '[pres element template]'; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath) || { path: undefined };
const internal = PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc;
- const boxShadow = this.props.treeViewDoc ? null : highlighting && this.borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` :
- this.boxShadow || (this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined);
-
- // Return surrounding highlight
- return <div className={`${DocumentView.ROOT_DIV} docView-hack`} ref={this._mainCont}
- onContextMenu={this.onContextMenu}
- onKeyDown={this.onKeyDown}
- onPointerDown={this.onPointerDown}
- onClick={this.onClick}
- onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))}
- onPointerLeave={action(e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document))}
- style={{
- display: this.hidden ? "inline" : undefined,
- borderRadius: this.borderRounding,
- pointerEvents: this.pointerEvents,
- outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px",
- border: highlighting && this.borderRounding && highlightStyle === "dashed" ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
- boxShadow,
- clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined
- }}>
- {!borderPath.path ? internal :
- <>
- {/* <div style={{ clipPath: `path('${borderPath.fill}')` }}>
+ const boxShadow = this.props.treeViewDoc
+ ? null
+ : highlighting && this.borderRounding && highlightStyle !== 'dashed'
+ ? `0 0 0 ${highlightIndex}px ${highlightColor}`
+ : this.boxShadow || (this.props.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
+
+ // Return surrounding highlight
+ return (
+ <div
+ className={`${DocumentView.ROOT_DIV} docView-hack`}
+ ref={this._mainCont}
+ onContextMenu={this.onContextMenu}
+ onKeyDown={this.onKeyDown}
+ onPointerDown={this.onPointerDown}
+ onClick={this.onClick}
+ onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))}
+ onPointerLeave={action(e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document))}
+ style={{
+ display: this.hidden ? 'inline' : undefined,
+ borderRadius: this.borderRounding,
+ pointerEvents: this.pointerEvents,
+ outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px',
+ border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
+ boxShadow,
+ clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined,
+ }}>
+ {!borderPath.path ? (
+ internal
+ ) : (
+ <>
+ {/* <div style={{ clipPath: `path('${borderPath.fill}')` }}>
{internal}
</div> */}
- {internal}
- <div key="border2" className="documentView-customBorder" style={{ pointerEvents: "none" }} >
- <svg style={{ overflow: "visible" }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
- <path d={borderPath.path} style={{ stroke: "black", fill: "transparent", strokeWidth: borderPath.width }} />
- </svg>
- </div>
- </>
- }
- {this.showFilterIcon ?
- <FontAwesomeIcon icon={"filter"} size="lg"
- style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }}
- onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })}
- />
- : (null)}
- </div>;
+ {internal}
+ <div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
+ <svg style={{ overflow: 'visible' }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
+ <path d={borderPath.path} style={{ stroke: 'black', fill: 'transparent', strokeWidth: borderPath.width }} />
+ </svg>
+ </div>
+ </>
+ )}
+ {this.showFilterIcon ? (
+ <FontAwesomeIcon
+ icon={'filter'}
+ size="lg"
+ style={{ position: 'absolute', top: '1%', right: '1%', cursor: 'pointer', padding: 1, color: this.showFilterIcon === 'hasFilter' ? '#18c718bd' : 'orange', zIndex: 1 }}
+ onPointerDown={action(e => {
+ this.props.select(false);
+ SettingsManager.propertiesWidth = 250;
+ e.stopPropagation();
+ })}
+ />
+ ) : null}
+ </div>
+ );
}
}
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
- public static ROOT_DIV = "documentView-effectsWrapper";
- public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
+ public static ROOT_DIV = 'documentView-effectsWrapper';
+ public get displayName() {
+ return 'DocumentView(' + this.props.Document?.title + ')';
+ } // this makes mobx trace() statements more descriptive
public ContentRef = React.createRef<HTMLDivElement>();
private _disposers: { [name: string]: IReactionDisposer } = {};
public static showBackLinks(linkSource: Doc) {
- const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + "-pivotish";
+ const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
DocServer.GetRefField(docid).then(docx => {
const rootAlias = () => {
const rootAlias = Doc.MakeAlias(linkSource);
rootAlias.x = rootAlias.y = 0;
return rootAlias;
};
- const linkCollection = ((docx instanceof Doc) && docx) || Docs.Create.StackingDocument([/*rootAlias()*/], { title: linkSource.title + "-pivot", _width: 500, _height: 500, }, docid);
+ const linkCollection =
+ (docx instanceof Doc && docx) ||
+ Docs.Create.StackingDocument(
+ [
+ /*rootAlias()*/
+ ],
+ { title: linkSource.title + '-pivot', _width: 500, _height: 500 },
+ docid
+ );
linkCollection.linkSource = linkSource;
- if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript("updateLinkCollection(self)");
+ if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript('updateLinkCollection(self)');
LightboxView.SetLightboxDoc(linkCollection);
});
}
@observable public docView: DocumentViewInternal | undefined | null;
- showContextMenu(pageX:number, pageY:number) { return this.docView?.onContextMenu(undefined, pageX, pageY); }
- get Document() { return this.props.Document; }
- get topMost() { return this.props.renderDepth === 0; }
- get rootDoc() { return this.docView?.rootDoc || this.Document; }
- get dataDoc() { return this.docView?.dataDoc || this.Document; }
- get finalLayoutKey() { return this.docView?.finalLayoutKey || "layout"; }
- get ContentDiv() { return this.docView?.ContentDiv; }
- get ComponentView() { return this.docView?._componentView; }
- get allLinks() { return this.docView?.allLinks || []; }
- get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; }
- get fitWidth() { return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth; }
-
- @computed get docViewPath(): DocumentView[] { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; }
- @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); }
+ showContextMenu(pageX: number, pageY: number) {
+ return this.docView?.onContextMenu(undefined, pageX, pageY);
+ }
+ get Document() {
+ return this.props.Document;
+ }
+ get topMost() {
+ return this.props.renderDepth === 0;
+ }
+ get rootDoc() {
+ return this.docView?.rootDoc || this.Document;
+ }
+ get dataDoc() {
+ return this.docView?.dataDoc || this.Document;
+ }
+ get finalLayoutKey() {
+ return this.docView?.finalLayoutKey || 'layout';
+ }
+ get ContentDiv() {
+ return this.docView?.ContentDiv;
+ }
+ get ComponentView() {
+ return this.docView?._componentView;
+ }
+ get allLinks() {
+ return this.docView?.allLinks || [];
+ }
+ get LayoutFieldKey() {
+ return this.docView?.LayoutFieldKey || 'layout';
+ }
+ get fitWidth() {
+ return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth;
+ }
+
+ @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.docView?._componentView?.reverseNativeScaling?.() ? 0 :
- returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
+ return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
}
@computed get nativeHeight() {
- return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
- returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
+ return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
}
@computed get shouldNotScale() {
- return (this.fitWidth && !this.nativeWidth) ||
- this.props.dontScaleFilter?.(this.Document) ||
- this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any);
+ return (this.fitWidth && !this.nativeWidth) || this.props.dontScaleFilter?.(this.Document) || this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any);
+ }
+ @computed get effectiveNativeWidth() {
+ return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
+ }
+ @computed get effectiveNativeHeight() {
+ return this.shouldNotScale ? 0 : this.nativeHeight || NumCast(this.layoutDoc.height);
}
- @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); }
- @computed get effectiveNativeHeight() { return this.shouldNotScale ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); }
@computed get nativeScaling() {
if (this.shouldNotScale) return 1;
const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
if (this.fitWidth || this.props.PanelHeight() / (this.effectiveNativeHeight || 1) > this.props.PanelWidth() / (this.effectiveNativeWidth || 1)) {
- return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or fitWidth
+ return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or fitWidth
}
return Math.max(minTextScale, this.props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
}
- @computed get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); }
+ @computed get panelWidth() {
+ return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth();
+ }
@computed get panelHeight() {
if (this.effectiveNativeHeight && !this.layoutDoc.nativeHeightUnfrozen) {
const scrollHeight = this.fitWidth ? Math.max(this.ComponentView?.getScrollHeight?.() ?? NumCast(this.layoutDoc.scrollHeight)) : 0;
@@ -1253,10 +1492,18 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
return this.props.PanelHeight();
}
- @computed get Xshift() { return this.effectiveNativeWidth ? (this.props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2 : 0; }
- @computed get Yshift() { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && !this.layoutDoc.nativeHeightUnfrozen ? 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 get centeringY() { return this.props.dontCenter?.includes("y") ? 0 : this.Yshift; }
+ @computed get Xshift() {
+ return this.effectiveNativeWidth ? (this.props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2 : 0;
+ }
+ @computed get Yshift() {
+ return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && !this.layoutDoc.nativeHeightUnfrozen ? 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 get centeringY() {
+ return this.props.dontCenter?.includes('y') ? 0 : this.Yshift;
+ }
toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight());
focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options);
@@ -1264,23 +1511,23 @@ export class DocumentView extends React.Component<DocumentViewProps> {
if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
return undefined;
}
- const xf = (this.docView?.props.ScreenToLocalTransform().scale(this.nativeScaling)).inverse();
+ const xf = this.docView?.props.ScreenToLocalTransform().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");
+ const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont');
if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined };
}
return { left, top, right, bottom, center: this.ComponentView?.getCenter?.(xf) };
- }
+ };
public iconify(finished?: () => void) {
this.ComponentView?.updateIcon?.();
- const layoutKey = Cast(this.Document.layoutKey, "string", null);
- if (layoutKey !== "layout_icon") {
- this.switchViews(true, "icon", finished);
- if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") this.Document.deiconifyLayout = layoutKey.replace("layout_", "");
+ const layoutKey = Cast(this.Document.layoutKey, 'string', null);
+ if (layoutKey !== 'layout_icon') {
+ this.switchViews(true, 'icon', finished);
+ if (layoutKey && layoutKey !== 'layout' && layoutKey !== 'layout_icon') this.Document.deiconifyLayout = layoutKey.replace('layout_', '');
} else {
- const deiconifyLayout = Cast(this.Document.deiconifyLayout, "string", null);
+ const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null);
this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finished);
this.Document.deiconifyLayout = undefined;
this.props.bringToFront(this.rootDoc);
@@ -1291,17 +1538,23 @@ export class DocumentView extends React.Component<DocumentViewProps> {
setCustomView = (custom: boolean, layout: string): void => {
Doc.setNativeView(this.props.Document);
custom && DocUtils.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
- }
+ };
switchViews = action((custom: boolean, view: string, finished?: () => void) => {
- this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc
- setTimeout(action(() => {
- this.setCustomView(custom, view);
- this.docView && (this.docView._animateScalingTo = 1); // expand it
- setTimeout(action(() => {
- this.docView && (this.docView._animateScalingTo = 0);
- finished?.();
- }), this.docView!._animateScaleTime - 10);
- }), this.docView!._animateScaleTime - 10);
+ this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc
+ setTimeout(
+ action(() => {
+ this.setCustomView(custom, view);
+ this.docView && (this.docView._animateScalingTo = 1); // expand it
+ setTimeout(
+ action(() => {
+ this.docView && (this.docView._animateScalingTo = 0);
+ finished?.();
+ }),
+ this.docView!._animateScaleTime - 10
+ );
+ }),
+ this.docView!._animateScaleTime - 10
+ );
});
startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
@@ -1315,7 +1568,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
PanelHeight = () => this.panelHeight;
ContentScale = () => this.nativeScaling;
selfView = () => this;
- screenToLocalTransform = () =>this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
+ screenToLocalTransform = () =>
+ this.props
+ .ScreenToLocalTransform()
+ .translate(-this.centeringX, -this.centeringY)
+ .scale(1 / this.nativeScaling);
componentDidMount() {
this._disposers.reactionScript = reaction(
() => ScriptCast(this.rootDoc.reactionScript)?.script?.run({ this: this.props.Document, self: Cast(this.rootDoc, Doc, null) || this.props.Document }).result,
@@ -1341,32 +1598,41 @@ export class DocumentView extends React.Component<DocumentViewProps> {
const yshift = () => (this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined);
const isPresTreeElement: boolean = this.props.treeViewDoc?.type === DocumentType.PRES;
const isButton: boolean = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear;
- return (<div className="contentFittingDocumentView">
- {!this.props.Document || !this.props.PanelWidth() ? (null) : (
- <div className="contentFittingDocumentView-previewDoc" ref={this.ContentRef}
- style={{
- transition: this.props.dataTransition,
- position: this.props.Document.isInkMask ? "absolute" : undefined,
- transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
- width: isButton || isPresTreeElement ? "100%" : xshift() ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
- height: isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
- `${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`),
- }}>
- <DocumentViewInternal {...this.props}
- DocumentView={this.selfView}
- viewPath={this.docViewPathFunc}
- PanelWidth={this.PanelWidth}
- PanelHeight={this.PanelHeight}
- NativeWidth={this.NativeWidth}
- NativeHeight={this.NativeHeight}
- isSelected={this.isSelected}
- select={this.select}
- ContentScaling={this.ContentScale}
- ScreenToLocalTransform={this.screenToLocalTransform}
- focus={this.props.focus || emptyFunction}
- ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} />
- </div>)}
- </div>);
+ return (
+ <div className="contentFittingDocumentView">
+ {!this.props.Document || !this.props.PanelWidth() ? null : (
+ <div
+ className="contentFittingDocumentView-previewDoc"
+ ref={this.ContentRef}
+ style={{
+ transition: this.props.dataTransition,
+ position: this.props.Document.isInkMask ? 'absolute' : undefined,
+ transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
+ width: isButton || isPresTreeElement ? '100%' : xshift() ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`,
+ height:
+ isButton || this.props.forceAutoHeight
+ ? undefined
+ : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
+ }}>
+ <DocumentViewInternal
+ {...this.props}
+ DocumentView={this.selfView}
+ viewPath={this.docViewPathFunc}
+ PanelWidth={this.PanelWidth}
+ PanelHeight={this.PanelHeight}
+ NativeWidth={this.NativeWidth}
+ NativeHeight={this.NativeHeight}
+ isSelected={this.isSelected}
+ select={this.select}
+ ContentScaling={this.ContentScale}
+ ScreenToLocalTransform={this.screenToLocalTransform}
+ focus={this.props.focus || emptyFunction}
+ ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))}
+ />
+ </div>
+ )}
+ </div>
+ );
}
}
@@ -1380,7 +1646,7 @@ ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) {
});
ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) {
- if (dv.Document.layoutKey === "layout_" + detailLayoutKeySuffix) dv.switchViews(false, "layout");
+ if (dv.Document.layoutKey === 'layout_' + detailLayoutKeySuffix) dv.switchViews(false, 'layout');
else dv.switchViews(true, detailLayoutKeySuffix);
});
@@ -1398,8 +1664,8 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
alias.y = 0;
alias._lockedPosition = false;
wid += otherdoc[WidthSym]();
- Doc.AddDocToList(Doc.GetProto(linkCollection), "data", alias);
+ Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', alias);
}
});
return links;
-}); \ No newline at end of file
+});