diff options
Diffstat (limited to 'src/client/views/collections/CollectionStackingViewFieldColumn.tsx')
-rw-r--r-- | src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 223 |
1 files changed, 85 insertions, 138 deletions
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 389b449b5..70ec1f925 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -2,9 +2,8 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt } from "../../../fields/Doc"; import { RichTextField } from "../../../fields/RichTextField"; -import { listSpec } from "../../../fields/Schema"; import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; @@ -20,7 +19,6 @@ import { undoBatch } from "../../util/UndoManager"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; -import { CollectionStackingView } from "./CollectionStackingView"; import "./CollectionStackingView.scss"; import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; import { Id } from "../../../fields/FieldSymbols"; @@ -29,13 +27,22 @@ export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; interface CSVFieldColumnProps { - cols: () => number; - headings: () => object[]; + Document: Doc; + DataDoc: Opt<Doc>; + docList: Doc[]; heading: string; + pivotField: string; + chromeStatus: string; + columnHeaders: SchemaHeaderField[] | undefined; headingObject: SchemaHeaderField | undefined; - docList: Doc[]; - parent: CollectionStackingView; + yMargin: number; + columnWidth: number; + numGroupColumns: number; + gridGap: number; type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; + headings: () => object[]; + renderChildren: (docs: Doc[]) => JSX.Element[]; + addDocument: (doc: Doc | Doc[]) => boolean; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; observeHeight: (myref: any) => void; @@ -68,39 +75,25 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC @undoBatch columnDrop = action((e: Event, de: DragManager.DropEvent) => { - if (de.complete.docDragData) { - const key = StrCast(this.props.parent.props.Document._pivotField); - const castedValue = this.getValue(this._heading); - de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false)); - this.props.parent.onInternalDrop(e, de); - e.stopPropagation(); - } + const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; + drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false)); }); getValue = (value: string): any => { const parsed = parseInt(value); - if (!isNaN(parsed)) { - return parsed; - } - if (value.toLowerCase().indexOf("true") > -1) { - return true; - } - if (value.toLowerCase().indexOf("false") > -1) { - return false; - } + if (!isNaN(parsed)) return parsed; + if (value.toLowerCase().indexOf("true") > -1) return true; + if (value.toLowerCase().indexOf("false") > -1) return false; return value; } @action headingChanged = (value: string, shiftDown?: boolean) => { - const key = StrCast(this.props.parent.props.Document._pivotField); const castedValue = this.getValue(value); if (castedValue) { - if (this.props.parent.columnHeaders) { - if (this.props.parent.columnHeaders.map(i => i.heading).indexOf(castedValue.toString()) > -1) { - return false; - } + if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { + return false; } - this.props.docList.forEach(d => d[key] = castedValue); + this.props.docList.forEach(d => d[this.props.pivotField] = castedValue); if (this.props.headingObject) { this.props.headingObject.setHeading(castedValue.toString()); this._heading = this.props.headingObject.heading; @@ -112,33 +105,18 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC @action changeColumnColor = (color: string) => { - if (this.props.headingObject) { - this.props.headingObject.setColor(color); - this._color = color; - } - } - - @action - pointerEntered = () => { - if (SnappingManager.GetIsDragging()) { - this._background = "#b4b4b4"; - } - } - - @action - pointerLeave = () => { - this._background = "inherit"; + this.props.headingObject?.setColor(color); + this._color = color; } - @action - textCallback = (char: string) => { - return this.addDocument("", false, true); - } + @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4"); + @action pointerLeave = () => this._background = "inherit"; + textCallback = (char: string) => this.addNewTextDoc("", false, true); @action - addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { + addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { if (!value && !forceEmptyNote) return false; - const key = StrCast(this.props.parent.props.Document._pivotField); + const key = this.props.pivotField; const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true }); newDoc[key] = this.getValue(this.props.heading); const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); @@ -146,39 +124,33 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC newDoc.heading = heading; FormattedTextBox.SelectOnLoad = newDoc[Id]; FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? "" : " "; - return this.props.parent.addDocument?.(newDoc) || false; + return this.props.addDocument?.(newDoc) || false; } @action deleteColumn = () => { - const key = StrCast(this.props.parent.props.Document._pivotField); - this.props.docList.forEach(d => d[key] = undefined); - if (this.props.parent.columnHeaders && this.props.headingObject) { - const index = this.props.parent.columnHeaders.indexOf(this.props.headingObject); - this.props.parent.columnHeaders.splice(index, 1); + this.props.docList.forEach(d => d[this.props.pivotField] = undefined); + if (this.props.columnHeaders && this.props.headingObject) { + const index = this.props.columnHeaders.indexOf(this.props.headingObject); + this.props.columnHeaders.splice(index, 1); } } @action collapseSection = () => { - if (this.props.headingObject) { - this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed); - this.toggleVisibility(); - } + this.props.headingObject?.setCollapsed(!this.props.headingObject.collapsed); + this.toggleVisibility(); } - headerDown = (e: React.PointerEvent<HTMLDivElement>) => { - setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); - } + headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); startDrag = (e: PointerEvent, down: number[], delta: number[]) => { - const alias = Doc.MakeAlias(this.props.parent.props.Document); - alias._width = this.props.parent.props.PanelWidth() / (Cast(this.props.parent.columnHeaders, listSpec(SchemaHeaderField))?.length || 1); + const alias = Doc.MakeAlias(this.props.Document); + alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1); alias._pivotField = undefined; - const key = StrCast(this.props.parent.props.Document._pivotField); let value = this.getValue(this._heading); value = typeof value === "string" ? `"${value}"` : value; - alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name }); + alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name }); if (alias.viewSpecScript) { DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY); return true; @@ -187,43 +159,25 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } renderColorPicker = () => { - const selected = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - - const pink = PastelSchemaPalette.get("pink2"); - const purple = PastelSchemaPalette.get("purple4"); - const blue = PastelSchemaPalette.get("bluegreen1"); - const yellow = PastelSchemaPalette.get("yellow4"); - const red = PastelSchemaPalette.get("red2"); - const green = PastelSchemaPalette.get("bluegreen7"); - const cyan = PastelSchemaPalette.get("bluegreen5"); - const orange = PastelSchemaPalette.get("orange1"); const gray = "#f1efeb"; - - return ( - <div className="collectionStackingView-colorPicker"> - <div className="colorOptions"> - <div className={"colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div> - <div className={"colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div> - <div className={"colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div> - <div className={"colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div> - <div className={"colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div> - <div className={"colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div> - <div className={"colorPicker" + (selected === green ? " active" : "")} style={{ backgroundColor: green }} onClick={() => this.changeColumnColor(green!)}></div> - <div className={"colorPicker" + (selected === cyan ? " active" : "")} style={{ backgroundColor: cyan }} onClick={() => this.changeColumnColor(cyan!)}></div> - <div className={"colorPicker" + (selected === orange ? " active" : "")} style={{ backgroundColor: orange }} onClick={() => this.changeColumnColor(orange!)}></div> - </div> + const selected = this.props.headingObject ? this.props.headingObject.color : gray; + const colors = ["pink2", "purple4", "bluegreen1", "yellow4", "gray", "red2", "bluegreen7", "bluegreen5", "orange1"]; + return <div className="collectionStackingView-colorPicker"> + <div className="colorOptions"> + {colors.map(col => { + const palette = PastelSchemaPalette.get(col); + return <div className={"colorPicker" + (selected === palette ? " active" : "")} style={{ backgroundColor: palette }} onClick={() => this.changeColumnColor(palette!)} /> + })} </div> - ); + </div>; } renderMenu = () => { - return ( - <div className="collectionStackingView-optionPicker"> - <div className="optionOptions"> - <div className={"optionPicker" + (true ? " active" : "")} onClick={action(() => { })}>Add options here</div> - </div> - </div > - ); + return <div className="collectionStackingView-optionPicker"> + <div className="optionOptions"> + <div className={"optionPicker" + (true ? " active" : "")} onClick={action(() => { })}>Add options here</div> + </div> + </div >; } @observable private collapsed: boolean = false; @@ -234,22 +188,22 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC ContextMenu.Instance.clearItems(); const layoutItems: ContextMenuProps[] = []; const docItems: ContextMenuProps[] = []; - const dataDoc = this.props.parent.props.DataDoc || this.props.parent.Document; + const dataDoc = this.props.DataDoc || this.props.Document; DocUtils.addDocumentCreatorMenuItems((doc) => { FormattedTextBox.SelectOnLoad = doc[Id]; - return this.props.parent.props.addDocument?.(doc) || false; - }, this.props.parent.props.addDocument || returnFalse, x, y, true); + return this.props.addDocument?.(doc); + }, this.props.addDocument, x, y, true); Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof (dataDoc[fieldKey]) === "string").map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => { - const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.parent.props.Document)); + const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document)); if (created) { - if (this.props.parent.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document); + if (this.props.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.Document); } - return this.props.parent.props.addDocument?.(created) || false; + return this.props.addDocument?.(created); } }, icon: "compress-arrows-alt" })); @@ -258,25 +212,25 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC description: ":" + fieldKey, event: () => { const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); if (created) { - const container = this.props.parent.Document.resolvedDataDoc ? Doc.GetProto(this.props.parent.Document) : this.props.parent.Document; + const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document; if (container.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(created, container); return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created); } - return this.props.parent.props.addDocument?.(created) || false; + return this.props.addDocument?.(created) || false; } }, icon: "compress-arrows-alt" })); !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Doc Fields ...", subitems: docItems, icon: "eye" }); !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Containers ...", subitems: layoutItems, icon: "eye" }); ContextMenu.Instance.setDefaultItem("::", (name: string): void => { - Doc.GetProto(this.props.parent.props.Document)[name] = ""; + Doc.GetProto(this.props.Document)[name] = ""; const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true }); if (created) { - if (this.props.parent.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document); + if (this.props.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.Document); } - this.props.parent.props.addDocument?.(created); + this.props.addDocument?.(created); } }); const pt = this.props.screenToLocalTransform().inverse().transformPoint(x, y); @@ -284,23 +238,19 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } @computed get innards() { TraceMobx(); - const cols = this.props.cols(); - const key = StrCast(this.props.parent.props.Document._pivotField); - let templatecols = ""; + const key = this.props.pivotField; const headings = this.props.headings(); const heading = this._heading; - const style = this.props.parent; - const singleColumn = style.isStackingView; - const columnYMargin = this.props.headingObject ? 0 : NumCast(this.props.parent.yMargin, 5); + const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin; const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); const evContents = heading ? heading : this.props?.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; const headingView = this.props.headingObject ? <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef} style={{ - marginTop: NumCast(this.props.parent.yMargin, 5), - width: (style.columnWidth) / + marginTop: this.props.yMargin, + width: (this.props.columnWidth) / ((uniqueHeadings.length + - ((this.props.parent.chromeStatus !== 'view-mode' && this.props.parent.chromeStatus) ? 1 : 0)) || 1) + ((this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus) ? 1 : 0)) || 1) }}> <div className={"collectionStackingView-collapseBar" + (this.props.headingObject.collapsed === true ? " active" : "")} onClick={this.collapseSection}></div> {/* the default bucket (no key value) has a tooltip that describes what it is. @@ -337,34 +287,32 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } </div> </div> : (null); - for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `; - const chromeStatus = this.props.parent.chromeStatus; - const type = this.props.parent.props.Document.type; + const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; + const type = this.props.Document.type; return <> - {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView} + {this.props.Document._columnsHideIfEmpty ? (null) : headingView} { this.collapsed ? (null) : <div> - <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`} + <div key={`${heading}-stack`} className={`collectionStackingView-masonrySingle`} style={{ - padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`, + padding: `${columnYMargin}px ${0}px ${this.props.yMargin}px ${0}px`, margin: "auto", width: "max-content", //singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`, height: 'max-content', position: "relative", - gridGap: style.gridGap, - gridTemplateColumns: singleColumn ? undefined : templatecols, - gridAutoRows: singleColumn ? undefined : "0px" + gridGap: this.props.gridGap, + gridTemplateColumns: templatecols, + gridAutoRows: "0px" }}> - {this.props.parent.children(this.props.docList, uniqueHeadings.length)} - {singleColumn ? (null) : this.props.parent.columnDragger} + {this.props.renderChildren(this.props.docList)} </div> - {(chromeStatus !== 'view-mode' && chromeStatus && type !== DocumentType.PRES) ? + {(this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus && type !== DocumentType.PRES) ? <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" - style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 10 }}> + style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10 }}> <EditableView GetValue={returnEmptyString} - SetValue={this.addDocument} + SetValue={this.addNewTextDoc} textCallback={this.textCallback} contents={"+ NEW"} toggle={this.toggleVisibility} @@ -381,11 +329,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC const headings = this.props.headings(); const heading = this._heading; const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); - const chromeStatus = this.props.parent.props.Document._chromeStatus; return ( <div className={"collectionStackingViewFieldColumn" + (SnappingManager.GetIsDragging() ? "Dragging" : "")} key={heading} style={{ - width: `${100 / ((uniqueHeadings.length + ((chromeStatus !== 'view-mode' && chromeStatus) ? 1 : 0)) || 1)}%`, + width: `${100 / ((uniqueHeadings.length + ((this.props.chromeStatus !== 'view-mode' && this.props.chromeStatus) ? 1 : 0)) || 1)}%`, height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined, background: this._background }} |