aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-02-16 14:39:41 -0500
committerbobzel <zzzman@gmail.com>2021-02-16 14:39:41 -0500
commit3dae4d3d8ac10f6f3c9f937282dbfa5882584aad (patch)
treeacf520396f5b68c6fbed342a959f823b021bb018
parent05a9a3eed9a1afb55ec0ca55845b33cc745289e0 (diff)
added getAnchor() to freeformView to capture viewtype & filters. fixed setPanIntoView bug. added setViewSpec componentView method to allow anchor to set view specs.
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx2
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx4
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx65
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx38
-rw-r--r--src/client/views/nodes/DocumentView.tsx17
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx6
6 files changed, 91 insertions, 41 deletions
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 904b4c761..2e6186680 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -216,7 +216,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
return (
<div className="collectionSchemaView-cellContainer" style={{ cursor: field instanceof Doc ? "grab" : "auto" }}
- ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
+ ref={dragRef} onPointerDown={this.onPointerDown} onClick={action(e => this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
<div className={className} ref={this._focusRef} tabIndex={-1}>
<div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null}>
{!this.props.Document._searchDoc ?
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 528cdc8b7..504cf32a0 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -103,7 +103,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
@undoBatch
- setColumnType = (columnField: SchemaHeaderField, type: ColumnType): void => {
+ setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => {
this._openTypes = false;
if (columnTypes.get(columnField.heading)) return;
@@ -114,7 +114,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
columns[index] = columnField;
this.columns = columns;
}
- }
+ });
@undoBatch
setColumnColor = (columnField: SchemaHeaderField, color: string): void => {
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 8c3e53dfd..426eced1d 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,16 +1,21 @@
+import { toUpper } from "lodash";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt, DocCastAsync, StrListCast } from "../../../fields/Doc";
+import { Doc, DocCastAsync, Opt, StrListCast } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { ObjectField } from "../../../fields/ObjectField";
import { RichTextField } from "../../../fields/RichTextField";
+import { listSpec } from "../../../fields/Schema";
import { ComputedField, ScriptField } from "../../../fields/ScriptField";
-import { NumCast, StrCast, BoolCast, Cast } from "../../../fields/Types";
-import { emptyFunction, returnFalse, setupMoveUpEvents, returnTrue } from "../../../Utils";
+import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentManager } from "../../util/DocumentManager";
import { Scripting } from "../../util/Scripting";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
import { EditableView } from "../EditableView";
+import { ViewSpecPrefix } from "../nodes/DocumentView";
import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
import { CollectionSubView } from "./CollectionSubView";
@@ -19,12 +24,6 @@ const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
import React = require("react");
-import { DocUtils, Docs } from "../../documents/Documents";
-import { toUpper } from "lodash";
-import { DocumentManager } from "../../util/DocumentManager";
-import { listSpec } from "../../../fields/Schema";
-import { LinkManager } from "../../util/LinkManager";
-import { LinkDocPreview } from "../nodes/LinkDocPreview";
@observer
export class CollectionTimeView extends CollectionSubView(doc => doc) {
@@ -33,6 +32,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@observable _collapsed: boolean = false;
@observable _childClickedScript: Opt<ScriptField>;
@observable _viewDefDivClick: Opt<ScriptField>;
+ @observable _focusDocFilters: Opt<string[]>; // fields that get overridden by a focus anchor
+ @observable _focusPivotField: Opt<string>;
+ @observable _focusRangeFilters: Opt<string[]>;
getAnchor = () => {
const anchor = Docs.Create.TextanchorDocument({
@@ -41,9 +43,15 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
hideLinkButton: true,
annotationOn: this.rootDoc
});
- Doc.GetProto(anchor).pivotField = this.pivotField;
- Doc.GetProto(anchor).docFilters = ObjectField.MakeCopy(this.layoutDoc._docFilters as ObjectField);
- Doc.GetProto(anchor)._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField);
+
+ // save view spec information for anchor
+ const proto = Doc.GetProto(anchor);
+ proto.pivotField = this.pivotField;
+ proto.docFilters = ObjectField.MakeCopy(this.layoutDoc._docFilters as ObjectField) || new List<string>([]);
+ proto.docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField) || new List<string>([]);
+ proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType;
+
+ // store anchor in annotations list of document (not technically needed since these anchors are never drawn)
if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) {
Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor);
} else {
@@ -63,26 +71,24 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
});
}
- @observable _scrollFilters: Opt<string[]>;
- @observable _scrollPivotField: Opt<string>;
- timeDocFilters = () => this._scrollFilters || ([] as string[]);
- get pivotField() { return this._scrollPivotField || StrCast(this.layoutDoc._pivotField); }
+ get pivotField() { return this._focusPivotField || StrCast(this.layoutDoc._pivotField); }
@action
- scrollFocus = (anchor: Doc, smooth: boolean) => {
- if (!LinkDocPreview.LinkInfo) {
- if (anchor.pivotField !== undefined) {
- this.layoutDoc._prevFilterIndex = 1;
- this.layoutDoc._pivotField = StrCast(anchor.pivotField);
- this.layoutDoc._docFilters = ObjectField.MakeCopy(Doc.GetProto(anchor).docFilters as ObjectField);
- this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(Doc.GetProto(anchor).docRangeFilters as ObjectField);
- }
- } else {
- this._scrollPivotField = StrCast(anchor.pivotField);
- this._scrollFilters = StrListCast(Doc.GetProto(anchor).docFilters);
+ setViewSpec = (anchor: Doc, preview: boolean) => {
+ if (preview) { // if in preview, then override document's fields with view spec
+ this._focusPivotField = StrCast(anchor.pivotField);
+ this._focusDocFilters = StrListCast(anchor.docFilters);
+ this._focusRangeFilters = StrListCast(anchor.docRangeFilters);
+ } else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec
+ this.layoutDoc._prevFilterIndex = 1;
+ this.layoutDoc._pivotField = StrCast(anchor.pivotField);
+ this.layoutDoc._docFilters = new List<string>(this.pivotDocFilters());
+ this.layoutDoc._docRangeFilters = new List<string>(this.pivotDocRangeFilters());
}
return 0;
}
+ pivotDocFilters = () => this._focusDocFilters || this.props.docFilters();
+ pivotDocRangeFilters = () => this._focusRangeFilters || this.props.docRangeFilters();
layoutEngine = () => this._layoutEngine;
toggleVisibility = action(() => this._collapsed = !this._collapsed);
@@ -136,9 +142,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.active() ? undefined : "none" }}
onClick={this.contentsDown}>
<CollectionFreeFormView {...this.props}
- engineProps={{ pivotField: this.pivotField, docFilters: this.docFilters }}
+ engineProps={{ pivotField: this.pivotField, docFilters: this.docFilters, docRangeFilters: this.docRangeFilters }}
fitContentsToDoc={returnTrue}
- docFilters={this.timeDocFilters}
+ docFilters={this.pivotDocFilters}
+ docRangeFilters={this.pivotDocRangeFilters}
childClickScript={this._childClickedScript}
viewDefDivClick={this._viewDefDivClick}
childFreezeDimensions={true}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b2ee6bbd0..c54596a9e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -6,6 +6,7 @@ import { collectionSchema, documentSchema } from "../../../../fields/documentSch
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
+import { ObjectField } from "../../../../fields/ObjectField";
import { RichTextField } from "../../../../fields/RichTextField";
import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema";
import { ScriptField } from "../../../../fields/ScriptField";
@@ -35,7 +36,7 @@ import { DocumentDecorations } from "../../DocumentDecorations";
import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth } from "../../InkingStroke";
import { LightboxView } from "../../LightboxView";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
-import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../../nodes/DocumentView";
+import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
import { FieldViewProps } from "../../nodes/FieldView";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
@@ -114,6 +115,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@observable _clusterSets: (Doc[])[] = [];
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeRef = React.createRef<HTMLDivElement>();
+ @observable _focusFilters: Opt<string[]>; // fields that get overriden by focus anchor
@computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); }
@computed get fitToContentVals() {
@@ -985,7 +987,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
panY: (bounds.top + bounds.bot) / 2,
scale: Math.min(maxZoom, scale * Math.min(this.props.PanelWidth() / Math.abs(pt2[0] - pt[0]), this.props.PanelHeight() / Math.abs(pt2[1] - pt[1])))
};
- } else if ((screen.right - screen.left) < (bounds.right - bounds.left)) {
+ } else if ((screen.right - screen.left) < (bounds.right - bounds.left) ||
+ (screen.bot - screen.top) < (bounds.bot - bounds.top)) {
return {
panX: (bounds.left + bounds.right) / 2,
panY: (bounds.top + bounds.bot) / 2,
@@ -1023,7 +1026,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
PanelWidth: childLayout[WidthSym],
PanelHeight: childLayout[HeightSym],
- docFilters: this.docFilters,
+ docFilters: this.freeformDocFilters,
docRangeFilters: this.docRangeFilters,
searchFilterDocs: this.searchFilterDocs,
focus: this.focusDocument,
@@ -1202,6 +1205,35 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.Document._useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
return elements;
}
+
+ freeformDocFilters = () => this._focusFilters || this.docFilters();
+ @action
+ setViewSpec = (anchor: Doc, preview: boolean) => {
+ if (preview) {
+ this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
+ } else if (anchor.pivotField !== undefined) {
+ this.layoutDoc._docFilters = ObjectField.MakeCopy(Doc.GetProto(anchor).docFilters as ObjectField);
+ }
+ return 0;
+ }
+
+ getAnchor = () => {
+ const anchor = Docs.Create.TextanchorDocument({
+ title: StrCast(this.layoutDoc._viewType),
+ useLinkSmallAnchor: true,
+ hideLinkButton: true,
+ annotationOn: this.rootDoc
+ });
+ const proto = Doc.GetProto(anchor);
+ proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType;
+ proto[ViewSpecPrefix + "_docFilters"] = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List<string>([]);
+ if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) {
+ Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor);
+ } else {
+ this.dataDoc[this.props.fieldKey + "-annotations"] = new List<Doc>([anchor]);
+ }
+ return anchor;
+ }
freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined;
@action
componentDidMount() {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4aa424af3..e52791901 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -45,6 +45,7 @@ import { LinkDocPreview } from "./LinkDocPreview";
import { PresBox } from './PresBox';
import { RadialMenu } from './RadialMenu';
import React = require("react");
+import { ObjectField } from "../../../fields/ObjectField";
const { Howl } = require('howler');
interface Window {
@@ -56,12 +57,13 @@ declare class MediaRecorder {
constructor(e: any);
}
-
export enum ViewAdjustment {
resetView = 1,
doNothing = 0
-
}
+
+export const ViewSpecPrefix = "_VIEW"; // 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
@@ -75,6 +77,7 @@ export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps | F
export interface DocComponentView {
getAnchor?: () => Doc;
scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus
+ setViewSpec?: (anchor: Doc, preview: boolean) => void;
back?: () => boolean;
forward?: () => boolean;
url?: () => string;
@@ -405,10 +408,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
- focus = (doc: Doc, options?: DocFocusOptions) => {
- const focusSpeed = this._componentView?.scrollFocus?.(doc, !LinkDocPreview.LinkInfo); // bcz: smooth parameter should really be passed into focus() instead of inferred here
+ focus = (anchor: Doc, options?: DocFocusOptions) => {
+ // 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]));
+ // 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, !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 ? options?.afterFocus(true) : ViewAdjustment.doNothing;
- this.props.focus(options?.docTransform ? doc : this.rootDoc, {
+ this.props.focus(options?.docTransform ? anchor : this.rootDoc, {
...options, afterFocus: (didFocus: boolean) =>
new Promise<ViewAdjustment>(res => setTimeout(async () => res(endFocus ? await endFocus(didFocus) : ViewAdjustment.doNothing), focusSpeed ?? 0))
});
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 7bd5d14d2..716810536 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -45,7 +45,11 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
if (anchor1 && anchor2) {
linkTarget = Doc.AreProtosEqual(anchor1, this._linkSrc) || Doc.AreProtosEqual(anchor1?.annotationOn as Doc, this._linkSrc) ? anchor2 : anchor1;
}
- linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => this._targetDoc = anno));
+ if (linkTarget?.annotationOn) {
+ linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => this._targetDoc = anno));
+ } else {
+ this._targetDoc = linkTarget;
+ }
this._toolTipText = "";
}
componentDidUpdate(props: any) {