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.tsx82
1 files changed, 33 insertions, 49 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fcfcaaeda..f34ac2b44 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -54,6 +54,7 @@ import { ScriptingBox } from './ScriptingBox';
import { PresEffect, PresEffectDirection } from './trails';
import { PinProps, PresBox } from './trails/PresBox';
import React = require('react');
+import { KeyValueBox } from './KeyValueBox';
const { Howl } = require('howler');
interface Window {
@@ -80,6 +81,7 @@ export enum OpenWhere {
replaceLeft = 'replace:left',
inParent = 'inParent',
inParentFromScreen = 'inParentFromScreen',
+ overlay = 'overlay',
}
export enum OpenWhereMod {
none = '',
@@ -87,6 +89,7 @@ export enum OpenWhereMod {
right = 'right',
top = 'top',
bottom = 'bottom',
+ rightKeyValue = 'rightKeyValue',
}
export interface DocFocusOptions {
@@ -94,6 +97,7 @@ export interface DocFocusOptions {
willZoomCentered?: boolean; // determines whether to zoom in on target document
zoomScale?: number; // percent of containing frame to zoom into document
zoomTime?: number;
+ didMove?: boolean; // whether a document was changed during the showDocument process
docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy
instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
preview?: boolean; // whether changes should be previewed by the componentView or written to the document
@@ -160,6 +164,7 @@ export interface DocumentViewSharedProps {
childHideResizeHandles?: () => boolean;
dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt
styleProvider: Opt<StyleProviderFunc>;
+ setTitleFocus?: () => void;
focus: DocFocusFunc;
fitWidth?: (doc: Doc) => boolean | undefined;
docFilters: () => string[];
@@ -313,8 +318,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@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 pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
+ return this.onClickHandler ? 'all' : this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
}
@computed get finalLayoutKey() {
return StrCast(this.Document.layoutKey, 'layout');
@@ -326,7 +331,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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));
+ const noClick = this.rootSelected() || this.props.isSelected() || this._componentView?.isAnyChildContentActive?.();
+ return noClick ? undefined : 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;
@@ -538,18 +544,11 @@ 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]); // 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;
dragData.moveDocument = this.props.moveDocument;
dragData.canEmbed = this.props.canEmbedOnDrag;
- //dragData.dimSource :
- // dragEffects field, set dim
- // add kv pairs to a doc, swap properties with the node while dragging, and then swap when dropping
- // add a dragEffects prop to DocumentView as a function that sets up. Each view has its own prop, when you start dragging:
- // in Draganager, figure out which doc(s) you're dragging and change what opacity function returns
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 && !this.props.dontHideOnDrag) }, () =>
@@ -559,22 +558,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
- onKeyDown = (e: React.KeyboardEvent) => {
- if (e.altKey) {
- e.stopPropagation();
- e.preventDefault();
- 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));
- else if (!this._titleRef.current.setIsFocused(true)) {
- // if focus didn't change, focus on interior text...
- this._titleRef.current?.setIsFocused(false);
- this._componentView?.setFocus?.();
- }
- }
- }
- };
-
defaultRestoreTargetView = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
const targetMatch =
Doc.AreProtosEqual(anchor, this.rootDoc) || // anchor is this document, so anchor's properties apply to this document
@@ -584,6 +567,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined;
};
+ // switches text input focus to the title bar of the document (and displays the title bar if it hadn't been)
+ setTitleFocus = () => {
+ if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = 'title';
+ setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined
+ };
+
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
if (!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;
@@ -613,6 +602,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
altKey,
shiftKey,
ctrlKey,
+ value: undefined,
},
console.log
);
@@ -627,7 +617,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
// bcz: hack? don't execute script if you're clicking on a scripting box itself
const { clientX, clientY, shiftKey, altKey, metaKey } = e;
const func = () =>
- this.onClickHandler.script.run(
+ this.onClickHandler?.script.run(
{
this: this.layoutDoc,
self: this.rootDoc,
@@ -655,7 +645,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
} else clickFunc();
} else if (!this._longPress && this.allLinks.length && this.Document.type !== DocumentType.LINK && !isScriptBox() && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
SelectionManager.DeselectAll();
- this.allLinks.length && LinkFollower.FollowLink(undefined, this.props.Document, this.props, e.altKey);
+ this.allLinks.length && LinkFollower.FollowLink(undefined, this.props.Document, 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 & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
@@ -990,7 +980,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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' });
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' });
@@ -1002,6 +991,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this.props.Document)), icon: 'fingerprint' });
}
+ moreItems.push({ description: 'Export collection', icon: 'download', event: async () => Doc.Zip(this.props.Document) });
+
+ (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' });
}
if (this.props.removeDocument && !Doc.IsSystem(this.rootDoc) && Doc.ActiveDashboard !== this.props.Document) {
@@ -1012,7 +1004,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
const help = cm.findByDescription('Help...');
const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : [];
- helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'layer-group' });
+ helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), 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 }), OpenWhere.addRight), 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' });
@@ -1078,7 +1070,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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);
- onClickFunc = () => this.onClickHandler;
+ onClickFunc = () => this.onClickHandler as any as ScriptField; // bcz: typing HACK. check and fix.
setHeight = (height: number) => (this.layoutDoc._height = height);
setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
isContentActive = (outsideReaction?: boolean) => {
@@ -1129,22 +1121,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</Tooltip>
);
}
+ contentPointerEvents = () => (this.onClickHandler ? 'none' : this.pointerEvents);
@computed get contents() {
TraceMobx();
return (
<div
className="documentView-contentsView"
style={{
- pointerEvents:
- this.opacity === 0
- ? 'none'
- : (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',
+ pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
}}>
{!this._retryThumb || !this.thumbShown() ? null : (
@@ -1165,7 +1149,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<DocumentContentsView
key={1}
{...this.props}
- pointerEvents={this.opacity === 0 ? returnNone : this.props.pointerEvents}
+ pointerEvents={this.contentPointerEvents}
docViewPath={this.props.viewPath}
thumbShown={this.thumbShown}
isHovering={this.props.isHovering}
@@ -1177,7 +1161,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
ScreenToLocalTransform={this.screenToLocal}
rootSelected={this.rootSelected}
onClick={this.onClickFunc}
- focus={emptyFunction}
+ focus={this.props.focus}
+ setTitleFocus={this.setTitleFocus}
layoutKey={this.finalLayoutKey}
/>
{this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
@@ -1495,7 +1480,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
className={`${DocumentView.ROOT_DIV} docView-hack`}
ref={this._mainCont}
onContextMenu={this.onContextMenu}
- onKeyDown={this.onKeyDown}
onPointerDown={this.onPointerDown}
onClick={this.onClick}
onPointerEnter={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)}
@@ -1504,7 +1488,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
style={{
display: this.hidden ? 'inline' : undefined,
borderRadius: this.borderRounding,
- pointerEvents: this.pointerEvents,
+ pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
}}>
{!borderPath.path ? (
animRenderDoc
@@ -1581,8 +1565,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
public static showBackLinks(linkSource: Doc) {
- const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
- DocServer.GetRefField(docid).then(docx => {
+ 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;
@@ -1595,7 +1579,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
/*rootAlias()*/
],
{ title: linkSource.title + '-pivot', _width: 500, _height: 500 },
- docid
+ docId
);
linkCollection.linkSource = linkSource;
if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript('updateLinkCollection(self)');
@@ -1857,7 +1841,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: isButton ? '100%' : xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`,
height:
- isButton || this.props.forceAutoHeight
+ isButton || this.props.LayoutTemplateString?.includes(KeyValueBox.name) || this.props.forceAutoHeight
? undefined
: yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
}}>