diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionNoteTakingView.tsx | 904 | ||||
-rw-r--r-- | src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx | 409 |
2 files changed, 1200 insertions, 113 deletions
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 3fd63d245..0d1f55fed 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -18,47 +18,44 @@ import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; +import { EditableView } from "../EditableView"; import { LightboxView } from "../LightboxView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView"; import { StyleProp } from "../StyleProvider"; -import { CollectionNoteTakingViewFieldColumn } from "./CollectionNoteTakingViewFieldColumn"; +import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; -import internal = require("events"); +import { CollectionNoteTakingViewFieldColumn } from "./CollectionNoteTakingViewFieldColumn"; const _global = (window /* browser */ || global /* node */) as any; + export type collectionNoteTakingViewProps = { chromeHidden?: boolean; + // view type is stacking viewType?: CollectionViewType; NativeWidth?: () => number; NativeHeight?: () => number; }; -//TODO: where am I going to add columns? - @observer export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() { - // used in a column dragger, likely due for the masonry grid view. We want to use this - _draggerRef = React.createRef<HTMLDivElement>(); + //-------------------------------------------- Delete? --------------------------------------------// + // Not sure what a pivot field is. Seems like we cause reaction in MobX get rid of it once we exit this view + _pivotFieldDisposer?: IReactionDisposer; // Seems like we cause reaction in MobX get rid of our height once we exit this view _autoHeightDisposer?: IReactionDisposer; + //------------------------------------------------------------------------------------------------// + _masonryGridRef: HTMLDivElement | null = null; + // used in a column dragger, likely due for the masonry grid view. We want to use this + _draggerRef = React.createRef<HTMLDivElement>(); // keeping track of documents. Updated on internal and external drops. What's the difference? _docXfs: { height: () => number, width: () => number, stackedDocTransform: () => Transform }[] = []; - - //--------------------------------------------------------------------------------------------------------------// - // TODO: these are things that I added but not sure that they actually belong here - // We may not need to actually keep track of the numColumns - _noteTakingRef: HTMLDivElement | null = null; - // this is the layout doc field that we're splitting on. Replaces pivot field - _columnIndex: string = "columnIndex"; - @computed get columnIndex() { return this._columnIndex} - _numColumns: number = 1; - @computed get numColumns() { return this._numColumns} - @computed get columnWidth() { return this.props.PanelWidth() - 2 * this.xMargin } - //--------------------------------------------------------------------------------------------------------------// - + // Doesn't look like this field is being used anywhere. Obsolete? + _columnStart: number = 0; + // map of node headers to their heights. Used in Masonry + @observable _heightMap = new Map<string, number>(); // Assuming that this is the current css cursor style @observable _cursor: CursorProperty = "grab"; // gets reset whenever we scroll. Not sure what it is @@ -67,6 +64,9 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); } // it looks like this gets the column headers that Mehek was showing just now @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); } + // Still not sure what a pivot is, but it appears that we can actually filter docs somehow? + // @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); } + @computed get pivotField() { return "Col" } // filteredChildren is what you want to work with. It's the list of things that you're currently displaying @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); } // how much margin we give the header @@ -74,6 +74,17 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); } + // are we stacking or masonry? + @computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking || (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.NoteTaking; } + // this is the number of StackingViewFieldColumns that we have + @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } + // reveals a button to add a group in masonry view + @computed get showAddAGroup() { return this.pivotField && !this.chromeHidden; } + // columnWidth handles the margin on the left and right side of the documents + @computed get columnWidth() { + return Math.min(this.props.PanelWidth() - 2 * this.xMargin, + this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250)); + } @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } @@ -81,36 +92,41 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti super(props); if (this.columnHeaders === undefined) { - this.layoutDoc._columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("0")]); + // TODO: what is a layout doc? Is it literally how this document is supposed to be layed out? + // here we're making an empty list of column headers (again, what Mehek showed us) + this.layoutDoc._columnHeaders = new List<SchemaHeaderField>(); } - console.log(this.layoutDoc._columnHeaders) } + // TODO: plj - these are the children children = (docs: Doc[]) => { + //TODO: can somebody explain me to what exactly TraceMobX is? TraceMobx(); + // appears that we are going to reset the _docXfs. TODO: what is Xfs? this._docXfs.length = 0; - // Go through each of the documents that are contained return docs.map((d, i) => { - if (d._columnIndex && parseInt(d._columnIndex.toString()) + 1 > this.numColumns) { - this._numColumns = parseInt(d._columnIndex.toString()) + 1; - } else if (d._columnIndex === undefined) { - d._columnIndex = 0; - } const height = () => this.getDocHeight(d); const width = () => this.getDocWidth(d); + // assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns + const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); // just getting the style - const style = { width: width(), marginTop: i ? this.gridGap : 0, height: height(), margin: this.xMargin }; + const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` }; // So we're choosing whether we're going to render a column or a masonry doc - return <div className={"collectionNoteTakingView-columnDoc"} key={d[Id]} style={style} > - {this.getDisplayDoc(d, width)} - </div> + return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} style={style} > + {this.getDisplayDoc(d, width)} + </div>; }); } + @action + setDocHeight = (key: string, sectionHeight: number) => { + this._heightMap.set(key, sectionHeight); + } - //TODO: this seems important - get Sections() { + // is sections that all collections inherit? I think this is how we show the masonry/columns + //TODO: this seems important + get Sections() { // appears that pivot field IS actually for sorting - if (!this.columnIndex || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>(); + if (!this.pivotField || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>(); if (this.columnHeaders === undefined) { setTimeout(() => this.layoutDoc._columnHeaders = new List<SchemaHeaderField>(), 0); @@ -120,18 +136,21 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti const fields = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); let changed = false; this.filteredChildren.map(d => { - const sectionValue = (d[this.columnIndex] ? d[this.columnIndex] : `NO ${this.columnIndex.toUpperCase()} VALUE`) as object; + if (!d[this.pivotField]) { + d[this.pivotField] = `0` + }; + const sectionValue = (d[this.pivotField] ? d[this.pivotField] : `0`) as object; // the next five lines ensures that floating point rounding errors don't create more than one section -syip const parsed = parseInt(sectionValue.toString()); const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; // look for if header exists already - const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.columnIndex.toUpperCase()} VALUE`)); + const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `0`)); if (existingHeader) { fields.get(existingHeader)!.push(d); } else { - const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.columnIndex.toUpperCase()} VALUE`); + const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `0`); fields.set(newSchemaHeader, [d]); columnHeaders.push(newSchemaHeader); changed = true; @@ -149,52 +168,26 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0); return fields; } - //TODO: this seems important - // get Sections() { - // // at the start, we likely will not have column headers - // if (this.columnHeaders === undefined) { - // console.log("columns weren't yet defined") - // setTimeout(() => this.layoutDoc._columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("0")])); - // return new Map<SchemaHeaderField, Doc[]>(); - // } - - // // on later renders, we should have the column headers - // const columnHeaders = Array.from(this.columnHeaders); - // console.log(columnHeaders) - // const fields = new Map<SchemaHeaderField, Doc[]>(); - // let changed = false; - // this.filteredChildren.map(d => { - // const sectionValue = (d._columnIndex ? d._columnIndex : `NO COLUMN VALUE`) as object; - // // the next five lines ensures that floating point rounding errors don't create more than one section -syip - // const parsed = parseInt(sectionValue.toString()); - // const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; - // const newSchemaHeader = new SchemaHeaderField(castedSectionValue.toString()); - // const currentDocs = fields.get(newSchemaHeader) - // if (currentDocs) { - // currentDocs.push(d) - // fields.set(newSchemaHeader, currentDocs); - // } - // const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO COLUMN VALUE`)); - // if (existingHeader) { - // columnHeaders.push(newSchemaHeader); - // changed = true; - // } - // }); - // changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0); - // return fields; - // } componentDidMount() { super.componentDidMount?.(); + // reset section headers when a new filter is inputted + this._pivotFieldDisposer = reaction( + () => this.pivotField, + () => this.layoutDoc._columnHeaders = new List() + ); + //TODO: where the heck are we getting filters from? this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), - this.headerMargin + - Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))))))); + this.headerMargin + (this.isStackingView ? + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) : + this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0))))); } componentWillUnmount() { super.componentWillUnmount(); + this._pivotFieldDisposer?.(); this._autoHeightDisposer?.(); } @@ -203,7 +196,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; } createRef = (ele: HTMLDivElement | null) => { - this._noteTakingRef = ele; + this._masonryGridRef = ele; this.createDashEventsTarget(ele!); //so the whole grid is the drop target? } @@ -326,7 +319,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti if (this.columnWidth < 150){ margin = 0; } - const maxWidth = (this.columnWidth / this.numColumns) - (margin * 2); + const maxWidth = (this.columnWidth / this.numGroupColumns) - (margin * 2); if (!this.layoutDoc._columnsFill && !(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d))) { return Math.min(d[WidthSym](), maxWidth); } @@ -340,7 +333,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0); const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0); if (nw && nh) { - const colWid = this.columnWidth / this.numColumns; + const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); return Math.min( maxHeight, @@ -369,6 +362,35 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti </div>; } + // TODO: plj + @action + onPointerOver = (e: React.PointerEvent) => { + // console.log("hovering over something") + if (DragManager.docsBeingDragged.length) { + // essentially copying code from onInternalDrop for this: + const doc = DragManager.docsBeingDragged[0]; + // console.log(doc[LayoutSym]()) + + console.log(doc[DataSym]); + console.log(Doc.IndexOf(doc, this.childDocs)); + + } + + + } + + //used in onPointerOver to swap two nodes in the rendered filtered children list + swapNodes = (i: number, j: number) => { + + } + + //plj added this + @action + onPointerDown = (e: React.PointerEvent) => { + + } + + // TODO: plj - look at this. Start with making changes to db, and then transition to client side @undoBatch @action onInternalDrop = (e: Event, de: DragManager.DropEvent) => { @@ -385,8 +407,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height()); if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { dropInd = i; - //TODO: not sure what the axis should actually be. Had a ternary previously with 0/1 - const axis = 1; + const axis = this.isStackingView ? 1 : 0; dropAfter = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0; } }); @@ -459,11 +480,13 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti refList: any[] = []; // what a section looks like if we're in stacking view sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - const key = "columnIndex"; + const key = this.pivotField; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; - const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); - if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { - type = types[0]; + if (this.pivotField) { + const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); + if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { + type = types[0]; + } } //TODO: I think that we only have one of these atm return <CollectionNoteTakingViewFieldColumn @@ -491,9 +514,9 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti DataDoc={this.props.DataDoc} renderChildren={this.children} columnWidth={this.columnWidth} - columnIndex={this._columnIndex} - numColumns={this.numColumns} + numGroupColumns={this.numGroupColumns} gridGap={this.gridGap} + pivotField={this.pivotField} key={heading?.heading ?? ""} headings={this.headings} heading={heading?.heading ?? ""} @@ -506,13 +529,55 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti />; } + // what a section looks like if we're in masonry. Shouldn't actually need to use this. + sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => { + const key = this.pivotField; + let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); + if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { + type = types[0]; + } + const rows = () => !this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, + Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); + return <CollectionMasonryViewFieldRow + showHandle={first} + Document={this.props.Document} + chromeHidden={this.chromeHidden} + pivotField={this.pivotField} + unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)} + observeHeight={(ref) => { + if (ref) { + this.refList.push(ref); + this.observer = new _global.ResizeObserver(action((entries: any) => { + if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0); + this.props.setHeight(this.headerMargin + height); + } + })); + this.observer.observe(ref); + } + }} + key={heading ? heading.heading : ""} + rows={rows} + headings={this.headings} + heading={heading ? heading.heading : ""} + headingObject={heading} + docList={docList} + parent={this} + type={type} + createDropTarget={this.createDashEventsTarget} + screenToLocalTransform={this.props.ScreenToLocalTransform} + setDocHeight={this.setDocHeight} + />; + } + @action // What are we adding a group to? addGroup = (value: string) => { if (value && this.columnHeaders) { const schemaHdrField = new SchemaHeaderField(value); this.columnHeaders.push(schemaHdrField); - DocUtils.addFieldEnumerations(undefined, this._columnIndex, [{ title: value, _backgroundColor: "schemaHdrField.color" }]); + DocUtils.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: "schemaHdrField.color" }]); return true; } return false; @@ -540,10 +605,12 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti @computed get renderedSections() { TraceMobx(); let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]; - const entries = Array.from(this.Sections.entries()); - sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries; + if (this.pivotField) { + const entries = Array.from(this.Sections.entries()); + sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries; + } // a section will have a header and a list of docs. Ok cool. - return sections.map((section, i) => this.sectionStacking(section[0], section[1])); + return sections.map((section, i) => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0)); } @computed get buttonMenu() { @@ -617,7 +684,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti } </div> : null} <div className="collectionStackingMasonry-cont" > - <div className={"collectionNoteTakingView"} + <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"} ref={this.createRef} style={{ overflowY: this.props.isContentActive() ? "auto" : "hidden", @@ -625,10 +692,29 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti pointerEvents: this.backgroundEvents ? "all" : undefined }} onScroll={action(e => this._scroll = e.currentTarget.scrollTop)} + onPointerOver={this.onPointerOver} + onPointerDown={this.onPointerDown} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} + // Todo: what is wheel? Are we talking about a mouse wheel? onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > + {/* so it appears that we are actually rendering the sections. Maybe this is what we're looking for? */} {this.renderedSections} + {/* I think that showAddGroup must be passed in as false, which is why we can't find what Mehek showed + Or it's because we aren't passing a pivot field */} + {!this.showAddAGroup ? (null) : + <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" + style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> + <EditableView {...editableViewProps} /> + </div>} + {/* {this.chromeHidden || !this.props.isSelected() ? (null) : + <Switch + onChange={this.onToggle} + onClick={this.onToggle} + defaultChecked={true} + checkedChildren="edit" + unCheckedChildren="view" + />} */} </div> </div> </> @@ -636,3 +722,643 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti ); } } + + +// import React = require("react"); +// import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +// import { CursorProperty } from "csstype"; +// import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; +// import { observer } from "mobx-react"; +// import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +// import { Id } from "../../../fields/FieldSymbols"; +// import { List } from "../../../fields/List"; +// import { listSpec } from "../../../fields/Schema"; +// import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +// import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; +// import { TraceMobx } from "../../../fields/util"; +// import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; +// import { Docs, DocUtils } from "../../documents/Documents"; +// import { DragManager, dropActionType } from "../../util/DragManager"; +// import { SnappingManager } from "../../util/SnappingManager"; +// import { Transform } from "../../util/Transform"; +// import { undoBatch } from "../../util/UndoManager"; +// import { ContextMenu } from "../ContextMenu"; +// import { ContextMenuProps } from "../ContextMenuItem"; +// import { LightboxView } from "../LightboxView"; +// import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; +// import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView"; +// import { StyleProp } from "../StyleProvider"; +// import { CollectionNoteTakingViewFieldColumn } from "./CollectionNoteTakingViewFieldColumn"; +// import "./CollectionStackingView.scss"; +// import { CollectionSubView } from "./CollectionSubView"; +// import { CollectionViewType } from "./CollectionView"; +// import internal = require("events"); +// const _global = (window /* browser */ || global /* node */) as any; + +// export type collectionNoteTakingViewProps = { +// chromeHidden?: boolean; +// viewType?: CollectionViewType; +// NativeWidth?: () => number; +// NativeHeight?: () => number; +// }; + +// //TODO: where am I going to add columns? + +// @observer +// export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() { +// // used in a column dragger, likely due for the masonry grid view. We want to use this +// _draggerRef = React.createRef<HTMLDivElement>(); +// // Seems like we cause reaction in MobX get rid of our height once we exit this view +// _autoHeightDisposer?: IReactionDisposer; +// // keeping track of documents. Updated on internal and external drops. What's the difference? +// _docXfs: { height: () => number, width: () => number, stackedDocTransform: () => Transform }[] = []; + +// //--------------------------------------------------------------------------------------------------------------// +// // TODO: these are things that I added but not sure that they actually belong here +// // We may not need to actually keep track of the numColumns +// _noteTakingRef: HTMLDivElement | null = null; +// // this is the layout doc field that we're splitting on. Replaces pivot field +// _columnIndex: string = "columnIndex"; +// @computed get columnIndex() { return this._columnIndex} +// _numColumns: number = 1; +// @computed get numColumns() { return this._numColumns} +// @computed get columnWidth() { return this.props.PanelWidth() - 2 * this.xMargin } +// //--------------------------------------------------------------------------------------------------------------// + +// // Assuming that this is the current css cursor style +// @observable _cursor: CursorProperty = "grab"; +// // gets reset whenever we scroll. Not sure what it is +// @observable _scroll = 0; // used to force the document decoration to update when scrolling +// // does this mean whether the browser is hidden? Or is chrome something else entirely? +// @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); } +// // it looks like this gets the column headers that Mehek was showing just now +// @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); } +// // filteredChildren is what you want to work with. It's the list of things that you're currently displaying +// @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); } +// // how much margin we give the header +// @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); } +// @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } +// @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); } +// @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); } + +// @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } + +// constructor(props: any) { +// super(props); + +// if (this.columnHeaders === undefined) { +// this.layoutDoc._columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("0")]); +// } +// console.log(this.layoutDoc._columnHeaders) +// } + +// children = (docs: Doc[]) => { +// TraceMobx(); +// this._docXfs.length = 0; +// // Go through each of the documents that are contained +// return docs.map((d, i) => { +// if (d._columnIndex && parseInt(d._columnIndex.toString()) + 1 > this.numColumns) { +// this._numColumns = parseInt(d._columnIndex.toString()) + 1; +// } else if (d._columnIndex === undefined) { +// d._columnIndex = 0; +// } +// const height = () => this.getDocHeight(d); +// const width = () => this.getDocWidth(d); +// // just getting the style +// const style = { width: width(), marginTop: i ? this.gridGap : 0, height: height(), margin: this.xMargin }; +// // So we're choosing whether we're going to render a column or a masonry doc +// return <div className={"collectionNoteTakingView-columnDoc"} key={d[Id]} style={style} > +// {this.getDisplayDoc(d, width)} +// </div> +// }); +// } + +// //TODO: this seems important +// get Sections() { +// // appears that pivot field IS actually for sorting +// if (!this.columnIndex || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>(); + +// if (this.columnHeaders === undefined) { +// setTimeout(() => this.layoutDoc._columnHeaders = new List<SchemaHeaderField>(), 0); +// return new Map<SchemaHeaderField, Doc[]>(); +// } +// const columnHeaders = Array.from(this.columnHeaders); +// const fields = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); +// let changed = false; +// this.filteredChildren.map(d => { +// const sectionValue = (d[this.columnIndex] ? d[this.columnIndex] : `NO ${this.columnIndex.toUpperCase()} VALUE`) as object; +// // the next five lines ensures that floating point rounding errors don't create more than one section -syip +// const parsed = parseInt(sectionValue.toString()); +// const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; + +// // look for if header exists already +// const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.columnIndex.toUpperCase()} VALUE`)); +// if (existingHeader) { +// fields.get(existingHeader)!.push(d); +// } +// else { +// const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.columnIndex.toUpperCase()} VALUE`); +// fields.set(newSchemaHeader, [d]); +// columnHeaders.push(newSchemaHeader); +// changed = true; +// } +// }); +// // remove all empty columns if hideHeadings is set +// // we will want to have something like this, so that we can hide columns and add them back in +// if (this.layoutDoc._columnsHideIfEmpty) { +// Array.from(fields.keys()).filter(key => !fields.get(key)!.length).map(header => { +// fields.delete(header); +// columnHeaders.splice(columnHeaders.indexOf(header), 1); +// changed = true; +// }); +// } +// changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0); +// return fields; +// } +// //TODO: this seems important +// // get Sections() { +// // // at the start, we likely will not have column headers +// // if (this.columnHeaders === undefined) { +// // console.log("columns weren't yet defined") +// // setTimeout(() => this.layoutDoc._columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("0")])); +// // return new Map<SchemaHeaderField, Doc[]>(); +// // } + +// // // on later renders, we should have the column headers +// // const columnHeaders = Array.from(this.columnHeaders); +// // console.log(columnHeaders) +// // const fields = new Map<SchemaHeaderField, Doc[]>(); +// // let changed = false; +// // this.filteredChildren.map(d => { +// // const sectionValue = (d._columnIndex ? d._columnIndex : `NO COLUMN VALUE`) as object; +// // // the next five lines ensures that floating point rounding errors don't create more than one section -syip +// // const parsed = parseInt(sectionValue.toString()); +// // const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; +// // const newSchemaHeader = new SchemaHeaderField(castedSectionValue.toString()); +// // const currentDocs = fields.get(newSchemaHeader) +// // if (currentDocs) { +// // currentDocs.push(d) +// // fields.set(newSchemaHeader, currentDocs); +// // } +// // const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO COLUMN VALUE`)); +// // if (existingHeader) { +// // columnHeaders.push(newSchemaHeader); +// // changed = true; +// // } +// // }); +// // changed && setTimeout(action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), 0); +// // return fields; +// // } + +// componentDidMount() { +// super.componentDidMount?.(); + +// this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, +// autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), +// this.headerMargin + +// Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))))))); +// } + +// componentWillUnmount() { +// super.componentWillUnmount(); +// this._autoHeightDisposer?.(); +// } + +// @action +// moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => { +// return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; +// } +// createRef = (ele: HTMLDivElement | null) => { +// this._noteTakingRef = ele; +// this.createDashEventsTarget(ele!); //so the whole grid is the drop target? +// } + +// @computed get onChildClickHandler() { return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); } +// @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } + +// addDocTab = (doc: Doc, where: string) => { +// if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { +// this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]); +// return true; +// } +// return this.props.addDocTab(doc, where); +// } + +// scrollToBottom = () => { +// smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); +// } + +// // let's dive in and get the actual document we want to drag/move around +// focusDocument = (doc: Doc, options?: DocFocusOptions) => { +// Doc.BrushDoc(doc); + +// let focusSpeed = 0; +// const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]); +// if (found) { +// const top = found.getBoundingClientRect().top; +// const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); +// if (Math.floor(localTop[1]) !== 0) { +// smoothScroll(focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); +// } +// } +// const endFocus = async (moved: boolean) => options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing; +// this.props.focus(this.rootDoc, { +// willZoom: options?.willZoom, scale: options?.scale, afterFocus: (didFocus: boolean) => +// new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)) +// }); +// } + +// styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => { +// if (property === StyleProp.Opacity && doc) { +// if (this.props.childOpacity) { +// return this.props.childOpacity(); +// } +// if (this.Document._currentFrame !== undefined) { +// return CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity; +// } +// } +// return this.props.styleProvider?.(doc, props, property); +// } +// isContentActive = () => this.props.isSelected() || this.props.isContentActive(); + +// // this is what renders the document that you see on the screen +// // called in Children: this actually adds a document to our children list +// getDisplayDoc(doc: Doc, width: () => number) { +// const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc; +// const height = () => this.getDocHeight(doc); + +// let dref: Opt<DocumentView>; +// const stackedDocTransform = () => this.getDocTransform(doc, dref); +// this._docXfs.push({ stackedDocTransform, width, height }); +// //DocumentView is how the node will be rendered +// return <DocumentView ref={r => dref = r || undefined} +// Document={doc} +// DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])} +// renderDepth={this.props.renderDepth + 1} +// PanelWidth={width} +// PanelHeight={height} +// styleProvider={this.styleProvider} +// layerProvider={this.props.layerProvider} +// docViewPath={this.props.docViewPath} +// fitWidth={this.props.childFitWidth} +// isContentActive={emptyFunction} +// isDocumentActive={this.isContentActive} +// LayoutTemplate={this.props.childLayoutTemplate} +// LayoutTemplateString={this.props.childLayoutString} +// freezeDimensions={this.props.childFreezeDimensions} +// NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox +// NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined} +// dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined} +// dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} +// rootSelected={this.rootSelected} +// showTitle={this.props.childShowTitle} +// dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType} +// onClick={this.onChildClickHandler} +// onDoubleClick={this.onChildDoubleClickHandler} +// ScreenToLocalTransform={stackedDocTransform} +// focus={this.focusDocument} +// docFilters={this.childDocFilters} +// hideDecorationTitle={this.props.childHideDecorationTitle?.()} +// hideResizeHandles={this.props.childHideResizeHandles?.()} +// hideTitle={this.props.childHideTitle?.()} +// docRangeFilters={this.childDocRangeFilters} +// searchFilterDocs={this.searchFilterDocs} +// ContainingCollectionDoc={this.props.CollectionView?.props.Document} +// ContainingCollectionView={this.props.CollectionView} +// addDocument={this.props.addDocument} +// moveDocument={this.props.moveDocument} +// removeDocument={this.props.removeDocument} +// contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} +// whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} +// addDocTab={this.addDocTab} +// bringToFront={returnFalse} +// scriptContext={this.props.scriptContext} +// pinToPres={this.props.pinToPres} +// />; +// } + +// getDocTransform(doc: Doc, dref?: DocumentView) { +// const y = this._scroll; // required for document decorations to update when the text box container is scrolled +// const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined); +// // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off +// return new Transform(- translateX + (dref?.centeringX || 0), - translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale); +// } +// getDocWidth(d?: Doc) { +// if (!d) return 0; +// const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); +// // TODO: pj - replace with a better way to calculate the margin +// let margin = 25; +// d.margin = 25; +// if (this.columnWidth < 150){ +// margin = 0; +// } +// const maxWidth = (this.columnWidth / this.numColumns) - (margin * 2); +// if (!this.layoutDoc._columnsFill && !(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d))) { +// return Math.min(d[WidthSym](), maxWidth); +// } +// return maxWidth; +// } +// getDocHeight(d?: Doc) { +// if (!d || d.hidden) return 0; +// const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); +// const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc; +// const maxHeight = (lim => lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1)); +// const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0); +// const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0); +// if (nw && nh) { +// const colWid = this.columnWidth / this.numColumns; +// const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); +// return Math.min( +// maxHeight, +// docWid * nh / nw); +// } +// const childHeight = NumCast(childLayoutDoc._height); +// const panelHeight = (childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; +// return Math.min(childHeight, maxHeight, panelHeight); +// } + +// // This following three functions must be from the view Mehek showed +// columnDividerDown = (e: React.PointerEvent) => { +// runInAction(() => this._cursor = "grabbing"); +// setupMoveUpEvents(this, e, this.onDividerMove, action(() => this._cursor = "grab"), emptyFunction); +// } +// @action +// onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => { +// this.layoutDoc._columnWidth = Math.max(10, this.columnWidth + delta[0]); +// return false; +// } + +// @computed get columnDragger() { +// return <div className="collectionStackingView-columnDragger" onPointerDown={this.columnDividerDown} ref={this._draggerRef} +// style={{ cursor: this._cursor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }} > +// <FontAwesomeIcon icon={"arrows-alt-h"} /> +// </div>; +// } + +// @undoBatch +// @action +// onInternalDrop = (e: Event, de: DragManager.DropEvent) => { +// // Fairly confident that this is where the swapping of nodes in the various arrays happens +// console.log('drop') +// const where = [de.x, de.y]; +// // start at -1 until we're sure we want to add it to the column +// let dropInd = -1; +// let dropAfter = 0; +// if (de.complete.docDragData) { +// // going to re-add the docs to the _docXFs based on position of where we just dropped +// this._docXfs.map((cd, i) => { +// const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); +// const pos1 = cd.stackedDocTransform().inverse().transformPoint(cd.width(), cd.height()); +// if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { +// dropInd = i; +// //TODO: not sure what the axis should actually be. Had a ternary previously with 0/1 +// const axis = 1; +// dropAfter = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0; +// } +// }); +// const oldDocs = this.childDocs.length; +// if (super.onInternalDrop(e, de)) { +// // check to see if we actually need anything to the new column of nodes (if droppedDocs != empty) +// const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= oldDocs); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note). +// const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments; // if nothing was added to the end of the list, then presumably the dropped documents were already in the list, but possibly got reordered so we use them. + +// const docs = this.childDocList; +// // reset drag manager docs, because we just dropped +// DragManager.docsBeingDragged = []; +// // still figuring out where to add the document +// if (docs && newDocs.length) { +// const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter; +// const offset = newDocs.reduce((off, ndoc) => this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0); +// newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1)); +// docs.splice(insertInd - offset, 0, ...newDocs); +// } +// } +// } // it seems like we're creating a link here. Weird. I didn't know that you could establish links by dragging +// else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { +// const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, _fitWidth: true, title: "dropped annotation" }); +// this.props.addDocument?.(source); +// de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed +// e.stopPropagation(); +// } +// else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); +// return false; +// } + +// @undoBatch +// internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) { +// const dropCreator = annoDragData.dropDocCreator; +// annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => { +// const dropDoc = dropCreator(annotationOn); +// return dropDoc || this.rootDoc; +// }; +// return true; +// } + +// @undoBatch +// @action +// //What is the difference between internal and external drop?? Does internal mean we're dropping inside of a collection? +// // I take it back: external drop means we took it out of column/collection that we were just in +// onExternalDrop = async (e: React.DragEvent): Promise<void> => { +// console.log('external drop') +// const where = [e.clientX, e.clientY]; +// let targInd = -1; +// this._docXfs.map((cd, i) => { +// const pos = cd.stackedDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); +// const pos1 = cd.stackedDocTransform().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.onExternalDrop(e, {}, () => { +// if (targInd !== -1) { +// const newDoc = this.childDocs[this.childDocs.length - 1]; +// const docs = this.childDocList; +// if (docs) { +// docs.splice(docs.length - 1, 1); +// docs.splice(targInd, 0, newDoc); +// } +// } +// }); +// } +// // sections are important +// headings = () => Array.from(this.Sections); +// refList: any[] = []; +// // what a section looks like if we're in stacking view +// sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { +// const key = "columnIndex"; +// let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; +// const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); +// if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { +// type = types[0]; +// } +// //TODO: I think that we only have one of these atm +// return <CollectionNoteTakingViewFieldColumn +// unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)} +// observeHeight={ref => { +// if (ref) { +// this.refList.push(ref); +// this.observer = new _global.ResizeObserver(action((entries: any) => { +// if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { +// const height = this.headerMargin + +// Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), +// Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))))); +// if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) { +// this.props.setHeight(height); +// } +// } +// })); +// this.observer.observe(ref); +// } +// }} +// addDocument={this.addDocument} +// chromeHidden={this.chromeHidden} +// columnHeaders={this.columnHeaders} +// Document={this.props.Document} +// DataDoc={this.props.DataDoc} +// renderChildren={this.children} +// columnWidth={this.columnWidth} +// columnIndex={this._columnIndex} +// numColumns={this.numColumns} +// gridGap={this.gridGap} +// key={heading?.heading ?? ""} +// headings={this.headings} +// heading={heading?.heading ?? ""} +// headingObject={heading} +// docList={docList} +// yMargin={this.yMargin} +// type={type} +// createDropTarget={this.createDashEventsTarget} +// screenToLocalTransform={this.props.ScreenToLocalTransform} +// />; +// } + +// @action +// // What are we adding a group to? +// addGroup = (value: string) => { +// if (value && this.columnHeaders) { +// const schemaHdrField = new SchemaHeaderField(value); +// this.columnHeaders.push(schemaHdrField); +// DocUtils.addFieldEnumerations(undefined, this._columnIndex, [{ title: value, _backgroundColor: "schemaHdrField.color" }]); +// return true; +// } +// return false; +// } + +// sortFunc = (a: [SchemaHeaderField, Doc[]], b: [SchemaHeaderField, Doc[]]): 1 | -1 => { +// const descending = StrCast(this.layoutDoc._columnsSort) === "descending"; +// const firstEntry = descending ? b : a; +// const secondEntry = descending ? a : b; +// return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1; +// } + +// onContextMenu = (e: React.MouseEvent): void => { +// // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout +// if (!e.isPropagationStopped()) { +// const subItems: ContextMenuProps[] = []; +// subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" }); +// subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); +// subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" }); +// ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); +// } +// } + +// // +// @computed get renderedSections() { +// TraceMobx(); +// let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]; +// const entries = Array.from(this.Sections.entries()); +// sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries; +// // a section will have a header and a list of docs. Ok cool. +// return sections.map((section, i) => this.sectionStacking(section[0], section[1])); +// } + +// @computed get buttonMenu() { +// const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); +// // TODO:glr Allow support for multiple buttons +// if (menuDoc) { +// const width: number = NumCast(menuDoc._width, 30); +// const height: number = NumCast(menuDoc._height, 30); +// console.log(menuDoc.title, width, height); +// return (<div className="buttonMenu-docBtn" +// style={{ width: width, height: height }}> +// <DocumentView +// Document={menuDoc} +// DataDoc={menuDoc} +// isContentActive={this.props.isContentActive} +// isDocumentActive={returnTrue} +// addDocument={this.props.addDocument} +// moveDocument={this.props.moveDocument} +// addDocTab={this.props.addDocTab} +// pinToPres={emptyFunction} +// rootSelected={this.props.isSelected} +// removeDocument={this.props.removeDocument} +// ScreenToLocalTransform={Transform.Identity} +// PanelWidth={() => 35} +// PanelHeight={() => 35} +// renderDepth={this.props.renderDepth} +// focus={emptyFunction} +// styleProvider={this.props.styleProvider} +// layerProvider={this.props.layerProvider} +// docViewPath={returnEmptyDoclist} +// whenChildContentsActiveChanged={emptyFunction} +// bringToFront={emptyFunction} +// docFilters={this.props.docFilters} +// docRangeFilters={this.props.docRangeFilters} +// searchFilterDocs={this.props.searchFilterDocs} +// ContainingCollectionView={undefined} +// ContainingCollectionDoc={undefined} +// /> +// </div> +// ); +// } +// } + + +// @computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); } +// @computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); } + +// @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; } + +// @computed get backgroundEvents() { return SnappingManager.GetIsDragging(); } +// observer: any; +// render() { +// TraceMobx(); +// const editableViewProps = { +// GetValue: () => "", +// SetValue: this.addGroup, +// // I don't recall ever seeing this add a group button +// contents: "+ ADD A GROUP" +// }; +// const buttonMenu = this.rootDoc.buttonMenu; +// const noviceExplainer = this.rootDoc.explainer; +// return ( +// <> +// {buttonMenu || noviceExplainer ? <div className="documentButtonMenu"> +// {buttonMenu ? this.buttonMenu : null} +// {Doc.UserDoc().noviceMode && noviceExplainer ? +// <div className="documentExplanation"> +// {noviceExplainer} +// </div> +// : null +// } +// </div> : null} +// <div className="collectionStackingMasonry-cont" > +// <div className={"collectionNoteTakingView"} +// ref={this.createRef} +// style={{ +// overflowY: this.props.isContentActive() ? "auto" : "hidden", +// background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor), +// pointerEvents: this.backgroundEvents ? "all" : undefined +// }} +// onScroll={action(e => this._scroll = e.currentTarget.scrollTop)} +// onDrop={this.onExternalDrop.bind(this)} +// onContextMenu={this.onContextMenu} +// onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} > +// {this.renderedSections} +// </div> +// </div> +// </> + +// ); +// } +// } diff --git a/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx index 0c3eef36d..5a8256e11 100644 --- a/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx @@ -3,14 +3,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, Opt } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; import { RichTextField } from "../../../fields/RichTextField"; import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { ScriptField } from "../../../fields/ScriptField"; -import { NumCast } from "../../../fields/Types"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { ImageField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnEmptyString, setupMoveUpEvents } from "../../../Utils"; +import { emptyFunction, setupMoveUpEvents, returnFalse, returnEmptyString } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { DragManager } from "../../util/DragManager"; @@ -20,27 +19,30 @@ import { undoBatch } from "../../util/UndoManager"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; -import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; import "./CollectionStackingView.scss"; +import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; +import { Id } from "../../../fields/FieldSymbols"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; +// So this is how we are storing a column interface CSVFieldColumnProps { Document: Doc; DataDoc: Opt<Doc>; docList: Doc[]; heading: string; - columnIndex: string; + pivotField: string; chromeHidden?: boolean; columnHeaders: SchemaHeaderField[] | undefined; headingObject: SchemaHeaderField | undefined; yMargin: number; columnWidth: number; - numColumns: number; + numGroupColumns: number; gridGap: number; type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; headings: () => object[]; + // I think that stacking view actually has a single column and then supposedly you can add more columns? Unsure renderChildren: (docs: Doc[]) => JSX.Element[]; addDocument: (doc: Doc | Doc[]) => boolean; createDropTarget: (ele: HTMLDivElement) => void; @@ -56,9 +58,9 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel private dropDisposer?: DragManager.DragDropDisposer; private _headerRef: React.RefObject<HTMLDivElement> = React.createRef(); - // @observable _paletteOn = false; + @observable _paletteOn = false; @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading; - // @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; _ele: HTMLElement | null = null; // This is likely similar to what we will be doing. Why do we need to make these refs? @@ -79,9 +81,8 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel @undoBatch columnDrop = action((e: Event, de: DragManager.DropEvent) => { const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; - drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.columnIndex, drop.val, false)); + 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; @@ -91,13 +92,13 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel } @action - headingChanged = (value: string) => { + headingChanged = (value: string, shiftDown?: boolean) => { const castedValue = this.getValue(value); if (castedValue) { if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { return false; } - this.props.docList.forEach(d => d[this.props.columnIndex] = 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; @@ -107,6 +108,12 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel return false; } + @action + changeColumnColor = (color: string) => { + this.props.headingObject?.setColor(color); + this._color = color; + } + @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4"); @action pointerLeave = () => this._background = "inherit"; textCallback = (char: string) => this.addNewTextDoc("-typed text-", false, true); @@ -114,7 +121,7 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel @action addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { if (!value && !forceEmptyNote) return false; - const key = this.props.columnIndex; + 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); @@ -127,7 +134,7 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel @action deleteColumn = () => { - this.props.docList.forEach(d => d[this.props.columnIndex] = undefined); + 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); @@ -150,7 +157,7 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel alias._pivotField = undefined; let value = this.getValue(this._heading); value = typeof value === "string" ? `"${value}"` : value; - alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.columnIndex} === ${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; @@ -158,6 +165,21 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel return false; } + // renderColorPicker = () => { + // const gray = "#f1efeb"; + // 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"> @@ -224,12 +246,12 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel } @computed get innards() { TraceMobx(); - const key = this.props.columnIndex; + const key = this.props.pivotField; const headings = this.props.headings(); const heading = this._heading; 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 evContents = heading ? heading : this.props?.type === "number" ? "0" : `0`; const headingView = this.props.headingObject ? <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef} style={{ @@ -241,18 +263,27 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel {/* the default bucket (no key value) has a tooltip that describes what it is. Further, it does not have a color and cannot be deleted. */} <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} - title={evContents === `NO ${key.toUpperCase()} VALUE` ? - `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}> + title={evContents === `0` ? + `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""} + style={{ background: evContents !== `0` ? this._color : "inherit" }}> <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} toggle={this.toggleVisibility} /> + {evContents === `0` ? (null) : + <div className="collectionStackingView-sectionColor"> + {/* <button className="collectionStackingView-sectionColorButton" onClick={action(e => this._paletteOn = !this._paletteOn)}> + <FontAwesomeIcon icon="palette" size="lg" /> + </button> */} + {/* {this._paletteOn ? this.renderColorPicker() : (null)} */} + </div> + } {<button className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}> <FontAwesomeIcon icon="trash" size="lg" /> </button>} - {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : + {/* {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : <div className="collectionStackingView-sectionOptions"> <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}> <button className="collectionStackingView-sectionOptionButton"> @@ -260,10 +291,10 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel </button> </Flyout> </div> - } + } */} </div> </div> : (null); - const templatecols = `${this.props.columnWidth / this.props.numColumns}px `; + const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; const type = this.props.Document.type; return <> {this.props.Document._columnsHideIfEmpty ? (null) : headingView} @@ -284,8 +315,14 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel {this.props.renderChildren(this.props.docList)} </div> {!this.props.chromeHidden && type !== DocumentType.PRES ? + // TODO: this is the "new" button: see what you can work with here + // change cursor to pointer for this, and update dragging cursor + //TODO: there is a bug that occurs when adding a freeform document and trying to move it around + //TODO: would be great if there was additional space beyond the frame, so that you can actually see your + // bottom note + //TODO: ok, so we are using a single column, and this is it! <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" - style={{ width: this.props.columnWidth / this.props.numColumns, marginBottom: 10, marginLeft: 25 }}> + style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10, marginLeft: 25 }}> <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} @@ -319,4 +356,328 @@ export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFiel </div > ); } -}
\ No newline at end of file +} + + +// import React = require("react"); +// import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +// import { action, computed, observable } from "mobx"; +// import { observer } from "mobx-react"; +// import { Doc, DocListCast, Opt } from "../../../fields/Doc"; +// import { Id } from "../../../fields/FieldSymbols"; +// import { RichTextField } from "../../../fields/RichTextField"; +// import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +// import { ScriptField } from "../../../fields/ScriptField"; +// import { NumCast } from "../../../fields/Types"; +// import { ImageField } from "../../../fields/URLField"; +// import { TraceMobx } from "../../../fields/util"; +// import { emptyFunction, returnEmptyString, setupMoveUpEvents } from "../../../Utils"; +// import { Docs, DocUtils } from "../../documents/Documents"; +// import { DocumentType } from "../../documents/DocumentTypes"; +// import { DragManager } from "../../util/DragManager"; +// import { SnappingManager } from "../../util/SnappingManager"; +// import { Transform } from "../../util/Transform"; +// import { undoBatch } from "../../util/UndoManager"; +// import { ContextMenu } from "../ContextMenu"; +// import { ContextMenuProps } from "../ContextMenuItem"; +// import { EditableView } from "../EditableView"; +// import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; +// import "./CollectionStackingView.scss"; +// const higflyout = require("@hig/flyout"); +// export const { anchorPoints } = higflyout; +// export const Flyout = higflyout.default; + +// interface CSVFieldColumnProps { +// Document: Doc; +// DataDoc: Opt<Doc>; +// docList: Doc[]; +// heading: string; +// columnIndex: string; +// chromeHidden?: boolean; +// columnHeaders: SchemaHeaderField[] | undefined; +// headingObject: SchemaHeaderField | undefined; +// yMargin: number; +// columnWidth: number; +// numColumns: 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; +// unobserveHeight: (myref: any) => void; +// } + +// @observer +// export class CollectionNoteTakingViewFieldColumn extends React.Component<CSVFieldColumnProps> { +// @observable private _background = "inherit"; + +// private dropDisposer?: DragManager.DragDropDisposer; +// private _headerRef: React.RefObject<HTMLDivElement> = React.createRef(); + +// // @observable _paletteOn = false; +// @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading; +// // @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; +// _ele: HTMLElement | null = null; + +// // This is likely similar to what we will be doing. Why do we need to make these refs? +// // is that the only way to have drop targets? +// createColumnDropRef = (ele: HTMLDivElement | null) => { +// this.dropDisposer?.(); +// if (ele) { +// this._ele = ele; +// this.props.observeHeight(ele); +// this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this)); +// } +// } +// componentWillUnmount() { +// this.props.unobserveHeight(this._ele); +// } + +// //TODO: what is scripting? I found it in SetInPlace def but don't know what that is +// @undoBatch +// columnDrop = action((e: Event, de: DragManager.DropEvent) => { +// const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; +// drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.columnIndex, 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; +// return value; +// } + +// @action +// headingChanged = (value: string) => { +// const castedValue = this.getValue(value); +// if (castedValue) { +// if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { +// return false; +// } +// this.props.docList.forEach(d => d[this.props.columnIndex] = castedValue); +// if (this.props.headingObject) { +// this.props.headingObject.setHeading(castedValue.toString()); +// this._heading = this.props.headingObject.heading; +// } +// return true; +// } +// return false; +// } + +// @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4"); +// @action pointerLeave = () => this._background = "inherit"; +// textCallback = (char: string) => this.addNewTextDoc("-typed text-", false, true); + +// @action +// addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { +// if (!value && !forceEmptyNote) return false; +// const key = this.props.columnIndex; +// 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); +// const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3; +// newDoc.heading = heading; +// FormattedTextBox.SelectOnLoad = newDoc[Id]; +// FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? "" : " "; +// return this.props.addDocument?.(newDoc) || false; +// } + +// @action +// deleteColumn = () => { +// this.props.docList.forEach(d => d[this.props.columnIndex] = 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 = () => { +// this.props.headingObject?.setCollapsed(!this.props.headingObject.collapsed); +// this.toggleVisibility(); +// } + +// headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); + +// //TODO: I think this is where I'm supposed to edit stuff +// startDrag = (e: PointerEvent, down: number[], delta: number[]) => { +// // is MakeAlias a way to make a copy of a doc without rendering it? +// const alias = Doc.MakeAlias(this.props.Document); +// alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1); +// alias._pivotField = undefined; +// let value = this.getValue(this._heading); +// value = typeof value === "string" ? `"${value}"` : value; +// alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.columnIndex} === ${value}`, { doc: Doc.name }); +// if (alias.viewSpecScript) { +// DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY); +// return true; +// } +// return false; +// } + +// renderMenu = () => { +// 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; + +// private toggleVisibility = action(() => this.collapsed = !this.collapsed); + +// menuCallback = (x: number, y: number) => { +// ContextMenu.Instance.clearItems(); +// const layoutItems: ContextMenuProps[] = []; +// const docItems: ContextMenuProps[] = []; +// const dataDoc = this.props.DataDoc || this.props.Document; + +// DocUtils.addDocumentCreatorMenuItems((doc) => { +// FormattedTextBox.SelectOnLoad = doc[Id]; +// 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.Document)); +// if (created) { +// if (this.props.Document.isTemplateDoc) { +// Doc.MakeMetadataFieldTemplate(created, this.props.Document); +// } +// return this.props.addDocument?.(created); +// } +// }, icon: "compress-arrows-alt" +// })); +// Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => DocListCast(dataDoc[fieldKey]).length).map(fieldKey => +// docItems.push({ +// description: ":" + fieldKey, event: () => { +// const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); +// if (created) { +// 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.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.Document)[name] = ""; +// const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true }); +// if (created) { +// if (this.props.Document.isTemplateDoc) { +// Doc.MakeMetadataFieldTemplate(created, this.props.Document); +// } +// this.props.addDocument?.(created); +// } +// }); +// const pt = this.props.screenToLocalTransform().inverse().transformPoint(x, y); +// ContextMenu.Instance.displayMenu(x, y, undefined, true); +// } +// @computed get innards() { +// TraceMobx(); +// const key = this.props.columnIndex; +// const headings = this.props.headings(); +// const heading = this._heading; +// 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: this.props.yMargin, +// width: (this.props.columnWidth) / +// ((uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1)) || 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. +// Further, it does not have a color and cannot be deleted. */} +// <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} +// title={evContents === `NO ${key.toUpperCase()} VALUE` ? +// `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}> +// <EditableView +// GetValue={() => evContents} +// SetValue={this.headingChanged} +// contents={evContents} +// oneLine={true} +// toggle={this.toggleVisibility} /> +// {<button className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}> +// <FontAwesomeIcon icon="trash" size="lg" /> +// </button>} +// {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : +// <div className="collectionStackingView-sectionOptions"> +// <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}> +// <button className="collectionStackingView-sectionOptionButton"> +// <FontAwesomeIcon icon="ellipsis-v" size="lg"></FontAwesomeIcon> +// </button> +// </Flyout> +// </div> +// } +// </div> +// </div> : (null); +// const templatecols = `${this.props.columnWidth / this.props.numColumns}px `; +// const type = this.props.Document.type; +// return <> +// {this.props.Document._columnsHideIfEmpty ? (null) : headingView} +// { +// this.collapsed ? (null) : +// <div> +// <div key={`${heading}-stack`} className={`collectionStackingView-masonrySingle`} +// style={{ +// 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: this.props.gridGap, +// gridTemplateColumns: templatecols, +// gridAutoRows: "0px" +// }}> +// {this.props.renderChildren(this.props.docList)} +// </div> +// {!this.props.chromeHidden && type !== DocumentType.PRES ? +// <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" +// style={{ width: this.props.columnWidth / this.props.numColumns, marginBottom: 10, marginLeft: 25 }}> +// <EditableView +// GetValue={returnEmptyString} +// SetValue={this.addNewTextDoc} +// textCallback={this.textCallback} +// placeholder={"Type ':' for commands"} +// contents={<FontAwesomeIcon icon={"plus"}/>} +// toggle={this.toggleVisibility} +// menuCallback={this.menuCallback} +// /> +// </div> : null} +// </div> +// } +// </>; +// } + + +// render() { +// TraceMobx(); +// const headings = this.props.headings(); +// const heading = this._heading; +// const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); +// return ( +// <div className={"collectionStackingViewFieldColumn" + (SnappingManager.GetIsDragging() ? "Dragging" : "")} key={heading} +// style={{ +// width: `${100 / (uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1) || 1)}%`, +// height: undefined, // DraggingManager.GetIsDragging() ? "100%" : undefined, +// background: this._background +// }} +// ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}> +// {this.innards} +// </div > +// ); +// } +// }
\ No newline at end of file |