diff options
author | Sam Wilkins <samwilkins333@gmail.com> | 2020-02-07 04:27:59 -0500 |
---|---|---|
committer | Sam Wilkins <samwilkins333@gmail.com> | 2020-02-07 04:27:59 -0500 |
commit | 703bad5d9f3c6e385fc6f7c4db3b237c0d41401f (patch) | |
tree | 7bb66748a83e76759bc7d2c3d9d8e4bf6aea954b | |
parent | 4eba9ccc46ac6a1ad346ce5027b098a8a5b838c4 (diff) | |
parent | 9f82ece7c763ba4a054d86a715311e0280fcb79f (diff) |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web
10 files changed, 95 insertions, 60 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index 9e3db9e06..0fa33dcb7 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -363,7 +363,7 @@ export function percent2frac(percent: string) { return Number(percent.substr(0, percent.length - 1)) / 100; } -export function numberRange(num: number) { return Array.from(Array(num)).map((v, i) => i); } +export function numberRange(num: number) { return num > 0 && num < 1000 ? Array.from(Array(num)).map((v, i) => i) : []; } export function returnTransparent() { return "transparent"; } diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 843c743db..293dc5414 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -19,6 +19,7 @@ position: absolute; top: 0; overflow-y: auto; + overflow-x: hidden; flex-wrap: wrap; transition: top .5s; >div { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 91c7ca76e..e04f4e8a6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -40,8 +40,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); } @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); } - @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * this.gridGap); } - @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 2 * this.gridGap)); } + @computed get xMargin() { return NumCast(this.props.Document._xMargin, 0); }// 2 * this.gridGap); } + @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } @@ -52,11 +52,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } - children(docs: Doc[]) { + children(docs: Doc[], columns?: number) { this._docXfs.length = 0; return docs.map((d, i) => { - const width = () => Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); const height = () => this.getDocHeight(d); + const width = () => (this.widthScale && !columns ? this.widthScale : 1) * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); const dref = React.createRef<HTMLDivElement>(); const dxf = () => this.getDocTransform(d, dref.current!); this._docXfs.push({ dxf: dxf, width: width, height: height }); @@ -377,6 +377,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1])); } + @computed get heightScale() { + return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), this.props.Document[HeightSym]() / this.props.PanelHeight()); + } + @computed get widthScale() { + return StrCast(this.props.Document.title).includes("slide") || true ? this.heightScale : undefined; + } render() { TraceMobx(); const editableViewProps = { @@ -391,8 +397,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { style={{ overflowY: this.props.active() ? "auto" : "hidden", transform: `scale(${Math.min(1, this.props.PanelHeight() / this.layoutDoc[HeightSym]())})`, - height: `${Math.max(100, 100 * 1 / Math.min(this.props.PanelWidth() / this.layoutDoc[WidthSym](), this.props.PanelHeight() / this.layoutDoc[HeightSym]()))}%`, - transformOrigin: "top" + height: `${Math.max(100, 100 * this.heightScale)}%`, + width: this.widthScale ? `${Math.max(100, 100 * this.widthScale)}%` : undefined, + transformOrigin: this.widthScale ? "top left" : "top", }} onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)} onDrop={this.onDrop.bind(this)} diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index b81b1f31d..21982f1ca 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -407,7 +407,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC gridTemplateColumns: singleColumn ? undefined : templatecols, gridAutoRows: singleColumn ? undefined : "0px" }}> - {this.props.parent.children(this.props.docList)} + {this.props.parent.children(this.props.docList, uniqueHeadings.length)} {singleColumn ? (null) : this.props.parent.columnDragger} </div> {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a2700e75a..e0e99d635 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -111,34 +111,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { get childDocs() { const docs = DocListCast(this.dataField); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); - const viewedDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; - const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []); - const clusters: { [key: string]: { [value: string]: string } } = {}; - for (let i = 0; i < docFilters.length; i += 3) { - const [key, value, modifiers] = docFilters.slice(i, i + 3); - const cluster = clusters[key]; - if (!cluster) { - const child: { [value: string]: string } = {}; - child[value] = modifiers; - clusters[key] = child; - } else { - cluster[value] = modifiers; - } - } - const filteredDocs = docFilters.length ? viewedDocs.filter(d => { - for (const key of Object.keys(clusters)) { - const cluster = clusters[key]; - const satisfiesFacet = Object.keys(cluster).some(inner => { - const modifier = cluster[inner]; - return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); - }); - if (!satisfiesFacet) { - return false; - } - } - return true; - }) : viewedDocs; - return filteredDocs; + return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; } @action diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index df5057b5b..a5ce73a92 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -5,6 +5,11 @@ height: 100%; width: 100%; overflow: hidden; + .collectionTimeView-backBtn { + background: green; + display: inline; + margin-right: 20px; + } .collectionFreeform-customText { text-align: left; } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index fb36a1b0c..0c1f93829 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,27 +1,27 @@ import { faEdit } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, observable, trace } 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 { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { Scripting } from "../../util/Scripting"; -import { ViewDefResult, ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; +import { CollectionTreeView } from "./CollectionTreeView"; +import { ObjectField } from "../../../new_fields/ObjectField"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -289,7 +289,19 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { <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)` }} > @@ -308,6 +320,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } 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")); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index e354ad0af..95f7794bb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -36,7 +36,6 @@ export interface PoolData { color?: string, transition?: string, highlight?: boolean, - state?: any } export interface ViewDefResult { @@ -71,19 +70,21 @@ interface pivotColumn { filters: string[] } + export function computePivotLayout( poolData: Map<string, PoolData>, pivotDoc: Doc, childDocs: Doc[], + filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: (views: any) => ViewDefResult[] + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; const pivotColumnGroups = new Map<FieldResult<Field>, pivotColumn>(); const pivotFieldKey = toLabel(pivotDoc._pivotField); - for (const doc of childDocs) { + for (const doc of filterDocs) { const val = Field.toString(doc[pivotFieldKey] as Field); if (val) { !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val] }); @@ -179,7 +180,7 @@ export function computePivotLayout( const dividers = sortedPivotKeys.map((key, i) => ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); groupNames.push(...dividers); - return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []); + return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c))); } function toNumber(val: FieldResult<Field>) { @@ -190,9 +191,10 @@ export function computeTimelineLayout( poolData: Map<string, PoolData>, pivotDoc: Doc, childDocs: Doc[], + filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[] + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; const pivotDateGroups = new Map<number, Doc[]>(); @@ -212,7 +214,7 @@ export function computeTimelineLayout( let minTime = Number.MAX_VALUE; let maxTime = -Number.MAX_VALUE; - childDocs.map(doc => { + filterDocs.map(doc => { const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey]))); if (!(Number.isNaN(num) || (minTimeReq && num < minTimeReq) || (maxTimeReq && num > maxTimeReq))) { !pivotDateGroups.get(num) && pivotDateGroups.set(num, []); @@ -275,7 +277,7 @@ export function computeTimelineLayout( } const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1, payload: undefined }; - return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]); + return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childDocs.filter(c => !filterDocs.includes(c))); function layoutDocsAtTime(keyDocs: Doc[], key: number) { keyDocs.forEach(doc => { @@ -298,7 +300,8 @@ export function computeTimelineLayout( } function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<Doc, ViewDefBounds>, - poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[]) { + poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[], + extraDocs: Doc[]) { const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as ViewDefBounds); @@ -323,6 +326,7 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }); } }); + extraDocs.map(ed => poolData.set(ed[Id], { x: 0, y: 0, zIndex: -99 })); return { elements: viewDefsToJSX(extras.concat(groupNames.map(gname => ({ diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ea3805b65..2518a4a55 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } f import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkTool, InkField, InkData } from "../../../../new_fields/InkField"; -import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; @@ -794,12 +794,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }.bind(this)); doTimelineLayout(poolData: Map<string, any>) { - return computeTimelineLayout(poolData, this.props.Document, this.childDocs, + return computeTimelineLayout(poolData, this.props.Document, this.childDocs, this.filterDocs, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } doPivotLayout(poolData: Map<string, any>) { - return computePivotLayout(poolData, this.props.Document, this.childDocs, + return computePivotLayout(poolData, this.props.Document, this.childDocs, this.filterDocs, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } @@ -812,7 +812,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state }); - state = pos.state === undefined ? state : pos.state; poolData.set(pair.layout[Id], pos); }); return { elements: elements }; @@ -826,6 +825,36 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } return { newPool, computedElementData: this.doFreeformLayout(newPool) }; } + + @computed get filterDocs() { + const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []); + const clusters: { [key: string]: { [value: string]: string } } = {}; + for (let i = 0; i < docFilters.length; i += 3) { + const [key, value, modifiers] = docFilters.slice(i, i + 3); + const cluster = clusters[key]; + if (!cluster) { + const child: { [value: string]: string } = {}; + child[value] = modifiers; + clusters[key] = child; + } else { + cluster[value] = modifiers; + } + } + const filteredDocs = docFilters.length ? this.childDocs.filter(d => { + for (const key of Object.keys(clusters)) { + const cluster = clusters[key]; + const satisfiesFacet = Object.keys(cluster).some(inner => { + const modifier = cluster[inner]; + return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); + }); + if (!satisfiesFacet) { + return false; + } + } + return true; + }) : this.childDocs; + return filteredDocs; + } get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; runInAction(() => diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f484b6115..3bceec45f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -88,6 +88,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF width: this.width, height: this.height, zIndex: this.ZInd, + display: this.ZInd === -99 ? "none" : undefined, pointerEvents: this.props.Document.isBackground ? "none" : undefined }} > |