aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx132
1 files changed, 69 insertions, 63 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 74143a731..145d8bf3d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,8 +1,9 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
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 { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
@@ -10,7 +11,7 @@ import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+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';
@@ -20,6 +21,7 @@ import { DocServer } from '../../DocServer';
import { Docs, DocUtils } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { Networking } from '../../Network';
+import { DictationManager } from '../../util/DictationManager';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
import { InteractionUtils } from '../../util/InteractionUtils';
@@ -37,7 +39,6 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from '../DocComponent';
import { EditableView } from '../EditableView';
-import { InkingStroke } from '../InkingStroke';
import { LightboxView } from '../LightboxView';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
@@ -52,8 +53,6 @@ import { RadialMenu } from './RadialMenu';
import { ScriptingBox } from './ScriptingBox';
import { PresBox } from './trails/PresBox';
import React = require('react');
-import { DictationManager } from '../../util/DictationManager';
-import { Tooltip } from '@material-ui/core';
const { Howl } = require('howler');
interface Window {
@@ -81,12 +80,13 @@ export interface DocFocusOptions {
instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
}
export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>;
-export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void;
+export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void;
export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
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
+ brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void;
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
@@ -498,8 +498,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
.ScreenToLocalTransform()
.scale(this.NativeDimScaling)
.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.offset[0] = Math.min(this.rootDoc[WidthSym](), dragData.offset[0]); // bcz: this was breaking dragging rotated objects since the offset may be out of bounds with regard to the unrotated document
+ // dragData.offset[1] = Math.min(this.rootDoc[HeightSym](), dragData.offset[1]);
dragData.dropAction = dropAction;
dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
@@ -534,7 +534,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
};
- focus = (anchor: Doc, options?: DocFocusOptions) => {
+ focus = (anchor: Doc, options: DocFocusOptions) => {
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)))
@@ -582,7 +582,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
console.log
);
UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click');
- } else if (!Doc.IsSystem(this.rootDoc)) {
+ } else if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isLinkButton) {
UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, 'lightbox', this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap');
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
@@ -881,9 +881,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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 : [];
if (this.props.bringToFront !== emptyFunction) {
+ const zorders = cm.findByDescription('ZOrder...');
+ const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.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({
@@ -891,8 +891,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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' });
@@ -1001,7 +1001,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
LightboxView.LightboxDoc !== this.rootDoc &&
this.thumb &&
!Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
- !Doc.isBrushedHighlightedDegree(this.props.Document) &&
+ (!Doc.isBrushedHighlightedDegree(this.props.Document) || this.rootDoc._viewType === CollectionViewType.Docking) &&
!this._componentView?.isAnyChildContentActive?.()
? true
: false;
@@ -1259,46 +1259,47 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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,
- width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
- 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)}
- SetValue={undoBatch((input: string) => {
- if (input?.startsWith('#')) {
- if (this.props.showTitle) {
- this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+ const titleView =
+ !showTitle || Doc.noviceMode ? null : (
+ <div
+ className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
+ key="title"
+ style={{
+ position: this.headerMargin ? 'relative' : 'absolute',
+ height: this.titleHeight,
+ width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
+ 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)}
+ SetValue={undoBatch((input: string) => {
+ 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';
+ }
} else {
- Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+ 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);
}
- } 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;
- Doc.SetInPlace(targetDoc, showTitle, value, true);
- }
- return true;
- })}
- />
- </div>
- );
+ return true;
+ })}
+ />
+ </div>
+ );
return this.props.hideTitle || (!showTitle && !showCaption) ? (
this.contents
) : (
@@ -1322,7 +1323,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@observable _isHovering = false;
@observable _: string = '';
_hoverTimeout: any = undefined;
- @computed get renderDoc() {
+ renderDoc = (style: object) => {
TraceMobx();
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;
@@ -1344,8 +1345,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
);
})}
style={{
+ ...style,
background: isButton || thumb ? undefined : this.backgroundColor,
opacity: this.opacity,
+ cursor: Doc.ActiveTool === InkTool.None ? 'grab' : 'crosshair',
color: StrCast(this.layoutDoc.color, 'inherit'),
fontFamily: StrCast(this.Document._fontFamily, 'inherit'),
fontSize: Cast(this.Document._fontSize, 'string', null),
@@ -1358,7 +1361,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</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
@@ -1369,13 +1372,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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);
+ const renderDoc = this.renderDoc({
+ borderRadius: this.borderRounding,
+ 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,
+ });
+ const animRenderDoc = PresBox.Instance?.isActiveItemTarget(this.layoutDoc) ? PresBox.AnimationEffect(renderDoc, PresBox.Instance.activeItem) : renderDoc;
// Return surrounding highlight
return (
<div
@@ -1391,19 +1401,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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
+ animRenderDoc
) : (
<>
{/* <div style={{ clipPath: `path('${borderPath.fill}')` }}>
- {internal}
+ {animRenderDoc}
</div> */}
- {internal}
+ {animRenderDoc}
<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 }} />
@@ -1552,7 +1558,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
- focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options);
+ focus = (doc: Doc, options: DocFocusOptions) => this.docView?.focus(doc, options);
getBounds = () => {
if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
return undefined;