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 --- .../collections/CollectionNoteTakingViewColumn.tsx | 337 +++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 src/client/views/collections/CollectionNoteTakingViewColumn.tsx (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx new file mode 100644 index 000000000..b299eb739 --- /dev/null +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -0,0 +1,337 @@ +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 + // 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 -- cgit v1.2.3-70-g09d2 From 323f846d035e78e729f918ccf2681f5f0834d98e Mon Sep 17 00:00:00 2001 From: ljungster Date: Wed, 22 Jun 2022 10:08:08 -0500 Subject: push before switching to childDocList --- .../views/collections/CollectionNoteTakingView.tsx | 105 ++++++--------------- .../collections/CollectionNoteTakingViewColumn.tsx | 7 -- 2 files changed, 30 insertions(+), 82 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 97fc5cc7c..302e7c890 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -97,7 +97,6 @@ export class CollectionNoteTakingView extends CollectionSubView(); const columnHeaders = this.columnHeaders; const sections = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); let docs = this.childDocs @@ -337,8 +336,6 @@ export class CollectionNoteTakingView extends CollectionSubView { if (DragManager.docsBeingDragged.length && this.childDocList) { - //TODO: update new observable field to empty slice once done - //TODO: how do we update the docs in the column once we switch over? // get the current docs for the column based on the mouse's x coordinate // will use again later, which is why we're saving as local const xCoord = e.clientX - 2 * this.gridGap @@ -347,48 +344,31 @@ export class CollectionNoteTakingView extends CollectionSubView { - //TODO: this isn't getting the actual positions of the doc like I thought it would - // const width = () => this.getDocWidth(doc); - // const displayDoc = this.getDisplayDoc(doc, width) - // const dref = displayDoc.props.dref const noteTakingDocTransform = () => this.getDocTransform(doc); - // const pos0 = noteTakingDocTransform().inverse().transformPoint(0, 0); let pos1 = noteTakingDocTransform().inverse().transformPoint(0, this.getDocHeight(doc) + 2 * this.gridGap)[1]; pos1 += pos0 // updating drop position based on y coordinates const yCoordInBetween = clientY > pos0 && (clientY < pos1 || i == colDocs.length - 1) if (yCoordInBetween) { dropInd = i; - dropAfter = 0; + // dropAfter = 0; if (clientY > (pos0 + pos1) / 2) { - dropAfter = 1; + // dropAfter = 1; } } pos0 = pos1 }) + // we alter the pivot fields of the docs in case they are moved to a new column. + // const colIndex = this.getColumnFromXCoord(xCoord) + // const colHeader = StrCast(this.columnHeaders[colIndex].heading) + // DragManager.docsBeingDragged.forEach(d => d[this.pivotField] = colHeader) + // used to notify sections to re-render + console.log([dropInd, this.getColumnFromXCoord(xCoord)]) this.docsDraggedRowCol = [dropInd, this.getColumnFromXCoord(xCoord)] - console.log(`[${this.docsDraggedRowCol[0]}, ${this.docsDraggedRowCol[1]}]`) - - // since we have row, col, we can send that to an observable value in NoteTaking view - - - // TODO: add the doc back into the proper position and then update childDocs list - // Need to update our list of all docs to properly - // const docs = this.childDocList; - // const docs = this.childDocs; - - // - // const newDocs = DragManager.docsBeingDragged; - // 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); - // } } } @@ -426,58 +406,33 @@ export class CollectionNoteTakingView extends CollectionSubView { - const where = [de.x, de.y]; - let dropInd = -1; - let dropAfter = 0; if (de.complete.docDragData) { - // const docs = this.getDocsFromXCoord(de.x) - const docs = this.childDocs - 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) - 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 = []; - // TODO: I don't think we will actually need any of this, but doesn't hurt to be sure. - 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)); - // doesn't appear to be causing issues, but potentially could create - // if (this.placeHolderDown) { - // docs.splice(0, 1); - // this.placeHolderDown = false - // } - docs.splice(insertInd - offset, 0, ...newDocs); - } + DragManager.docsBeingDragged = [] this.docsDraggedRowCol = [] + // filter out the currently dragged docs from the child docs, since we will insert them later + const rowCol = this.docsDraggedRowCol + const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= this.childDocs.length); // 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; + + const docs = this.childDocs + if (docs && newDocs.length) { + // remove the dragged documents from the childDocList + newDocs.filter(d => docs.indexOf(d) !== -1).forEach(d => docs.splice(docs.indexOf(d), 1)) + // if the doc starts a columnm (or the drop index is undefined), we can just push it to the back. Otherwise we need to add it to the column properly + if (rowCol[0] <= 0) { + docs.splice(docs.length - 1, 0, ...newDocs) + } else { + const colDocs = this.getDocsFromXCoord(de.x) + const previousDoc = colDocs[rowCol[0] - 1] + const previousDocIndex = this.childDocs.findIndex(d => {d[Id] == previousDoc[Id]}) + //TODO: removing the doc instead of doing what we expect it to do + docs.splice(previousDocIndex, 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?.()) { diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index b299eb739..bdcb9c399 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -140,13 +140,6 @@ export class CollectionNoteTakingViewColumn extends React.Component Date: Wed, 3 Aug 2022 13:33:38 -0400 Subject: fixes for dragging notes so that they highlight properly and go to the right place when embedded in freeform views. --- src/client/documents/Documents.ts | 9 +- src/client/util/CurrentUserUtils.ts | 3 +- src/client/util/DragManager.ts | 12 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/StyleProvider.tsx | 8 +- .../views/collections/CollectionNoteTakingView.tsx | 91 +++--- .../collections/CollectionNoteTakingViewColumn.tsx | 358 +++++++++++---------- .../CollectionNoteTakingViewDivider.tsx | 112 +++---- .../views/collections/CollectionStackingView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 30 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- 11 files changed, 332 insertions(+), 303 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 32d7152fd..9d00664ad 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1036,7 +1036,14 @@ export namespace Docs { } export function NoteTakingDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.NoteTaking }, id, undefined, protoId); + return InstanceFromProto( + Prototypes.get(DocumentType.COL), + new List(documents), + { columnHeaders: new List([new SchemaHeaderField('Untitled')]), ...options, _viewType: CollectionViewType.NoteTaking }, + id, + undefined, + protoId + ); } export function MulticolumnDocument(documents: Array, options: DocumentOptions) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 28dc44c25..7856c913b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -135,7 +135,6 @@ export class CurrentUserUtils { return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts)); } - /// Initializes templates that can be applied to notes static setupNoteTemplates(doc: Doc, field="template-notes") { const tempNotes = DocCast(doc[field]); @@ -255,6 +254,7 @@ export class CurrentUserUtils { creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist }[] = [ {key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _autoHeight: true }}, + {key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200 }}, {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100 }}, {key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _fitWidth:false, _backgroundGridShow: true, }}, {key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }}, @@ -280,6 +280,7 @@ export class CurrentUserUtils { return [ { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, }, + { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, }, { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab), scripts: { onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, }, { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, }, diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 3a1bb1673..f4987cf34 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,4 +1,4 @@ -import { action } from 'mobx'; +import { action, observable, runInAction } from 'mobx'; import { DateField } from '../../fields/DateField'; import { Doc, Field, Opt } from '../../fields/Doc'; import { List } from '../../fields/List'; @@ -320,7 +320,7 @@ export namespace DragManager { y: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()), }; } - export let docsBeingDragged: Doc[] = []; + export let docsBeingDragged: Doc[] = observable([] as Doc[]); export let CanEmbed = false; export let DocDragData: DocumentDragData | undefined; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { @@ -349,13 +349,13 @@ export namespace DragManager { xs: number[] = [], ys: number[] = []; - docsBeingDragged = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : []; const elesCont = { left: Number.MAX_SAFE_INTEGER, right: Number.MIN_SAFE_INTEGER, top: Number.MAX_SAFE_INTEGER, bottom: Number.MIN_SAFE_INTEGER, }; + const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : []; const dragElements = eles.map(ele => { if (!ele.parentNode) dragDiv.appendChild(ele); const dragElement = ele.parentNode === dragDiv ? ele : (ele.cloneNode(true) as HTMLElement); @@ -405,7 +405,7 @@ export namespace DragManager { }); dragLabel.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0) - 20}px)`; - if (docsBeingDragged.length) { + if (docsToDrag.length) { const pdfBox = dragElement.getElementsByTagName('canvas'); const pdfBoxSrc = ele.getElementsByTagName('canvas'); Array.from(pdfBox) @@ -429,6 +429,8 @@ export namespace DragManager { return dragElement; }); + runInAction(() => docsBeingDragged.push(...docsToDrag)); + const hideDragShowOriginalElements = (hide: boolean) => { dragLabel.style.display = hide ? '' : 'none'; !hide && dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); @@ -456,7 +458,7 @@ export namespace DragManager { SnappingManager.SetIsDragging(false); SnappingManager.clearSnapLines(); batch.end(); - docsBeingDragged = []; + docsBeingDragged.length = 0; }); var startWindowDragTimer: any; const moveHandler = (e: PointerEvent) => { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c53e61699..0db9eab69 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -351,7 +351,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @action onPointerDown = (e: React.PointerEvent): void => { - DragManager.docsBeingDragged = SelectionManager.Views().map(dv => dv.rootDoc); + DragManager.docsBeingDragged.push(...SelectionManager.Views().map(dv => dv.rootDoc)); this._inkDragDocs = DragManager.docsBeingDragged .filter(doc => doc.type === DocumentType.INK) .map(doc => { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 692f7b98e..a83163eb0 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -110,8 +110,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt (props?.PanelHeight() || 0) ? 5 : 10) : 0; case StyleProp.HeaderMargin: - return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || doc?.type === DocumentType.LABEL) && + return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || + (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || + doc?.type === DocumentType.LABEL) && showTitle() && !StrCast(doc?.showTitle).includes(':hover') ? 15 diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index f442559fb..1854a4213 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,6 +1,6 @@ import React = require('react'); import { CursorProperty } from 'csstype'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +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'; @@ -21,10 +21,12 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { FieldViewProps } from '../nodes/FieldView'; +import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import './CollectionNoteTakingView.scss'; import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn'; -import CollectionNoteTakingViewDivider from './CollectionNoteTakingViewDivider'; +import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider'; import { CollectionSubView } from './CollectionSubView'; const _global = (window /* browser */ || global) /* node */ as any; @@ -40,7 +42,6 @@ export type collectionNoteTakingViewProps = { @observer export class CollectionNoteTakingView extends CollectionSubView>() { - _pivotFieldDisposer?: IReactionDisposer; _autoHeightDisposer?: IReactionDisposer; _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); @@ -54,10 +55,10 @@ export class CollectionNoteTakingView extends CollectionSubView pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout); @@ -90,7 +91,7 @@ export class CollectionNoteTakingView extends CollectionSubView([new SchemaHeaderField('New Column')]); + this.dataDoc.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 { @@ -126,18 +127,16 @@ export class CollectionNoteTakingView extends CollectionSubView { - docIdsToRemove.add(d[Id]); - }); + DragManager.docsBeingDragged.forEach(d => docIdsToRemove.add(d[Id])); docs = docs.filter(d => !docIdsToRemove.has(d[Id])); } // this will sort the docs into the correct columns (minus the ones you're currently dragging) docs.map(d => { - if (!d[this.pivotField]) { - d[this.pivotField] = columnHeaders.length > 0 ? columnHeaders[0].heading : `New Column`; + if (!d[this.notetakingCategoryField]) { + d[this.notetakingCategoryField] = columnHeaders.length > 0 ? columnHeaders[0].heading : `New Column`; } - const sectionValue = d[this.pivotField] as object; + const sectionValue = d[this.notetakingCategoryField] as object; // look for if header exists already const existingHeader = columnHeaders.find(sh => sh.heading === sectionValue.toString()); @@ -156,14 +155,15 @@ export class CollectionNoteTakingView extends CollectionSubView { + setTimeout( + action(() => (this.docsDraggedRowCol.length = 0)), + 100 + ); + }; componentDidMount() { super.componentDidMount?.(); - // reset section headers when a new filter is inputted - this._pivotFieldDisposer = reaction( - () => this.pivotField, - () => (this.layoutDoc._columnHeaders = new List()) - ); - + document.addEventListener('pointerup', this.removeDocDragHighlight, true); 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', '')))))) @@ -171,8 +171,8 @@ export class CollectionNoteTakingView extends CollectionSubView, property: string) => { + if (property === StyleProp.BoxShadow && doc && DragManager.docsBeingDragged.includes(doc)) { + return `#9c9396 ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}`; + } if (property === StyleProp.Opacity && doc) { if (this.props.childOpacity) { return this.props.childOpacity(); @@ -258,9 +261,9 @@ export class CollectionNoteTakingView extends CollectionSubView sh.heading === castedSectionValue); const colStartXCoords = this.columnStartXCoords; @@ -364,20 +367,14 @@ export class CollectionNoteTakingView extends CollectionSubView { - const noteTakingDocTransform = () => this.getDocTransform(doc); - let pos1 = noteTakingDocTransform() - .inverse() - .transformPoint(0, this.getDocHeight(doc) + 2 * this.gridGap)[1]; + let pos1 = this.getDocHeight(doc) + 2 * this.gridGap; pos1 += pos0; // updating drop position based on y coordinates const yCoordInBetween = clientY > pos0 && (clientY < pos1 || i == colDocs.length - 1); @@ -393,10 +390,10 @@ export class CollectionNoteTakingView extends CollectionSubView (d[this.pivotField] = colHeader)); + DragManager.docsBeingDragged.forEach(d => (d[this.notetakingCategoryField] = colHeader)); // used to notify sections to re-render - // console.log([dropInd, this.getColumnFromXCoord(xCoord)]) - this.docsDraggedRowCol = [dropInd, this.getColumnFromXCoord(xCoord)]; + this.docsDraggedRowCol.length = 0; + this.docsDraggedRowCol.push(dropInd, this.getColumnFromXCoord(xCoord)); } }; @@ -425,7 +422,7 @@ export class CollectionNoteTakingView extends CollectionSubView { if (d instanceof Promise) return; - const sectionValue = d[this.pivotField] as object; + const sectionValue = d[this.notetakingCategoryField] as object; if (sectionValue.toString() == colHeader) { docsMatchingHeader.push(d); } @@ -434,13 +431,24 @@ export class CollectionNoteTakingView extends CollectionSubView { + const docView = fieldProps.DocumentView?.(); + if (docView && (e.ctrlKey || docView.rootDoc._singleLine) && ['Enter'].includes(e.key)) { + e.stopPropagation?.(); + const newDoc = Doc.MakeCopy(docView.rootDoc, true); + Doc.GetProto(newDoc).text = undefined; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + return this.addDocument?.(newDoc); + } + }; + @undoBatch @action onInternalDrop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData) { if (super.onInternalDrop(e, de)) { - DragManager.docsBeingDragged = []; - // this.docsDraggedRowCol = [] // filter out the currently dragged docs from the child docs, since we will insert them later const rowCol = this.docsDraggedRowCol; const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= this.childDocs.length); // 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). @@ -456,10 +464,9 @@ export class CollectionNoteTakingView extends CollectionSubView object[]; renderChildren: (docs: Doc[]) => JSX.Element[]; addDocument: (doc: Doc | Doc[]) => boolean; @@ -48,37 +48,37 @@ interface CSVFieldColumnProps { observeHeight: (myref: any) => void; unobserveHeight: (myref: any) => void; editableViewProps: any; - resizeColumns: (n: number) => void - columnStartXCoords: number[] - PanelWidth: number - maxColWidth: number + 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"; + @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 + // 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"; + @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? @@ -90,7 +90,7 @@ export class CollectionNoteTakingViewColumn extends React.Component { const parsed = parseInt(value); if (!isNaN(parsed)) return parsed; - if (value.toLowerCase().indexOf("true") > -1) return true; - if (value.toLowerCase().indexOf("false") > -1) return false; + if (value.toLowerCase().indexOf('true') > -1) return true; + if (value.toLowerCase().indexOf('false') > -1) return false; return value; - } + }; @action headingChanged = (value: string, shiftDown?: boolean) => { @@ -117,7 +117,7 @@ export class CollectionNoteTakingViewColumn extends React.Component i.heading).indexOf(castedValue.toString()) !== -1) { return false; } - this.props.docList.forEach(d => d[this.props.pivotField] = 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; @@ -125,11 +125,11 @@ export class CollectionNoteTakingViewColumn extends React.Component SnappingManager.GetIsDragging() && (this._background = "#b4b4b4"); - @action pointerLeave = () => this._background = "inherit"; - textCallback = (char: string) => this.addNewTextDoc("-typed text-", false, true); + @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) => { @@ -139,46 +139,46 @@ export class CollectionNoteTakingViewColumn extends React.Component { if (!this.props.columnHeaders) { - return + 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) + 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 + //TODO: I think this is where I'm supposed to edit stuff startDrag = (e: PointerEvent, down: number[], delta: number[]) => { - console.log('in startDrag') + 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; + 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} + const options = { hideSource: false }; DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY, options); - console.log('in startDrag') + console.log('in startDrag'); return true; } return false; - } + }; menuCallback = (x: number, y: number) => { ContextMenu.Instance.clearItems(); @@ -187,44 +187,62 @@ export class CollectionNoteTakingViewColumn extends React.Component { - 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); + 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); + 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); } - 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); + }, + 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; } - 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 }); + }, + 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); @@ -233,98 +251,100 @@ export class CollectionNoteTakingViewColumn extends React.Component -
- evContents} - SetValue={this.headingChanged} - contents={evContents} - oneLine={true} - /> +
+ evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} />
-
: (null); + + ) : 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)} -
+ 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} -
- } - ; + {!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 ( -
+ ref={this.createColumnDropRef} + onPointerEnter={this.pointerEntered} + onPointerLeave={this.pointerLeave}> {this.innards} -
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx index ed5dc3715..7d31b3193 100644 --- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx @@ -1,61 +1,63 @@ -import { action, observable } from "mobx"; -import * as React from "react"; +import { action, observable } from 'mobx'; +import * as React from 'react'; interface DividerProps { - index: number - xMargin: number - setColumnStartXCoords: (movementX: number, colIndex: number) => void + index: number; + xMargin: number; + setColumnStartXCoords: (movementX: number, colIndex: number) => void; } -export default class Divider extends React.Component{ - @observable private isHoverActive = false; - @observable private isResizingActive = false; - - @action - private registerResizing = (e: React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - window.addEventListener("pointermove", this.onPointerMove); - window.addEventListener("pointerup", this.onPointerUp); - this.isResizingActive = true; - } +export class CollectionNoteTakingViewDivider extends React.Component { + @observable private isHoverActive = false; + @observable private isResizingActive = false; - @action - private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - } + @action + private registerResizing = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + window.removeEventListener('pointermove', this.onPointerMove); + window.removeEventListener('pointerup', this.onPointerUp); + window.addEventListener('pointermove', this.onPointerMove); + window.addEventListener('pointerup', this.onPointerUp); + this.isResizingActive = true; + }; - @action - onPointerMove = ({ movementX }: PointerEvent) => { - this.props.setColumnStartXCoords(movementX, this.props.index) - } - - render() { - return ( -
this.isHoverActive = true)} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} - > -
this.registerResizing(e)} - style={{ - height: "95%", - width: 12, - borderRight: "4px solid #282828", - borderLeft: "4px solid #282828", - margin: "0px 10px" - }} - /> -
- ) - } -} \ No newline at end of file + @action + private onPointerUp = () => { + this.isResizingActive = false; + this.isHoverActive = false; + window.removeEventListener('pointermove', this.onPointerMove); + window.removeEventListener('pointerup', this.onPointerUp); + }; + + @action + onPointerMove = ({ movementX }: PointerEvent) => { + this.props.setColumnStartXCoords(movementX, this.props.index); + }; + + render() { + return ( +
(this.isHoverActive = true))} + onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}> +
this.registerResizing(e)} + style={{ + height: '95%', + width: 12, + borderRight: '4px solid #282828', + borderLeft: '4px solid #282828', + margin: '0px 10px', + }} + /> +
+ ); + } +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 1927db51e..ef68cadd7 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -447,8 +447,6 @@ export class CollectionStackingView extends CollectionSubView docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1)); docs.splice(insertInd - offset, 0, ...newDocs); } + // reset drag manager docs, because we just dropped + DragManager.docsBeingDragged.length = 0; } } 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' }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index afb618b34..1ee1aec5a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -156,9 +156,7 @@ export interface DocumentViewSharedProps { scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document createNewFilterDoc?: () => void; updateFilterDoc?: (doc: Doc) => void; - // Parker added both of these - originalBackgroundColor?: string; - isNoteTakingView?: boolean; + dontHideOnDrag?: boolean; } // these props are specific to DocuentViews @@ -494,12 +492,6 @@ export class DocumentViewInternal extends DocComponent { - doc.backgroundColor = "#C9DAEF"; - doc.opacity = 0.5; - }); - } const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props .ScreenToLocalTransform() @@ -511,22 +503,16 @@ export class DocumentViewInternal extends DocComponent (ffview.ChildDrag = this.props.DocumentView())); - DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStar && !this.props.isNoteTakingView)}, - () => setTimeout(action(() => { - ffview && (ffview.ChildDrag = undefined) - //TODO: is there a better way than adding another field to the props? Not quite sure how "this" works tbh - if (this.props.isNoteTakingView) { - this.props.Document.backgroundColor = ""; - this.props.Document.opacity = 1; - } - }))); // this needs to happen after the drop event is processed. + ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView())); + DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) }, () => + setTimeout(action(() => ffview && (ffview.ChildDrag = undefined))) + ); // this needs to happen after the drop event is processed. ffview?.setupDragLines(false); } } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b8ee89ef2..add83f4e0 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1001,7 +1001,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }), ({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => { const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight)); - autoHeight && newHeight && this.props.setHeight?.(newHeight); + if (autoHeight && newHeight && newHeight !== this.rootDoc.height) { + this.props.setHeight?.(newHeight); + } }, { fireImmediately: true } ); @@ -1695,7 +1697,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this.rootDoc[this.fieldKey + '-scrollHeight'] = scrollHeight); - if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) { + if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) { setScrollHeight(); } else { setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... -- cgit v1.2.3-70-g09d2 From 29d0c334b0bb28b6ae6e1f94fae12d1b4ee0e545 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 3 Aug 2022 18:59:00 -0400 Subject: fixed dragging external documents onto notetaking view --- .../collections/CollectionNoteTakingView.scss | 152 ++++++++++----------- .../views/collections/CollectionNoteTakingView.tsx | 66 +++------ .../collections/CollectionNoteTakingViewColumn.tsx | 3 +- 3 files changed, 94 insertions(+), 127 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss index a878033ed..fe98f307e 100644 --- a/src/client/views/collections/CollectionNoteTakingView.scss +++ b/src/client/views/collections/CollectionNoteTakingView.scss @@ -1,50 +1,50 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .collectionNoteTakingView-DocumentButtons { - display: flex; - justify-content: space-between; - margin: auto; + display: flex; + justify-content: space-between; + margin: auto; } .collectionNoteTakingView-addDocumentButton { - display: flex; - overflow: hidden; - margin: auto; - width: 100%; - overflow: ellipses; - - .editableView-container-editing-oneLine, - .editableView-container-editing { - color: grey; - padding: 10px; - width: 100%; - } - - .editableView-input:hover, - .editableView-container-editing:hover, - .editableView-container-editing-oneLine:hover { - cursor: text - } - - .editableView-input { - outline-color: black; - letter-spacing: 2px; - color: grey; - border: 0px; - padding: 12px 10px 11px 10px; - } - - font-size: 75%; - letter-spacing: 2px; - cursor: pointer; - - .editableView-input { - outline-color: black; - letter-spacing: 2px; - color: grey; - border: 0px; - padding: 12px 10px 11px 10px; - } + display: flex; + overflow: hidden; + margin: auto; + width: 100%; + overflow: ellipses; + + .editableView-container-editing-oneLine, + .editableView-container-editing { + color: grey; + padding: 10px; + width: 100%; + } + + .editableView-input:hover, + .editableView-container-editing:hover, + .editableView-container-editing-oneLine:hover { + cursor: text; + } + + .editableView-input { + outline-color: black; + letter-spacing: 2px; + color: grey; + border: 0px; + padding: 12px 10px 11px 10px; + } + + font-size: 75%; + letter-spacing: 2px; + cursor: pointer; + + .editableView-input { + outline-color: black; + letter-spacing: 2px; + color: grey; + border: 0px; + padding: 12px 10px 11px 10px; + } } .collectionNoteTakingView { @@ -83,21 +83,13 @@ overflow-y: auto; overflow-x: hidden; flex-wrap: wrap; - transition: top .5s; + transition: top 0.5s; - >div { + > div { position: relative; display: block; } - .collectionNoteTakingViewFieldColumn { - height: max-content; - } - - .collectionNoteTakingViewFieldColumnDragging { - height: 100%; - } - .collectionSchemaView-previewDoc { height: 100%; position: absolute; @@ -144,33 +136,33 @@ // Documents in NoteTaking view .collectionNoteTakingView-columnDoc { display: flex; - // margin: auto; // Removed auto so that it is no longer center aligned - this could be something we change + // margin: auto; // Removed auto so that it is no longer center aligned - this could be something we change position: relative; &:hover { - .hoverButtons{ - opacity: 1; - } + .hoverButtons { + opacity: 1; + } } .hoverButtons { - display: flex; - opacity: 0; - position: absolute; - height: 100%; - left: -35px; - justify-content: center; - align-items: center; - padding: 0px 10px; - - .buttonWrapper { - padding: 3px; - border-radius: 3px; - - &:hover { - background: rgba(0, 0, 0, 0.26); + display: flex; + opacity: 0; + position: absolute; + height: 100%; + left: -35px; + justify-content: center; + align-items: center; + padding: 0px 10px; + + .buttonWrapper { + padding: 3px; + border-radius: 3px; + + &:hover { + background: rgba(0, 0, 0, 0.26); + } } - } } } @@ -200,7 +192,7 @@ span::before, span::after { - content: ""; + content: ''; width: 50%; border-top: dashed gray 1px; position: relative; @@ -241,7 +233,7 @@ .editableView-input:hover, .editableView-container-editing:hover, .editableView-container-editing-oneLine:hover { - cursor: text + cursor: text; } .collectionNoteTakingView-sectionHeader-subCont { @@ -287,7 +279,7 @@ height: 100%; display: none; - [class*="css"] { + [class*='css'] { max-width: 102px; } @@ -329,7 +321,7 @@ height: 100%; display: none; - [class*="css"] { + [class*='css'] { max-width: 102px; } @@ -338,7 +330,6 @@ } .collectionNoteTakingView-optionPicker { - .optionOptions { display: inline; } @@ -398,7 +389,7 @@ .editableView-input:hover, .editableView-container-editing:hover, .editableView-container-editing-oneLine:hover { - cursor: text + cursor: text; } .editableView-input { @@ -451,7 +442,7 @@ top: 4px; border-radius: 50% 50%; background-color: #fff; - content: " "; + content: ' '; cursor: pointer; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); -webkit-transform: scale(1); @@ -481,7 +472,6 @@ } @media only screen and (max-device-width: 480px) { - .collectionNoteTakingView .collectionNoteTakingView-columnDragger, .collectionNoteTakingView-columnDragger { width: 0.1; @@ -489,4 +479,4 @@ opacity: 0; font-size: 0; } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 1854a4213..989719c80 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -363,30 +363,30 @@ export class CollectionNoteTakingView extends CollectionSubView { - if (DragManager.docsBeingDragged.length && this.childDocList) { + onPointerOver = (ex: number, ey: number) => { + console.log('Pover9ing = '); + if (this.childDocList) { // get the current docs for the column based on the mouse's x coordinate // will use again later, which is why we're saving as local - const xCoord = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0] - 2 * this.gridGap; + const xCoord = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[0] - 2 * this.gridGap; const colDocs = this.getDocsFromXCoord(xCoord); // get the index for where you need to insert the doc you are currently dragging - const clientY = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[1]; + const clientY = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[1]; let dropInd = -1; let pos0 = (this.refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2; colDocs.forEach((doc, i) => { let pos1 = this.getDocHeight(doc) + 2 * this.gridGap; pos1 += pos0; // updating drop position based on y coordinates - const yCoordInBetween = clientY > pos0 && (clientY < pos1 || i == colDocs.length - 1); - if (yCoordInBetween) { + const yCoordInBetween = clientY > pos0 && clientY < pos1; + if (yCoordInBetween || (clientY < pos0 && i === 0)) { dropInd = i; - // dropAfter = 0; - if (clientY > (pos0 + pos1) / 2) { - // dropAfter = 1; - } + } else if (i === colDocs.length - 1 && dropInd === -1) { + dropInd = !colDocs.includes(DragManager.docsBeingDragged.lastElement()) ? i + 1 : i; } pos0 = pos1; }); + console.log('Pover = ' + dropInd + ' ' + this.getColumnFromXCoord(xCoord)); // we alter the pivot fields of the docs in case they are moved to a new column. const colIndex = this.getColumnFromXCoord(xCoord); const colHeader = StrCast(this.columnHeaders[colIndex].heading); @@ -495,43 +495,20 @@ export class CollectionNoteTakingView extends CollectionSubView => { - const where = [e.clientX, e.clientY]; - let targInd = -1; - 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]; - const docs = this.childDocList; - if (docs) { - docs.splice(docs.length - 1, 1); - docs.splice(targInd, 0, newDoc); - } + const targInd = this.docsDraggedRowCol?.[0] || 0; + super.onExternalDrop(e, {}, docus => { + this.onPointerOver(e.clientX, e.clientY); + docus?.map(doc => this.addDocument(doc)); + const newDoc = this.childDocs.lastElement(); + const docs = this.childDocList; + if (docs && targInd !== -1) { + docs.splice(docs.length - 1, 1); + docs.splice(targInd, 0, newDoc); } + this.removeDocDragHighlight(); }); }; - // setDocsForColHeader = (key: string, docs: Doc[]) => { - // this._docsByColumnHeader = new Map(this._docsByColumnHeader.set(key, docs)) - // } - headings = () => Array.from(this.Sections); refList: any[] = []; @@ -723,7 +700,8 @@ export class CollectionNoteTakingView extends CollectionSubView (this._scroll = e.currentTarget.scrollTop))} - onPointerOver={this.onPointerOver} + onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))} + onPointerOver={e => this.onPointerOver(e.clientX, e.clientY)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}> diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 55d032498..5ba262418 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -286,7 +286,7 @@ export class CollectionNoteTakingViewColumn extends React.Component {headingView} { -
+
Date: Thu, 4 Aug 2022 11:01:37 -0400 Subject: fixed notetaking view to have an 'unset' category for unassigned notes. fixed pivot view to not fail when docs have no width. --- .../views/collections/CollectionNoteTakingView.tsx | 30 +++++---- .../collections/CollectionNoteTakingViewColumn.tsx | 2 + .../CollectionFreeFormLayoutEngines.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - src/client/views/nodes/FilterBox.tsx | 2 +- src/client/views/nodes/FunctionPlotBox.tsx | 76 ++++++++++++---------- .../views/nodes/formattedText/RichTextMenu.tsx | 13 ---- 7 files changed, 66 insertions(+), 64 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 989719c80..f24b98621 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -55,10 +55,18 @@ export class CollectionNoteTakingView extends CollectionSubView { + return !d[this.notetakingCategoryField] && !columnHeaders.find(sh => sh.heading === 'unset'); + }); + if (needsUnsetCategory) { + columnHeaders.push(new SchemaHeaderField('unset')); + } + return columnHeaders; } @computed get notetakingCategoryField() { - return 'noteTakingCategory'; + return 'NotetakingCategory'; } @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout); @@ -120,8 +128,8 @@ export class CollectionNoteTakingView extends CollectionSubView(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); let docs = this.childDocs; + const sections = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); const rowCol = this.docsDraggedRowCol; // filter out the currently dragged docs from the child docs, since we will insert them later @@ -133,10 +141,7 @@ export class CollectionNoteTakingView extends CollectionSubView { - if (!d[this.notetakingCategoryField]) { - d[this.notetakingCategoryField] = columnHeaders.length > 0 ? columnHeaders[0].heading : `New Column`; - } - const sectionValue = d[this.notetakingCategoryField] as object; + const sectionValue = (d[this.notetakingCategoryField] as object) ?? `unset`; // look for if header exists already const existingHeader = columnHeaders.find(sh => sh.heading === sectionValue.toString()); @@ -310,7 +315,7 @@ export class CollectionNoteTakingView extends CollectionSubView sh.heading === castedSectionValue); const colStartXCoords = this.columnStartXCoords; @@ -364,7 +369,6 @@ export class CollectionNoteTakingView extends CollectionSubView { - console.log('Pover9ing = '); if (this.childDocList) { // get the current docs for the column based on the mouse's x coordinate // will use again later, which is why we're saving as local @@ -386,7 +390,6 @@ export class CollectionNoteTakingView extends CollectionSubView { if (d instanceof Promise) return; - const sectionValue = d[this.notetakingCategoryField] as object; + const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset'; if (sectionValue.toString() == colHeader) { docsMatchingHeader.push(d); } @@ -619,7 +622,7 @@ export class CollectionNoteTakingView extends CollectionSubView); + eles.push(); } } return eles; @@ -686,7 +689,7 @@ export class CollectionNoteTakingView extends CollectionSubView {buttonMenu || noviceExplainer ? ( -
+
{buttonMenu ? this.buttonMenu : null} {Doc.UserDoc().noviceMode && noviceExplainer ?
{noviceExplainer}
: null}
@@ -694,6 +697,7 @@ export class CollectionNoteTakingView extends CollectionSubView { + console.log('HEADING CH'); const castedValue = this.getValue(value); if (castedValue) { if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { @@ -255,6 +256,7 @@ export class CollectionNoteTakingViewColumn extends React.Component panelDim[1] ? panelDim[1] / (aggBounds.b - aggBounds.y) : wscale; + const width = aggBounds.r - aggBounds.x === 0 ? 1 : aggBounds.r - aggBounds.x; + const height = aggBounds.b - aggBounds.y === 0 ? 1 : aggBounds.b - aggBounds.y; + const wscale = panelDim[0] / width; + let scale = wscale * height > panelDim[1] ? panelDim[1] / height : wscale; if (Number.isNaN(scale)) scale = 1; Array.from(docMap.entries()) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3e938ec1c..82b377dfa 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -496,7 +496,6 @@ export class CollectionFreeFormView extends CollectionSubView() { @observable _loaded = false; componentDidMount() { reaction( - () => DocListCastAsync(this.layoutDoc.data), + () => DocListCastAsync(this.layoutDoc[this.fieldKey]), async activeTabsAsync => { const activeTabs = await activeTabsAsync; activeTabs && (await SearchBox.foreachRecursiveDocAsync(activeTabs, emptyFunction)); diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 3ab0a3ff2..15d0f88f6 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -1,4 +1,4 @@ -import functionPlot from "function-plot"; +import functionPlot from 'function-plot'; import { action, computed, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -12,7 +12,6 @@ import { Docs } from '../../documents/Documents'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; - const EquationSchema = createSchema({}); type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>; @@ -20,74 +19,83 @@ const EquationDocument = makeInterface(EquationSchema, documentSchema); @observer export class FunctionPlotBox extends ViewBoxBaseComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FunctionPlotBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(FunctionPlotBox, fieldKey); + } public static GraphCount = 0; _plot: any; - _plotId = ""; + _plotId = ''; _plotEle: any; constructor(props: any) { super(props); - this._plotId = "graph" + FunctionPlotBox.GraphCount++; + this._plotId = 'graph' + FunctionPlotBox.GraphCount++; } componentDidMount() { this.props.setContentView?.(this); - reaction(() => [DocListCast(this.dataDoc.data).lastElement()?.text, this.layoutDoc.width, this.layoutDoc.height, this.dataDoc.xRange, this.dataDoc.yRange], - () => this.createGraph()); + reaction( + () => [DocListCast(this.dataDoc[this.fieldKey]).lastElement()?.text, this.layoutDoc.width, this.layoutDoc.height, this.dataDoc.xRange, this.dataDoc.yRange], + () => this.createGraph() + ); } getAnchor = () => { const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc }); anchor.xRange = new List(Array.from(this._plot.options.xAxis.domain)); anchor.yRange = new List(Array.from(this._plot.options.yAxis.domain)); return anchor; - } + }; @action scrollFocus = (doc: Doc, smooth: boolean) => { - this.dataDoc.xRange = new List(Array.from(Cast(doc.xRange, listSpec("number"), Cast(this.dataDoc.xRange, listSpec("number"), [-10, 10])))); - this.dataDoc.yRange = new List(Array.from(Cast(doc.yRange, listSpec("number"), Cast(this.dataDoc.xRange, listSpec("number"), [-1, 9])))); + this.dataDoc.xRange = new List(Array.from(Cast(doc.xRange, listSpec('number'), Cast(this.dataDoc.xRange, listSpec('number'), [-10, 10])))); + this.dataDoc.yRange = new List(Array.from(Cast(doc.yRange, listSpec('number'), Cast(this.dataDoc.xRange, listSpec('number'), [-1, 9])))); return 0; - } + }; createGraph = (ele?: HTMLDivElement) => { this._plotEle = ele || this._plotEle; const width = this.props.PanelWidth(); const height = this.props.PanelHeight(); - const fn = StrCast(DocListCast(this.dataDoc.data).lastElement()?.text, "x^2").replace(/\\frac\{(.*)\}\{(.*)\}/, "($1/$2)"); + const fn = StrCast(DocListCast(this.dataDoc.data).lastElement()?.text, 'x^2').replace(/\\frac\{(.*)\}\{(.*)\}/, '($1/$2)'); try { this._plot = functionPlot({ - target: "#" + this._plotEle.id, + target: '#' + this._plotEle.id, width, height, - xAxis: { domain: Cast(this.dataDoc.xRange, listSpec("number"), [-10, 10]) }, - yAxis: { domain: Cast(this.dataDoc.xRange, listSpec("number"), [-1, 9]) }, + xAxis: { domain: Cast(this.dataDoc.xRange, listSpec('number'), [-10, 10]) }, + yAxis: { domain: Cast(this.dataDoc.xRange, listSpec('number'), [-1, 9]) }, grid: true, data: [ { fn, // derivative: { fn: "2 * x", updateOnMouseMove: true } - } - ] + }, + ], }); } catch (e) { console.log(e); } - } + }; @computed get theGraph() { - return
r && this.createGraph(r)} style={{ position: "absolute", width: "100%", height: "100%" }} - onPointerDown={e => e.stopPropagation()} />; + return
r && this.createGraph(r)} style={{ position: 'absolute', width: '100%', height: '100%' }} onPointerDown={e => e.stopPropagation()} />; } render() { TraceMobx(); - return (
- {this.theGraph} -
-
); + return ( +
+ {this.theGraph} +
+
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 21326efaa..2a77210ae 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -60,7 +60,6 @@ export class RichTextMenu extends AntimodeMenu { @observable private showLinkDropdown: boolean = false; _reaction: IReactionDisposer | undefined; - _delayHide = false; constructor(props: Readonly<{}>) { super(props); runInAction(() => { @@ -70,16 +69,6 @@ export class RichTextMenu extends AntimodeMenu { }); } - componentDidMount() { - this._reaction = reaction( - () => SelectionManager.Views(), - () => this._delayHide && !(this._delayHide = false) && this.fadeOut(true) - ); - } - componentWillUnmount() { - this._reaction?.(); - } - @computed get noAutoLink() { return this._noLinkActive; } @@ -108,8 +97,6 @@ export class RichTextMenu extends AntimodeMenu { return this._activeAlignment; } - public delayHide = () => (this._delayHide = true); - @action public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: any) { if (this._linkToRef.current?.getBoundingClientRect().width) { -- cgit v1.2.3-70-g09d2 From abdbf5c657b9d1d9a26a4d46dda2097be152f4ff Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 4 Aug 2022 17:03:21 -0400 Subject: fixed undo/redo for notetaking view. fixed list undo/redo for schemaheaderfields -- not very elegant though. --- .../views/collections/CollectionNoteTakingView.tsx | 52 ++++++++-------- .../collections/CollectionNoteTakingViewColumn.tsx | 39 ++---------- src/fields/List.ts | 72 ++++++++++++---------- src/fields/util.ts | 12 +++- 4 files changed, 80 insertions(+), 95 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index f24b98621..1bf5b7d86 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -42,12 +42,10 @@ export type collectionNoteTakingViewProps = { @observer export class CollectionNoteTakingView extends CollectionSubView>() { - _autoHeightDisposer?: IReactionDisposer; + _disposers: { [key: string]: IReactionDisposer } = {}; _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); - // _docXfs: { height: () => number, width: () => number, noteTakingDocTransform: () => Transform }[] = []; - // @observable _docsByColumnHeader = new Map(); - //TODO: need to make sure that we save the mapping + @observable columnStartXCoords: number[] = []; @observable docsDraggedRowCol: number[] = []; @observable _cursor: CursorProperty = 'grab'; @observable _scroll = 0; // used to force the document decoration to update when scrolling @@ -86,7 +84,6 @@ export class CollectionNoteTakingView extends CollectionSubView([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); + this.resizeColumns(this.columnHeaders.length); } } @@ -126,7 +121,8 @@ export class CollectionNoteTakingView extends CollectionSubView(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); @@ -169,16 +165,21 @@ export class CollectionNoteTakingView extends CollectionSubView 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._disposers.headers = reaction( + () => this.columnHeaders.slice(), + headers => this.resizeColumns(headers.length), + { fireImmediately: true } + ); } componentWillUnmount() { document.removeEventListener('pointerup', this.removeDocDragHighlight, true); super.componentWillUnmount(); - this._autoHeightDisposer?.(); + Object.keys(this._disposers).forEach(key => this._disposers[key]()); } @action @@ -315,9 +316,8 @@ export class CollectionNoteTakingView extends CollectionSubView sh.heading === castedSectionValue); + const heading = StrCast(d[this.notetakingCategoryField], 'unset'); + const existingHeader = this.columnHeaders.find(sh => sh.heading === heading); const colStartXCoords = this.columnStartXCoords; if (!existingHeader) { return 1000; @@ -352,6 +352,7 @@ export class CollectionNoteTakingView extends CollectionSubView { const totalWidth = this.PanelWidth; const dividerWidth = 32; @@ -368,8 +369,8 @@ export class CollectionNoteTakingView extends CollectionSubView { - if (this.childDocList) { + onPointerOver = (buttons: boolean, ex: number, ey: number) => { + if (this.childDocList && buttons) { // get the current docs for the column based on the mouse's x coordinate // will use again later, which is why we're saving as local const xCoord = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[0] - 2 * this.gridGap; @@ -500,7 +501,7 @@ export class CollectionNoteTakingView extends CollectionSubView => { const targInd = this.docsDraggedRowCol?.[0] || 0; super.onExternalDrop(e, {}, docus => { - this.onPointerOver(e.clientX, e.clientY); + this.onPointerOver(true, e.clientX, e.clientY); docus?.map(doc => this.addDocument(doc)); const newDoc = this.childDocs.lastElement(); const docs = this.childDocList; @@ -515,6 +516,11 @@ export class CollectionNoteTakingView extends CollectionSubView Array.from(this.Sections); refList: any[] = []; + editableViewProps = () => ({ + GetValue: () => '', + SetValue: this.addGroup, + contents: '+ New Column', + }); sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { const type = 'number'; @@ -544,7 +550,7 @@ export class CollectionNoteTakingView extends CollectionSubView '', - SetValue: this.addGroup, - contents: '+ New Column', - }} + editableViewProps={this.editableViewProps} /> ); }; @@ -622,7 +624,7 @@ export class CollectionNoteTakingView extends CollectionSubView); + eles.push(); } } return eles; @@ -705,7 +707,7 @@ export class CollectionNoteTakingView extends CollectionSubView (this._scroll = e.currentTarget.scrollTop))} onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))} - onPointerOver={e => this.onPointerOver(e.clientX, e.clientY)} + onPointerOver={e => this.onPointerOver(e.buttons ? true : false, e.clientX, e.clientY)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}> diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 8452d895f..9b7518c60 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -47,7 +47,7 @@ interface CSVFieldColumnProps { screenToLocalTransform: () => Transform; observeHeight: (myref: any) => void; unobserveHeight: (myref: any) => void; - editableViewProps: any; + editableViewProps: () => any; resizeColumns: (n: number) => void; columnStartXCoords: number[]; PanelWidth: number; @@ -112,7 +112,6 @@ export class CollectionNoteTakingViewColumn extends React.Component { - console.log('HEADING CH'); const castedValue = this.getValue(value); if (castedValue) { if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { @@ -144,43 +143,17 @@ export class CollectionNoteTakingViewColumn extends React.Component { - if (!this.props.columnHeaders) { - return; - } - if (this.props.headingObject) { + if (this.props.columnHeaders && 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.docList.forEach(d => (d[this.props.pivotField] = 'unset')); 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[] = []; @@ -256,7 +229,6 @@ export class CollectionNoteTakingViewColumn extends React.Component
evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} /> @@ -314,7 +285,7 @@ export class CollectionNoteTakingViewColumn extends React.Component
- +
{this.props.columnHeaders?.length && this.props.columnHeaders.length > 1 && ( + )}
) : null; - const templatecols = `${this.columnWidth}px `; + const templatecols = this.columnWidth; const type = this.props.Document.type; return ( <> {headingView} - { -
-
- {this.props.renderChildren(this.props.docList)} -
+
+
+ {this.props.renderChildren(this.props.docList)} +
- {!this.props.chromeHidden && type !== DocumentType.PRES ? ( -
-
- -
-
- -
- {this.props.columnHeaders?.length && this.props.columnHeaders.length > 1 && ( - - )} + {!this.props.chromeHidden && type !== DocumentType.PRES ? ( +
+
+
- ) : null} -
- } +
+ +
+
+ ) : null} +
); } diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx index 8d659f790..a1309b11f 100644 --- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx @@ -57,7 +57,6 @@ export class CollectionNoteTakingViewDivider extends React.Component
-- cgit v1.2.3-70-g09d2 From dff4b18106261af77d81211e5482a38b19b2a166 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 26 Aug 2022 09:19:15 -0400 Subject: more notetaking cleanup --- src/client/views/collections/CollectionNoteTakingView.scss | 12 +++++++++++- .../views/collections/CollectionNoteTakingViewColumn.tsx | 7 +------ 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss index 5582fd391..08b13fd50 100644 --- a/src/client/views/collections/CollectionNoteTakingView.scss +++ b/src/client/views/collections/CollectionNoteTakingView.scss @@ -54,7 +54,7 @@ .collectionNoteTakingViewFieldColumn { height: 100%; display: flex; - flex-direction: colum; + overflow: hidden; } .collectionNoteTakingViewFieldColumn:hover { .collectionNoteTakingView-DocumentButtons { @@ -112,6 +112,11 @@ height: auto; } + .collectionNoteTakingView-columnStack { + height: 100%; + width: 100%; + display: inline-block; + } .collectionNoteTakingView-Nodes { width: 100%; height: 100%; @@ -123,6 +128,11 @@ left: 0; width: 100%; position: absolute; + margin: auto; + width: max-content; + height: max-content; + position: relative; + grid-auto-rows: 0px; } .collectionNoteTakingView-description { diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index d951454ff..84d1c0205 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -262,19 +262,14 @@ export class CollectionNoteTakingViewColumn extends React.Component {headingView} -
+
{this.props.renderChildren(this.props.docList)}
-- cgit v1.2.3-70-g09d2