From 3442776999d1d7b7bced9bbed601ead637a43cc7 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 10:24:37 -0400 Subject: merged stacking sections branch. --- .../views/collections/CollectionStackingView.tsx | 247 --------------------- 1 file changed, 247 deletions(-) delete mode 100644 src/client/views/collections/CollectionStackingView.tsx (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx deleted file mode 100644 index 6d9e942c9..000000000 --- a/src/client/views/collections/CollectionStackingView.tsx +++ /dev/null @@ -1,247 +0,0 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction, untracked, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; -import { ContextMenu } from "../ContextMenu"; -import { CollectionSchemaPreview } from "./CollectionSchemaView"; -import "./CollectionStackingView.scss"; -import { CollectionSubView } from "./CollectionSubView"; -import { undoBatch } from "../../util/UndoManager"; -import { DragManager } from "../../util/DragManager"; -import { DocumentType } from "../../documents/Documents"; -import { Transform } from "../../util/Transform"; -import { CursorProperty } from "csstype"; - -@observer -export class CollectionStackingView extends CollectionSubView(doc => doc) { - _masonryGridRef: HTMLDivElement | null = null; - _draggerRef = React.createRef(); - _heightDisposer?: IReactionDisposer; - _gridSize = 1; - _docXfs: any[] = []; - @observable private cursor: CursorProperty = "grab"; - @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); } - - componentDidMount() { - this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => this.singleColumn && - (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) - , { fireImmediately: true }); - } - componentWillUnmount() { - if (this._heightDisposer) this._heightDisposer(); - } - - @action - moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { - return this.props.removeDocument(doc) && addDocument(doc); - } - createRef = (ele: HTMLDivElement | null) => { - this._masonryGridRef = ele; - this.createDropTarget(ele!); - } - - overlays = (doc: Doc) => { - return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {}; - } - - getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { - let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.getDocHeight(layoutDoc); - let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); - return - ; - } - getDocHeight(d: Doc) { - let nw = NumCast(d.nativeWidth); - let nh = NumCast(d.nativeHeight); - let aspect = nw && nh ? nh / nw : 1; - let wid = Math.min(d[WidthSym](), this.columnWidth); - return (nw && nh) ? wid * aspect : d[HeightSym](); - } - - - offsetTransform(doc: Doc, translateX: number, translateY: number) { - let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); - } - getDocTransform(doc: Doc, dref: HTMLDivElement) { - let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); - return this.offsetTransform(doc, translateX, translateY); - } - getSingleDocTransform(doc: Doc, ind: number, width: number) { - let localY = this.filteredChildren.reduce((height, d, i) => - height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); - let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY); - return this.offsetTransform(doc, translate[0], translate[1]); - } - - @computed - get children() { - this._docXfs.length = 0; - return this.filteredChildren.map((d, i) => { - let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.getDocHeight(layoutDoc); - if (this.singleColumn) { - let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100; - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } else { - let dref = React.createRef(); - let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } - }); - } - - _columnStart: number = 0; - columnDividerDown = (e: React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - runInAction(() => this.cursor = "grabbing"); - document.addEventListener("pointermove", this.onDividerMove); - document.addEventListener('pointerup', this.onDividerUp); - this._columnStart = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; - } - @action - onDividerMove = (e: PointerEvent): void => { - let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; - let delta = dragPos - this._columnStart; - this._columnStart = dragPos; - - this.props.Document.columnWidth = this.columnWidth + delta; - } - - @action - onDividerUp = (e: PointerEvent): void => { - runInAction(() => this.cursor = "grab"); - document.removeEventListener("pointermove", this.onDividerMove); - document.removeEventListener('pointerup', this.onDividerUp); - } - - @computed get columnDragger() { - return
- -
; - } - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ - description: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" - }); - } - } - - @undoBatch - @action - drop = (e: Event, de: DragManager.DropEvent) => { - let targInd = -1; - let where = [de.x, de.y]; - if (de.data instanceof DragManager.DocumentDragData) { - this._docXfs.map((cd, i) => { - let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); - if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { - targInd = i; - } - }); - } - if (super.drop(e, de)) { - let newDoc = de.data.droppedDocuments[0]; - let docs = this.childDocList; - if (docs) { - if (targInd === -1) targInd = docs.length; - else targInd = docs.indexOf(this.filteredChildren[targInd]); - let srcInd = docs.indexOf(newDoc); - docs.splice(srcInd, 1); - docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); - } - } - return false; - } - @undoBatch - @action - onDrop = (e: React.DragEvent): void => { - let where = [e.clientX, e.clientY]; - let targInd = -1; - this._docXfs.map((cd, i) => { - let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); - if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { - targInd = i; - } - }); - super.onDrop(e, {}, () => { - if (targInd !== -1) { - let newDoc = this.childDocs[this.childDocs.length - 1]; - let docs = this.childDocList; - if (docs) { - docs.splice(docs.length - 1, 1); - docs.splice(targInd, 0, newDoc); - } - } - }); - } - render() { - let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.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 ( -
e.stopPropagation()} > -
- {this.children} - {this.singleColumn ? (null) : this.columnDragger} -
-
- ); - } -} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 090d0b67dcc5148ecfbfac01cd9f1ddd3a52d8a7 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 13:16:57 -0400 Subject: fixed missing stacking view. made titles editable. --- src/client/views/EditableView.scss | 1 + src/client/views/EditableView.tsx | 1 + .../views/collections/CollectionStackingView.tsx | 247 +++++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 11 +- 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 src/client/views/collections/CollectionStackingView.tsx (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss index dfa110f8d..a5150cd66 100644 --- a/src/client/views/EditableView.scss +++ b/src/client/views/EditableView.scss @@ -17,4 +17,5 @@ } .editableView-input { width: 100%; + background: inherit; } \ No newline at end of file diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 989fb1be9..f2cdffd38 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -67,6 +67,7 @@ export class EditableView extends React.Component { @action onClick = (e: React.MouseEvent) => { + e.nativeEvent.stopPropagation(); if (!this.props.onClick || !this.props.onClick(e)) { this._editing = true; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx new file mode 100644 index 000000000..6d9e942c9 --- /dev/null +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -0,0 +1,247 @@ +import React = require("react"); +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed, IReactionDisposer, reaction, untracked, observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { BoolCast, NumCast, Cast } from "../../../new_fields/Types"; +import { emptyFunction, Utils } from "../../../Utils"; +import { ContextMenu } from "../ContextMenu"; +import { CollectionSchemaPreview } from "./CollectionSchemaView"; +import "./CollectionStackingView.scss"; +import { CollectionSubView } from "./CollectionSubView"; +import { undoBatch } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; +import { DocumentType } from "../../documents/Documents"; +import { Transform } from "../../util/Transform"; +import { CursorProperty } from "csstype"; + +@observer +export class CollectionStackingView extends CollectionSubView(doc => doc) { + _masonryGridRef: HTMLDivElement | null = null; + _draggerRef = React.createRef(); + _heightDisposer?: IReactionDisposer; + _gridSize = 1; + _docXfs: any[] = []; + @observable private cursor: CursorProperty = "grab"; + @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); } + + componentDidMount() { + this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], + () => this.singleColumn && + (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => + height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) + , { fireImmediately: true }); + } + componentWillUnmount() { + if (this._heightDisposer) this._heightDisposer(); + } + + @action + moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { + return this.props.removeDocument(doc) && addDocument(doc); + } + createRef = (ele: HTMLDivElement | null) => { + this._masonryGridRef = ele; + this.createDropTarget(ele!); + } + + overlays = (doc: Doc) => { + return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {}; + } + + getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { + let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; + let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; + let height = () => this.getDocHeight(layoutDoc); + let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); + return + ; + } + getDocHeight(d: Doc) { + let nw = NumCast(d.nativeWidth); + let nh = NumCast(d.nativeHeight); + let aspect = nw && nh ? nh / nw : 1; + let wid = Math.min(d[WidthSym](), this.columnWidth); + return (nw && nh) ? wid * aspect : d[HeightSym](); + } + + + offsetTransform(doc: Doc, translateX: number, translateY: number) { + let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); + } + getDocTransform(doc: Doc, dref: HTMLDivElement) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + return this.offsetTransform(doc, translateX, translateY); + } + getSingleDocTransform(doc: Doc, ind: number, width: number) { + let localY = this.filteredChildren.reduce((height, d, i) => + height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); + let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY); + return this.offsetTransform(doc, translate[0], translate[1]); + } + + @computed + get children() { + this._docXfs.length = 0; + return this.filteredChildren.map((d, i) => { + let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); + let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; + let height = () => this.getDocHeight(layoutDoc); + if (this.singleColumn) { + let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); + let rowHgtPcnt = height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100; + this._docXfs.push({ dxf: dxf, width: width, height: height }); + return
+ {this.getDisplayDoc(layoutDoc, d, dxf)} +
; + } else { + let dref = React.createRef(); + let dxf = () => this.getDocTransform(layoutDoc, dref.current!); + let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + this._docXfs.push({ dxf: dxf, width: width, height: height }); + return
+ {this.getDisplayDoc(layoutDoc, d, dxf)} +
; + } + }); + } + + _columnStart: number = 0; + columnDividerDown = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + runInAction(() => this.cursor = "grabbing"); + document.addEventListener("pointermove", this.onDividerMove); + document.addEventListener('pointerup', this.onDividerUp); + this._columnStart = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; + } + @action + onDividerMove = (e: PointerEvent): void => { + let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; + let delta = dragPos - this._columnStart; + this._columnStart = dragPos; + + this.props.Document.columnWidth = this.columnWidth + delta; + } + + @action + onDividerUp = (e: PointerEvent): void => { + runInAction(() => this.cursor = "grab"); + document.removeEventListener("pointermove", this.onDividerMove); + document.removeEventListener('pointerup', this.onDividerUp); + } + + @computed get columnDragger() { + return
+ +
; + } + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ + description: "Toggle multi-column", + event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" + }); + } + } + + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + let targInd = -1; + let where = [de.x, de.y]; + if (de.data instanceof DragManager.DocumentDragData) { + this._docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }); + } + if (super.drop(e, de)) { + let newDoc = de.data.droppedDocuments[0]; + let docs = this.childDocList; + if (docs) { + if (targInd === -1) targInd = docs.length; + else targInd = docs.indexOf(this.filteredChildren[targInd]); + let srcInd = docs.indexOf(newDoc); + docs.splice(srcInd, 1); + docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); + } + } + return false; + } + @undoBatch + @action + onDrop = (e: React.DragEvent): void => { + let where = [e.clientX, e.clientY]; + let targInd = -1; + this._docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }); + super.onDrop(e, {}, () => { + if (targInd !== -1) { + let newDoc = this.childDocs[this.childDocs.length - 1]; + let docs = this.childDocList; + if (docs) { + docs.splice(docs.length - 1, 1); + docs.splice(targInd, 0, newDoc); + } + } + }); + } + render() { + let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.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 ( +
e.stopPropagation()} > +
+ {this.children} + {this.singleColumn ? (null) : this.columnDragger} +
+
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1c03bfc81..e0975f7bd 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -37,6 +37,7 @@ import { RouteStore } from '../../../server/RouteStore'; import { FormattedTextBox } from './FormattedTextBox'; import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; +import { EditableView } from '../EditableView'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -287,6 +288,7 @@ export class DocumentView extends DocComponent(Docu } onClick = async (e: React.MouseEvent) => { + if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing. e.stopPropagation(); let altKey = e.altKey; let ctrlKey = e.ctrlKey; @@ -664,10 +666,17 @@ export class DocumentView extends DocComponent(Docu {!showTitle ? (null) :
- {this.props.Document[showTitle]} + StrCast(this.props.Document[showTitle])} + SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle] = value) ? true : true} + />
} {!showCaption ? (null) : -- cgit v1.2.3-70-g09d2 From a4820fade4149196ecbe8e30de31f7b8e6b5057f Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 13:28:27 -0400 Subject: what's up with StackingView - bad merge? --- .../views/collections/CollectionStackingView.tsx | 89 ++++++++++++---------- 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6d9e942c9..0e5f9a321 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,9 +4,8 @@ import { action, computed, IReactionDisposer, reaction, untracked, observable, r import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast } from "../../../new_fields/Types"; +import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, Utils } from "../../../Utils"; -import { ContextMenu } from "../ContextMenu"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @@ -21,8 +20,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _heightDisposer?: IReactionDisposer; - _gridSize = 1; _docXfs: any[] = []; + _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @@ -31,15 +30,25 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @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 Sections() { + let sectionFilter = StrCast(this.props.Document.sectionFilter); + let fields = new Map(); + sectionFilter && this.filteredChildren.map(d => { + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; + if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); + else fields.get(sectionValue)!.push(d); + }); + return fields; + } componentDidMount() { this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], () => this.singleColumn && - (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => + (this.props.Document.height = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) , { fireImmediately: true }); } componentWillUnmount() { - if (this._heightDisposer) this._heightDisposer(); + this._heightDisposer && this._heightDisposer(); } @action @@ -87,7 +96,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return (nw && nh) ? wid * aspect : d[HeightSym](); } - offsetTransform(doc: Doc, translateX: number, translateY: number) { let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); @@ -97,6 +105,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); return this.offsetTransform(doc, translateX, translateY); } + getSingleDocTransform(doc: Doc, ind: number, width: number) { let localY = this.filteredChildren.reduce((height, d, i) => height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); @@ -104,24 +113,24 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.offsetTransform(doc, translate[0], translate[1]); } - @computed - get children() { + children(docs: Doc[]) { this._docXfs.length = 0; - return this.filteredChildren.map((d, i) => { + return docs.map((d, i) => { let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => this.getDocHeight(layoutDoc); if (this.singleColumn) { + //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100; + let rowHgtPcnt = height(); this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
+ return
{this.getDisplayDoc(layoutDoc, d, dxf)}
; } else { let dref = React.createRef(); let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); this._docXfs.push({ dxf: dxf, width: width, height: height }); return
{this.getDisplayDoc(layoutDoc, d, dxf)} @@ -130,7 +139,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } - _columnStart: number = 0; columnDividerDown = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -144,7 +152,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; let delta = dragPos - this._columnStart; this._columnStart = dragPos; - this.props.Document.columnWidth = this.columnWidth + delta; } @@ -160,14 +167,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; } - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ - description: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" - }); - } - } @undoBatch @action @@ -219,28 +218,40 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } }); } - render() { + section(heading: string, docList: Doc[]) { let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.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 ?
{heading}
: (null)} +
+ {this.children(docList)} + {this.singleColumn ? (null) : this.columnDragger} +
; + } + render() { return ( -
e.stopPropagation()} > -
- {this.children} - {this.singleColumn ? (null) : this.columnDragger} -
+
e.stopPropagation()} > + {/* {sectionFilter as boolean ? [ + ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], + ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], + ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()). + map(section => this.section(section[0].toString(), section[1] as Doc[])) : + this.section("", this.filteredChildren)}
); } -- cgit v1.2.3-70-g09d2