aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionTimeView.tsx
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2020-02-07 13:58:33 -0500
committerbob <bcz@cs.brown.edu>2020-02-07 13:58:33 -0500
commitea5e85e30b83b40135c83025d4f1be1ed188b9b7 (patch)
tree6e28ccee1b6cdcdca2ad5ecb5d49365d0cd28b13 /src/client/views/collections/CollectionTimeView.tsx
parentccedb9302632fcdbc75292b90942a34b98bebcee (diff)
parent688f54be8be328d733e05b0781aa8908305e14fa (diff)
Merge branch 'master' into fixinglayoutsyms
Diffstat (limited to 'src/client/views/collections/CollectionTimeView.tsx')
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx152
1 files changed, 100 insertions, 52 deletions
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 253dfa890..0c1f93829 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,29 +1,34 @@
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, observable } from "mobx";
+import { action, computed, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { Set } from "typescript-collections";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
+import { RichTextField } from "../../../new_fields/RichTextField";
import { listSpec } from "../../../new_fields/Schema";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { Docs } from "../../documents/Documents";
+import { Scripting } from "../../util/Scripting";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
import { EditableView } from "../EditableView";
import { anchorPoints, Flyout } from "../TemplateMenu";
+import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import "./CollectionTimeView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { CollectionTreeView } from "./CollectionTreeView";
+import "./CollectionTimeView.scss";
import React = require("react");
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { RichTextField } from "../../../new_fields/RichTextField";
+import { CollectionTreeView } from "./CollectionTreeView";
+import { ObjectField } from "../../../new_fields/ObjectField";
@observer
export class CollectionTimeView extends CollectionSubView(doc => doc) {
+ _changing = false;
+ @observable _layoutEngine = "pivot";
+
componentDidMount() {
- this.props.Document._freeformLayoutEngine = "timeline";
const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked;
if (!this.props.Document._facetCollection) {
const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true });
@@ -31,19 +36,24 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
this.props.Document.excludeFields = new List<string>(["_facetCollection", "_docFilter"]);
const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)";
- const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailed'); useRightSplit(alias); ";
+ const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
facetCollection.onCheckedClick = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name });
- this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name });
+ this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name, shiftKey: "boolean" });
this.props.Document._facetCollection = facetCollection;
this.props.Document._fitToBox = true;
}
+ if (!this.props.Document.onViewDefClick) {
+ this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" })
+ }
}
+
bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth;
getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 0);
@computed get _allFacets() {
const facets = new Set<string>();
this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
+ Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key)));
return facets.toArray();
}
@@ -106,14 +116,13 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const docItems: ContextMenuProps[] = [];
const keySet: Set<string> = new Set();
- this.childLayoutPairs.map(pair =>
- Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey =>
- pair.layout[fieldKey] instanceof RichTextField ||
- typeof (pair.layout[fieldKey]) === "number" ||
- typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey)));
+ this.childLayoutPairs.map(pair => this._allFacets.filter(fieldKey =>
+ pair.layout[fieldKey] instanceof RichTextField ||
+ typeof (pair.layout[fieldKey]) === "number" ||
+ typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey)));
keySet.toArray().map(fieldKey =>
- docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" }));
- docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" })
+ docItems.push({ description: ":" + fieldKey, event: () => this.props.Document._pivotField = fieldKey, icon: "compress-arrows-alt" }));
+ docItems.push({ description: ":(null)", event: () => this.props.Document._pivotField = undefined, icon: "compress-arrows-alt" })
ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" });
const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
ContextMenu.Instance.displayMenu(x, y, ":");
@@ -190,14 +199,14 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
document.removeEventListener("pointermove", this.onMidUp);
}
+ layoutEngine = () => this._layoutEngine;
@computed get contents() {
return <div className="collectionTimeView-innards" key="timeline" style={{ width: this.bodyPanelWidth() }}>
- <CollectionFreeFormView {...this.props} ScreenToLocalTransform={this.getTransform} PanelWidth={this.bodyPanelWidth} />
+ <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine} ScreenToLocalTransform={this.getTransform} PanelWidth={this.bodyPanelWidth} />
</div>;
}
-
- _changing = false;
- render() {
+ @computed get filterView() {
+ trace();
const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null);
const flyout = (
<div className="collectionTimeView-flyout" style={{ width: `${this._facetWidth}` }}>
@@ -208,68 +217,98 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
</label>)}
</div>
);
+ return <div className="collectionTimeView-treeView" style={{ width: `${this._facetWidth}px`, overflow: this._facetWidth < 15 ? "hidden" : undefined }}>
+ <div className="collectionTimeView-addFacet" style={{ width: `${this._facetWidth}px` }} onPointerDown={e => e.stopPropagation()}>
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
+ <div className="collectionTimeView-button">
+ <span className="collectionTimeView-span">Facet Filters</span>
+ <FontAwesomeIcon icon={faEdit} size={"lg"} />
+ </div>
+ </Flyout>
+ </div>
+ <div className="collectionTimeView-tree" key="tree">
+ <CollectionTreeView {...this.props} Document={facetCollection} />
+ </div>
+ </div>;
+ }
+
+ public static SyncTimelineToPresentation(doc: Doc) {
+ const fieldKey = Doc.LayoutFieldKey(doc);
+ doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(curPresentationItem()[this._pivotField || 'year'] || 0)");
+ }
+ specificMenu = (e: React.MouseEvent) => {
+ const layoutItems: ContextMenuProps[] = [];
+ const doc = this.props.Document;
+
+ layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline" }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot" }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" });
+
+ ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" });
+ }
+
+ render() {
const newEditableViewProps = {
GetValue: () => "",
SetValue: (value: any) => {
if (value?.length) {
- this.props.Document.pivotField = value;
+ this.props.Document._pivotField = value;
return true;
}
return false;
},
showMenuOnLoad: true,
- contents: ":" + StrCast(this.props.Document.pivotField),
+ contents: ":" + StrCast(this.props.Document._pivotField),
toggle: this.toggleVisibility,
color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
};
let nonNumbers = 0;
this.childDocs.map(doc => {
- const num = NumCast(doc[StrCast(this.props.Document.pivotField)], Number(StrCast(doc[StrCast(this.props.Document.pivotField)])));
+ const num = NumCast(doc[StrCast(this.props.Document._pivotField)], Number(StrCast(doc[StrCast(this.props.Document._pivotField)])));
if (Number.isNaN(num)) {
nonNumbers++;
}
});
- const doTimeline = nonNumbers / this.childDocs.length < 0.1;
- if (doTimeline !== (this.props.Document._freeformLayoutEngine === "timeline")) {
+ const forceLayout = StrCast(this.props.Document._forceRenderEngine);
+ const doTimeline = forceLayout ? (forceLayout === "timeline") : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6;
+ if (doTimeline !== (this._layoutEngine === "timeline")) {
if (!this._changing) {
this._changing = true;
- setTimeout(() => {
- if (nonNumbers / this.childDocs.length > 0.1) {
- this.childDocs.map(child => child.isMinimized = false);
- this.props.Document._freeformLayoutEngine = "pivot";
- } else {
- this.props.Document._freeformLayoutEngine = "timeline";
- }
+ setTimeout(action(() => {
+ this._layoutEngine = doTimeline ? "timeline" : "pivot";
this._changing = false;
- }, 0);
+ }), 0);
}
- return (null);
}
+
+ const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null);
return !facetCollection ? (null) :
- <div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
+ <div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} onContextMenu={this.specificMenu}
+ style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
<div className={"pivotKeyEntry"}>
- <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
+ <button className="collectionTimeView-backBtn" style={{ width: 50, height: 20, background: "green" }}
+ onClick={action(() => {
+ let pfilterIndex = NumCast(this.props.Document._pfilterIndex);
+ if (pfilterIndex > 0) {
+ this.props.Document._docFilter = ObjectField.MakeCopy(this.props.Document["_pfilter" + --pfilterIndex] as ObjectField);
+ this.props.Document._pfilterIndex = pfilterIndex;
+ } else {
+ this.props.Document._docFilter = new List([]);
+ }
+ })}>
+ back
+ </button>
+ <EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
</div>
{!this.props.isSelected() || this.props.PanelHeight() < 100 ? (null) :
<div className="collectionTimeView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this._facetWidth}px, 0px)` }} >
<span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} />
</div>
}
- <div className="collectionTimeView-treeView" style={{ width: `${this._facetWidth}px`, overflow: this._facetWidth < 15 ? "hidden" : undefined }}>
- <div className="collectionTimeView-addFacet" style={{ width: `${this._facetWidth}px` }} onPointerDown={e => e.stopPropagation()}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
- <div className="collectionTimeView-button">
- <span className="collectionTimeView-span">Facet Filters</span>
- <FontAwesomeIcon icon={faEdit} size={"lg"} />
- </div>
- </Flyout>
- </div>
- <div className="collectionTimeView-tree" key="tree">
- <CollectionTreeView {...this.props} Document={facetCollection} />
- </div>
- </div>
+ {this.filterView}
{this.contents}
{!this.props.isSelected() || !doTimeline ? (null) : <>
<div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} />
@@ -278,4 +317,13 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
</>}
</div>;
}
-} \ No newline at end of file
+}
+
+Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
+ let pfilterIndex = NumCast(pivotDoc._pfilterIndex);
+ pivotDoc["_pfilter" + pfilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilter as ObjectField);
+ pivotDoc._pfilterIndex = ++pfilterIndex;
+ pivotDoc._docFilter = new List();
+ (bounds.payload as string[]).map(filterVal =>
+ Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check"));
+}); \ No newline at end of file