From 733d16628dfc04316674d42c939b1077deb9bd31 Mon Sep 17 00:00:00 2001 From: ljungster Date: Thu, 16 Jun 2022 07:28:53 -0500 Subject: comitting before deleting comments --- .../views/collections/CollectionNoteTakingView.tsx | 251 +++++++-------- .../collections/CollectionNoteTakingViewColumn.tsx | 337 +++++++++++++++++++++ .../CollectionNoteTakingViewFieldColumn.tsx | 327 -------------------- 3 files changed, 469 insertions(+), 446 deletions(-) create mode 100644 src/client/views/collections/CollectionNoteTakingViewColumn.tsx delete mode 100644 src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx (limited to 'src') diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 3ae2fac7d..2c8225eac 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -3,7 +3,7 @@ import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; +import { Copy, Id, ToScriptString, ToString } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; @@ -24,12 +24,13 @@ import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from import { StyleProp } from "../StyleProvider"; import "./CollectionNoteTakingView.scss"; import CollectionNoteTakingViewDivider from "./CollectionNoteTakingViewDivider"; -import { CollectionNoteTakingViewFieldColumn } from "./CollectionNoteTakingViewFieldColumn"; +import { CollectionNoteTakingViewColumn } from "./CollectionNoteTakingViewColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; +import { ObjectField } from "../../../fields/ObjectField"; +import { faThumbsDown } from "@fortawesome/free-solid-svg-icons"; const _global = (window /* browser */ || global /* node */) as any; - export type collectionNoteTakingViewProps = { chromeHidden?: boolean; viewType?: CollectionViewType; @@ -37,67 +38,54 @@ export type collectionNoteTakingViewProps = { NativeHeight?: () => number; }; +//TODO: somehow need to update the mapping and then have everything else rerender. Maybe with a refresh boolean like +// in Hypermedia? + @observer export class CollectionNoteTakingView extends CollectionSubView>() { - //-------------------------------------------- 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; _draggerRef = React.createRef(); - // keeping track of documents. Updated on internal and external drops. What's the difference? - _docXfs: { height: () => number, width: () => number, noteTakingDocTransform: () => Transform }[] = []; - // Assuming that this is the current css cursor style + // _docXfs: { height: () => number, width: () => number, noteTakingDocTransform: () => Transform }[] = []; + // @observable _docsByColumnHeader = new Map(); + //TODO: need to make sure that we save the mapping @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); } - // 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 @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 numGroupColumns() { return this.columnHeaders.length; } - // @computed get columnWidth() {return this.props.PanelWidth() - 2 * this.xMargin;} - - //-------------------------------------------- Parker's Playground --------------------------------------------// - // draggedDocBackgroundColors: string[] = [] @observable columnStartXCoords: number[] = [] @computed get PanelWidth() {return this.props.PanelWidth()} @computed get maxColWdith() {return this.props.PanelWidth() - 2 * this.xMargin;} - // dividerXCoords: number[] = [] - //-------------------------------------------------------------------------------------------------------------// + // If the user has not yet created any docs (in another view), this will create a single column. Otherwise, + // it will adjust according to the constructor(props: any) { super(props); - if (this.columnHeaders === undefined) { this.layoutDoc._columnHeaders = new List([new SchemaHeaderField('New Column')]); this.columnStartXCoords = [0] + // add all of the docs that have not been added to a column to this new column } else { const numHeaders = this.columnHeaders.length this.resizeColumns(numHeaders) } } - // TODO [pal]: is there a better way to do this? + // passed as a prop to the NoteTakingField, which uses this function + // to render the docs you see within an individual column. children = (docs: Doc[]) => { TraceMobx(); - this._docXfs.length = 0; return docs.map((d, i) => { const height = () => this.getDocHeight(d); const width = () => this.getDocWidth(d); - //TODO change style here so that const style = { width: width(), marginTop: this.gridGap, height: height() }; return
{this.getDisplayDoc(d, width)} @@ -105,12 +93,17 @@ export class CollectionNoteTakingView extends CollectionSubView(); - const columnHeaders = Array.from(this.columnHeaders); + if (this.columnHeaders instanceof Promise) return new Map(); + const columnHeaders = this.columnHeaders; const fields = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); - let changed = false; - this.filteredChildren.map(d => { + // let changed = false; + // const values = Array.from(this._docsByColumnHeader.values()); + const docs = this.childDocList + if (docs) { + docs.map(d => { + if (d instanceof Promise) return; if (!d[this.pivotField]) { d[this.pivotField] = columnHeaders.length > 0 ? columnHeaders[0].heading : `New Column` }; @@ -123,35 +116,37 @@ export class CollectionNoteTakingView extends CollectionSubView !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); + // We don't ever want hidden columns + // 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; } 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", ""))))))); @@ -167,6 +162,7 @@ export class CollectionNoteTakingView extends CollectionSubView boolean): boolean => { return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; } + createRef = (ele: HTMLDivElement | null) => { this._masonryGridRef = ele; this.createDashEventsTarget(ele!); //so the whole grid is the drop target? @@ -220,16 +216,12 @@ export class CollectionNoteTakingView extends CollectionSubView 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 + // rules for displaying the documents 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; const noteTakingDocTransform = () => this.getDocTransform(doc, dref); - this._docXfs.push({ noteTakingDocTransform, width, height }); - //DocumentView is how the node will be rendered return dref = r || undefined} Document={doc} DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])} @@ -241,10 +233,9 @@ export class CollectionNoteTakingView extends CollectionSubView; } - //TODO update this to + // This is used to get the coordinates of a document when we go from a view like freeform to columns 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); @@ -288,7 +279,8 @@ export class CollectionNoteTakingView extends CollectionSubView { - //TODO: that isn't the proper width of columns const totalWidth = this.PanelWidth const dividerWidth = 32 const totaldividerWidth = (n - 1) * dividerWidth @@ -342,28 +335,14 @@ export class CollectionNoteTakingView extends CollectionSubView { if (DragManager.docsBeingDragged.length && this.childDocList) { // get the current column based on the mouse's x coordinate - // const clientX = e.clientX - 2 * this.gridGap // unsure how large left tab is, may need to change the subtraction op - // let col = 0 - // for (let i = 0; i < this.columnStartXCoords.length; i++) { - // if (clientX > this.columnStartXCoords[i]) { - // col = i - // } - // } - const col = this.getClientColumn(e) - // get all of the docs in that column - let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]; - if (this.pivotField) { - const entries = Array.from(this.Sections.entries()); - sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries; - } - const docs = sections[col][1] + const docs = this.getDocsFromXCoord(e.clientX - 2 * this.gridGap) // get the index for where you need to insert the doc you are currently dragging const clientY = e.clientY - console.log(clientY) let dropInd = -1; let dropAfter = 0; docs.forEach((doc, i) => { @@ -377,7 +356,6 @@ export class CollectionNoteTakingView extends CollectionSubView pos0[1] && (clientY < pos1[1] || i == docs.length - 1) if (yCoordInBetween) { dropInd = i; - console.log(dropInd) if (clientY > (pos0[1] + pos1[1]) / 2) { dropAfter = 1; } @@ -396,14 +374,14 @@ export class CollectionNoteTakingView extends CollectionSubView { - const clientX = e.clientX + // returns the column index for a given x-coordinate + getColumnFromXCoord = (xCoord: number): number => { const numColumns = this.columnHeaders.length const coords = this.columnStartXCoords coords.push(this.props.PanelWidth()) let colIndex = 0 for (let i = 0; i < numColumns; i++) { - if (clientX > coords[i] && clientX < coords[i + 1]) { + if (xCoord > coords[i] && xCoord < coords[i + 1]) { colIndex = i break } @@ -411,38 +389,53 @@ export class CollectionNoteTakingView extends CollectionSubView { + const colIndex = this.getColumnFromXCoord(xCoord) + const colHeader = StrCast(this.columnHeaders[colIndex].heading) + const docs = this.childDocList + const docsMatchingHeader: Doc[] = [] + if (docs) { + docs.map(d => { + if (d instanceof Promise) return; + const sectionValue = d[this.pivotField] as object; + if (sectionValue.toString() == colHeader) { + docsMatchingHeader.push(d) + } + }) + } + return docsMatchingHeader; + } + + @undoBatch @action onInternalDrop = (e: Event, de: DragManager.DropEvent) => { - // Fairly confident that this is where the swapping of nodes in the various arrays happens const where = [de.x, de.y]; - // start at -1 until we're sure we want to add it to the column - //Parker added this to reset doc colors - - // 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.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - const pos1 = cd.noteTakingDocTransform().inverse().transformPoint(cd.width(), cd.height()); - // const top = cd.height(); - // const pos = cd.noteTakingDocTransform().transformPoint(0, cd.height()); - // TODO: plan - // Get the top of the box - // Check if there could possibly be a box below - - // const pos1 = cd.noteTakingDocTransform().transformPoint(0, cd.height()); - // if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { - if (where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { - dropInd = i; - const axis = 1; - dropAfter = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0; - } - }); + const docs = this.getDocsFromXCoord(de.x) + docs.map((d, i) => { + const pos0 = this.getDocTransform(d).inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + const pos1 = this.getDocTransform(d).inverse().transformPoint(this.getDocWidth(d), this.getDocHeight(d)); + // const pos = d.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + // const pos1 = cd.noteTakingDocTransform().inverse().transformPoint(cd.width(), cd.height()); + // const top = cd.height(); + // const pos = cd.noteTakingDocTransform().transformPoint(0, cd.height()); + // TODO: plan + // Get the top of the box + // Check if there could possibly be a box below + + // const pos1 = cd.noteTakingDocTransform().transformPoint(0, cd.height()); + // if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) { + if (where[1] > pos0[1] && (i === docs.length - 1 || where[1] < pos1[1])) { + dropInd = i; + const axis = 1; + dropAfter = where[axis] > (pos0[axis] + pos1[axis]) / 2 ? 1 : 0; + } + }); + //TODO: all of this is wrong 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) @@ -452,7 +445,7 @@ export class CollectionNoteTakingView extends CollectionSubView this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0); @@ -486,18 +479,29 @@ export class CollectionNoteTakingView extends CollectionSubView => { const where = [e.clientX, e.clientY]; let targInd = -1; - this._docXfs.map((cd, i) => { - const pos = cd.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - const pos1 = cd.noteTakingDocTransform().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; - } - }); + const docs = this.getDocsFromXCoord(where[0]) + docs.map((d, i) => { + const pos0 = this.getDocTransform(d).inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + const pos1 = this.getDocTransform(d).inverse().transformPoint(this.getDocWidth(d), this.getDocHeight(d)); + // const pos0 = cd.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + // const pos1 = cd.noteTakingDocTransform().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos0[0] && where[0] < pos1[0] && where[1] > pos0[1] && where[1] < pos1[1]) { + targInd = i; + } + }) + // this._docXfs.map((cd, i) => { + // const pos = cd.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + // const pos1 = cd.noteTakingDocTransform().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]; @@ -510,12 +514,17 @@ export class CollectionNoteTakingView extends CollectionSubView { + // this._docsByColumnHeader = new Map(this._docsByColumnHeader.set(key, docs)) + // } + headings = () => Array.from(this.Sections); + refList: any[] = []; + sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { const type = "number"; - return this.refList.splice(this.refList.indexOf(ref), 1)} observeHeight={ref => { if (ref) { @@ -534,6 +543,8 @@ export class CollectionNoteTakingView extends CollectionSubView; } + // called when adding a new columnHeader @action addGroup = (value: string) => { if (value && this.columnHeaders) { @@ -593,6 +605,7 @@ export class CollectionNoteTakingView extends CollectionSubView { const coords = [...this.columnStartXCoords] @@ -600,19 +613,19 @@ export class CollectionNoteTakingView extends CollectionSubView; + docList: Doc[]; + heading: string; + pivotField: string; + chromeHidden?: boolean; + columnHeaders: SchemaHeaderField[] | undefined; + headingObject: SchemaHeaderField | undefined; + 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; + unobserveHeight: (myref: any) => void; + editableViewProps: any; + resizeColumns: (n: number) => void + columnStartXCoords: number[] + PanelWidth: number + maxColWidth: number + // docsByColumnHeader: Map + // setDocsForColHeader: (key: string, docs: Doc[]) => void +} + +@observer +export class CollectionNoteTakingViewColumn extends React.Component { + @observable private _background = "inherit"; + + @computed get columnWidth() { + // base cases + if (!this.props.columnHeaders || !this.props.headingObject || this.props.columnHeaders.length == 1) { + return this.props.maxColWidth + } + const i = this.props.columnHeaders.indexOf(this.props.headingObject) + if (i < 0) { + return this.props.maxColWidth + } + const endColValue = i == this.props.numGroupColumns - 1 ? this.props.PanelWidth : this.props.columnStartXCoords[i+1] + // TODO make the math work here. 35 is half of 70, which is the current width of the divider + return endColValue - this.props.columnStartXCoords[i] - 30 + } + + private dropDisposer?: DragManager.DragDropDisposer; + private _headerRef: React.RefObject = React.createRef(); + + @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); + } + + @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.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; + return value; + } + + @action + 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.pivotField] = 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.pivotField; + const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true }); + const colValue = this.getValue(this.props.heading); + newDoc[key] = colValue; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? "" : " "; + // let currentDocs: Doc[] = [] + // const docsFromMap = this.props.docsByColumnHeader.get(colValue) + // if (docsFromMap) { + // currentDocs = [...docsFromMap] + // } + // currentDocs.push(newDoc) + // this.props.setDocsForColHeader(colValue, currentDocs) + return this.props.addDocument?.(newDoc) || false; + } + + @action + deleteColumn = () => { + if (!this.props.columnHeaders) { + return + } + if (this.props.headingObject) { + const index = this.props.columnHeaders.indexOf(this.props.headingObject); + const newIndex = index == 0 ? 1 : index - 1 + const newHeader = this.props.columnHeaders[newIndex]; + this.props.docList.forEach(d => d[this.props.pivotField] = newHeader.heading.toString()) + this.props.columnHeaders.splice(index, 1); + this.props.resizeColumns(this.props.columnHeaders.length) + } + } + + headerDown = (e: React.PointerEvent) => 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[]) => { + console.log('in startDrag') + // 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._width = this.columnWidth; + alias._pivotField = undefined; + let value = this.getValue(this._heading); + value = typeof value === "string" ? `"${value}"` : value; + alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name }); + if (alias.viewSpecScript) { + const options = {hideSource: false} + DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY, options); + console.log('in startDrag') + return true; + } + return false; + } + + menuCallback = (x: number, y: number) => { + ContextMenu.Instance.clearItems(); + const layoutItems: ContextMenuProps[] = []; + const docItems: ContextMenuProps[] = []; + const dataDoc = this.props.DataDoc || this.props.Document; + const pivotValue = this.getValue(this.props.heading); + + DocUtils.addDocumentCreatorMenuItems((doc) => { + const key = this.props.pivotField; + doc[key] = this.getValue(this.props.heading); + FormattedTextBox.SelectOnLoad = doc[Id]; + return this.props.addDocument?.(doc); + }, this.props.addDocument, x, y, true, this.props.pivotField, pivotValue); + + 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); + } + }); + ContextMenu.Instance.displayMenu(x, y, undefined, true); + } + + @computed get innards() { + TraceMobx(); + const key = this.props.pivotField; + const heading = this._heading; + const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin; + const evContents = heading ? heading : "25"; + const headingView = this.props.headingObject ? +
+
+ evContents} + SetValue={this.headingChanged} + contents={evContents} + oneLine={true} + /> +
+
: (null); + // const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; + const templatecols = `${this.columnWidth}px `; + const type = this.props.Document.type; + return <> + {headingView} + {
+
+ {this.props.renderChildren(this.props.docList)} +
+ + {!this.props.chromeHidden && type !== DocumentType.PRES ? +
+ style={{ width: this.columnWidth - 20, marginBottom: 10 }}> +
+ +
+
+ +
+ {(this.props.columnHeaders?.length && this.props.columnHeaders.length > 1) && + + } +
+ : null} +
+ } + ; + } + + + render() { + TraceMobx(); + const heading = this._heading; + return ( +
+ {this.innards} +
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx deleted file mode 100644 index 90196ff1c..000000000 --- a/src/client/views/collections/CollectionNoteTakingViewFieldColumn.tsx +++ /dev/null @@ -1,327 +0,0 @@ -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 { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; -import { ScriptField } from "../../../fields/ScriptField"; -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 "./CollectionNoteTakingView.scss"; -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; - docList: Doc[]; - heading: string; - pivotField: string; - chromeHidden?: boolean; - columnHeaders: SchemaHeaderField[] | undefined; - headingObject: SchemaHeaderField | undefined; - 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; - unobserveHeight: (myref: any) => void; - editableViewProps: any; - resizeColumns: (n: number) => void - columnStartXCoords: number[] - PanelWidth: number - maxColWidth: number -} - -@observer -export class CollectionNoteTakingViewFieldColumn extends React.Component { - @observable private _background = "inherit"; - - @computed get columnWidth() { - // base cases - if (!this.props.columnHeaders || !this.props.headingObject || this.props.columnHeaders.length == 1) { - return this.props.maxColWidth - } - const i = this.props.columnHeaders.indexOf(this.props.headingObject) - if (i < 0) { - return this.props.maxColWidth - } - const endColValue = i == this.props.numGroupColumns - 1 ? this.props.PanelWidth : this.props.columnStartXCoords[i+1] - // TODO make the math work here. 35 is half of 70, which is the current width of the divider - return endColValue - this.props.columnStartXCoords[i] - 30 - } - - private dropDisposer?: DragManager.DragDropDisposer; - private _headerRef: React.RefObject = React.createRef(); - - @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); - } - - @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.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; - return value; - } - - @action - 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.pivotField] = 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.pivotField; - const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true }); - newDoc[key] = this.getValue(this.props.heading); - FormattedTextBox.SelectOnLoad = newDoc[Id]; - FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? "" : " "; - return this.props.addDocument?.(newDoc) || false; - } - - @action - deleteColumn = () => { - if (!this.props.columnHeaders) { - return - } - if (this.props.headingObject) { - const index = this.props.columnHeaders.indexOf(this.props.headingObject); - const newIndex = index == 0 ? 1 : index - 1 - const newHeader = this.props.columnHeaders[newIndex]; - this.props.docList.forEach(d => d[this.props.pivotField] = newHeader.heading.toString()) - this.props.columnHeaders.splice(index, 1); - this.props.resizeColumns(this.props.columnHeaders.length) - } - } - - headerDown = (e: React.PointerEvent) => 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[]) => { - console.log('in startDrag') - // 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._width = this.columnWidth; - alias._pivotField = undefined; - let value = this.getValue(this._heading); - value = typeof value === "string" ? `"${value}"` : value; - alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name }); - if (alias.viewSpecScript) { - const options = {hideSource: false} - DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY, options); - console.log('in startDrag') - return true; - } - return false; - } - - menuCallback = (x: number, y: number) => { - ContextMenu.Instance.clearItems(); - const layoutItems: ContextMenuProps[] = []; - const docItems: ContextMenuProps[] = []; - const dataDoc = this.props.DataDoc || this.props.Document; - const pivotValue = this.getValue(this.props.heading); - - DocUtils.addDocumentCreatorMenuItems((doc) => { - const key = this.props.pivotField; - doc[key] = this.getValue(this.props.heading); - FormattedTextBox.SelectOnLoad = doc[Id]; - return this.props.addDocument?.(doc); - }, this.props.addDocument, x, y, true, this.props.pivotField, pivotValue); - - 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); - } - }); - ContextMenu.Instance.displayMenu(x, y, undefined, true); - } - - @computed get innards() { - TraceMobx(); - const key = this.props.pivotField; - const heading = this._heading; - const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin; - const evContents = heading ? heading : "25"; - const headingView = this.props.headingObject ? -
-
- evContents} - SetValue={this.headingChanged} - contents={evContents} - oneLine={true} - /> -
-
: (null); - // const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; - const templatecols = `${this.columnWidth}px `; - const type = this.props.Document.type; - return <> - {headingView} - {
-
- {this.props.renderChildren(this.props.docList)} -
- - {!this.props.chromeHidden && type !== DocumentType.PRES ? -
- style={{ width: this.columnWidth - 20, marginBottom: 10 }}> -
- -
-
- -
- {(this.props.columnHeaders?.length && this.props.columnHeaders.length > 1) && - - } -
- : null} -
- } - ; - } - - - render() { - TraceMobx(); - const heading = this._heading; - return ( -
- {this.innards} -
- ); - } -} \ No newline at end of file -- cgit v1.2.3-70-g09d2