From c357ef923eafc17210f278d36a0693fe902b21fb Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 14 Aug 2019 13:41:23 -0400 Subject: fixed more sizing issues with stacking/masonry views --- .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 90 +++++++++------------- .../CollectionStackingViewFieldColumn.tsx | 66 +++++----------- 3 files changed, 60 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 13bb34037..7332a490a 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -389,7 +389,7 @@ export class CollectionDockingView extends React.Component { - if (!this._isPointerDown) return; + if (!this._isPointerDown || !SelectionManager.GetIsDragging()) return; var activeContentItem = tab.header.parent.getActiveContentItem(); if (tab.contentItem !== activeContentItem) { tab.header.parent.setActiveContentItem(tab.contentItem); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d68ef2bbd..4e49e368b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -10,7 +10,7 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; +import { emptyFunction, Utils, numberRange } from "../../../Utils"; import { DocumentType } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; @@ -33,14 +33,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _docXfs: any[] = []; _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; - get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } + @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.childDocs.filter(d => !d.isMinimized); } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } - @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } - @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } - @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } - @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); } + @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; } + @computed get showAddAGroup() { return (this.sectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')); } + @computed get columnWidth() { + return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin, + this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250)); + } + + childDocHeight(child: Doc) { return this.getDocHeight(Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, child).layout); } get layoutDoc() { // if this document's layout field contains a document (ie, a rendering template), then we will use that @@ -48,7 +55,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; } - get Sections() { if (!this.sectionFilter) return new Map(); @@ -78,33 +84,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } componentDidMount() { - // is there any reason this needs to exist? -syip + // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). this._heightDisposer = reaction(() => { - if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) { - let maxHght = 0; - Array.from(this.Sections.values()).map(s => { - let hgt = 50 + s.reduce((height, d, i) => { - let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d); - return height + this.getDocHeight(pair.layout, this.Sections.size) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap); - }, this.yMargin); - maxHght = Math.max(hgt, maxHght); - }) - if (!maxHght) { - let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => { - let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d); - return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap); - }, this.yMargin); - maxHght = hgt * this.props.ContentScaling(); - } - return maxHght * this.props.ContentScaling(); + if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) { + let sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]); + return this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => Math.max(maxHght, + 50 + s.reduce((height, d, i) => height + this.childDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap), this.yMargin) + ), 0); } return -1; }, (hgt: number) => { - if (hgt !== -1) { - let doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc; - doc.height = hgt; - } + let doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc; + doc && (doc.height = hgt); }, { fireImmediately: true } ); @@ -137,7 +129,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); } getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) { - let height = () => this.getDocHeight(layoutDoc, this.singleColumn ? this.Sections.size : 1); + let height = () => this.getDocHeight(layoutDoc); let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); return doc) { previewScript={undefined}> ; } - getDocHeight(d: Doc, columnScale: number = 1) { + getDocHeight(d: Doc) { let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (!d.ignoreAspect && nw && nh) { let aspect = nw && nh ? nh / nw : 1; - let wid = d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(d[WidthSym](), this.columnWidth / columnScale); + let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); + if (!(d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(d[WidthSym](), wid); return wid * aspect; } return d[HeightSym](); @@ -251,15 +244,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } headings = () => Array.from(this.Sections.keys()); - section = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - if (!this.singleColumn) return this.sectionMasonry(heading, docList); + sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { let key = this.sectionFilter; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; let types = docList.length ? docList.map(d => typeof d[key]) : this.childDocs.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { type = types[0]; } - let cols = () => this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, + let cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); return doc) { translate(offset[0], offset[1]). scale(NumCast(doc.width, 1) / this.columnWidth); } - children(docs: Doc[]) { + masonryChildren(docs: Doc[]) { this._docXfs.length = 0; return docs.map((d, i) => { + let dref = React.createRef(); let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); let width = () => (d.nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth);/// (uniqueHeadings.length + 1); let height = () => this.getDocHeight(layoutDoc); - let dref = React.createRef(); let dxf = () => this.getDocTransform(layoutDoc, dref.current!); let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); this._docXfs.push({ dxf: dxf, width: width, height: height }); @@ -302,8 +294,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { sectionMasonry(heading: SchemaHeaderField | undefined, docList: Doc[]) { let cols = Math.max(1, Math.min(docList.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); - let templatecols = ""; - for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return
{!heading ? (null) :
@@ -314,10 +304,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { padding: `${this.yMargin}px ${this.xMargin}px`, width: `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`, gridGap: this.gridGap, - gridTemplateColumns: templatecols, - }} - > - {this.children(docList)} + gridTemplateColumns: numberRange(cols).reduce((list, i) => list + ` ${this.columnWidth}px`, ""), + }}> + {this.masonryChildren(docList)} {this.columnDragger}
; @@ -356,7 +345,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } render() { - let headings = Array.from(this.Sections.keys()); let editableViewProps = { GetValue: () => "", SetValue: this.addGroup, @@ -364,18 +352,16 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }; Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); - // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let sections = (this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc) : [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]) return ( -
e.stopPropagation()} > - {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc). - map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) : - this.section(undefined, this.filteredChildren)} - {(this.sectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')) ? + {sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]))} + {!this.showAddAGroup ? (null) :
+ style={{ width: this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> -
: null} +
} {this.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? { - let headings = this.props.headings(); - let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d); - let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(d[WidthSym](), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1); - let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1); + let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns); + let height = () => parent.getDocHeight(pair.layout); let dref = React.createRef(); - // if (uniqueHeadings.length > 0) { let dxf = () => this.getDocTransform(pair.layout, dref.current!); this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // } - // else { - // //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. - // let dxf = () => this.getDocTransform(layoutDoc, i, width()); - // this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // } - let rowHgtPcnt = height(); let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap); - let style = parent.singleColumn ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` }; - return
+ let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; + return
{this.props.parent.getDisplayDoc(pair.layout, pair.data, dxf, width)}
; - // } else { - // let dref = React.createRef(); - // let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - // this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // let rowHgtPcnt = height(); - // let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap); - // let divStyle = parent.singleColumn ? { width: width(), marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` }; - // return
- // {this.props.parent.getDisplayDoc(layoutDoc, d, dxf, width)} - //
; - // } }); } @@ -278,7 +254,7 @@ export class CollectionStackingViewFieldColumn extends React.Component headings.indexOf(i) === idx); let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; let headerEditableViewProps = { @@ -326,7 +302,7 @@ export class CollectionStackingViewFieldColumn extends React.Component}
: (null); - for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `; + for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `; return (
@@ -348,7 +324,7 @@ export class CollectionStackingViewFieldColumn extends React.Component {(this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ?
+ style={{ width: style.columnWidth / style.numGroupColumns }}>
: null}
-- cgit v1.2.3-70-g09d2 From 6c2d425d3724dc4742cd2a844a6e28c4d580b319 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 14 Aug 2019 14:03:10 -0400 Subject: added collapsible headers for masonry view --- .../views/collections/CollectionStackingView.tsx | 26 +++++++++++++--------- src/new_fields/SchemaHeaderField.ts | 14 +++++++++--- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4e49e368b..5713cc770 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -291,24 +291,28 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } + @observable _headingsHack: number = 1; sectionMasonry(heading: SchemaHeaderField | undefined, docList: Doc[]) { let cols = Math.max(1, Math.min(docList.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); return
{!heading ? (null) : -
+
this._headingsHack++ && heading.setCollapsed(!heading.collapsed))} > {heading.heading}
} -
list + ` ${this.columnWidth}px`, ""), - }}> - {this.masonryChildren(docList)} - {this.columnDragger} -
+ {this._headingsHack && heading && heading.collapsed ? (null) : +
list + ` ${this.columnWidth}px`, ""), + }}> + {this.masonryChildren(docList)} + {this.columnDragger} +
+ }
; } diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts index 23605cfb0..7494c9bd1 100644 --- a/src/new_fields/SchemaHeaderField.ts +++ b/src/new_fields/SchemaHeaderField.ts @@ -1,8 +1,8 @@ import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, createSimpleSchema, primitive } from "serializr"; +import { serializable, primitive } from "serializr"; import { ObjectField } from "./ObjectField"; import { Copy, ToScriptString, OnUpdate } from "./FieldSymbols"; -import { scriptingGlobal, Scripting } from "../client/util/Scripting"; +import { scriptingGlobal } from "../client/util/Scripting"; import { ColumnType } from "../client/views/collections/CollectionSchemaView"; export const PastelSchemaPalette = new Map([ @@ -53,9 +53,11 @@ export class SchemaHeaderField extends ObjectField { @serializable(primitive()) width: number; @serializable(primitive()) + collapsed: boolean | undefined; + @serializable(primitive()) desc: boolean | undefined; // boolean determines sort order, undefined when no sort - constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean) { + constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) { super(); this.heading = heading; @@ -63,6 +65,7 @@ export class SchemaHeaderField extends ObjectField { this.type = type ? type : 0; this.width = width ? width : -1; this.desc = desc; + this.collapsed = collapsed; } setHeading(heading: string) { @@ -90,6 +93,11 @@ export class SchemaHeaderField extends ObjectField { this[OnUpdate](); } + setCollapsed(collapsed: boolean | undefined) { + this.collapsed = collapsed; + this[OnUpdate](); + } + [Copy]() { return new SchemaHeaderField(this.heading, this.color, this.type); } -- cgit v1.2.3-70-g09d2