From 73e5ac3b651d92a3755db7d8376fc84d199be066 Mon Sep 17 00:00:00 2001
From: ljungster <parkerljung@gmail.com>
Date: Mon, 22 Aug 2022 05:13:57 -0500
Subject: commented CollectionNoteTakingView

---
 .../views/collections/CollectionNoteTakingView.tsx | 160 +++++++--------------
 1 file changed, 49 insertions(+), 111 deletions(-)

(limited to 'src/client/views/collections/CollectionNoteTakingView.tsx')

diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 0c5f69db0..a2f05c031 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -37,45 +37,34 @@ 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?
-
+/**
+ * CollectionNoteTakingView is a column-based view for displaying documents. In this view, the user can (1)
+ * add and remove columns (2) change column sizes and (3) move documents within and between columns. This
+ * view is reminiscent of Kanban-style web apps like Trello, or the 'Board' view in Notion. Each column is 
+ * headed by a SchemaHeaderField followed by the column's documents. SchemaHeaderFields are NOT present in
+ * the rest of Dash, so it may be worthwhile to transition the headers to simple documents.
+ */
 @observer
 export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() {
     _disposers: { [key: string]: IReactionDisposer } = {};
     _masonryGridRef: HTMLDivElement | null = null;
-    _draggerRef = React.createRef<HTMLDivElement>(); // change to relative widths for deleting.  change storage from columnStartXCoords to columnHeaders (schemaHeaderFields has a widgth alrady)
-    // @observable columnStartXCoords: number[] = []; // columnHeaders -- SchemaHeaderField -- widht
+    _draggerRef = React.createRef<HTMLDivElement>();
     @observable docsDraggedRowCol: number[] = [];
     @observable _cursor: CursorProperty = 'grab';
-    @observable _scroll = 0; // used to force the document decoration to update when scrolling
+    @observable _scroll = 0; 
     @computed get chromeHidden() {
         return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
     }
+    // columnHeaders() returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
     @computed get columnHeaders() {
         const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null);
         const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders.find(sh => sh.heading === 'unset'));
-
-        //  @#Oberable draggedColIndex = ...
-        //@observable cloneDivXYcoords
-        // @observable clonedDiv...
-
-        // render() {
-        //    { this.clonedDiv ? <div clone styule={{transform: clonedDivXYCoords}} : null}
-        // }
-
-        //  in NoteatakinView Column code, add a poinerDown handler that calls setupMoveUpEvents() which will clone the column div
-        //    and re-render it under the cursor during move events.
-        //    that move move event will update 2 observales -- the draggedColIndex up above, and the location of the clonedDiv so that the render in this view will know where to render the cloned div
-        // add observable variable that tells drag column to rnder in a different location than where the schemaHeaderFiel sa y ot.
-        // if (col 1 is where col 3) {
-        //     return 3 2 1 4 56
-        // }
         if (needsUnsetCategory) {
             columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1));
         }
         return columnHeaders;
     }
+    // 
     @computed get notetakingCategoryField() {
         return 'NotetakingCategory';
     }
@@ -93,7 +82,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     }
     @computed get yMargin() {
         return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5);
-    } // 2 * this.gridGap)); }
+    }
     @computed get gridGap() {
         return NumCast(this.layoutDoc._gridGap, 10);
     }
@@ -111,13 +100,12 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         return this.maxColWidth - numDividers * this.dividerWidth;
     }
 
-    // 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
+    // Documents should NOT have column category fields until entering this view, so the contructor creates the 'New Column'
+    // category for the user to then edit later.
     constructor(props: any) {
         super(props);
         if (this.columnHeaders === undefined) {
             this.dataDoc.columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField('New Column', undefined, undefined, 1)]);
-            // add all of the docs that have not been added to a column to this new column
         }
     }
 
@@ -137,6 +125,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         });
     };
 
+    // Sections is one of the more important functions in this file, rendering the the documents
+    // for the UI. It properly renders documents being dragged between columns.
     // [CAVEATS] (1) keep track of the offsetting
     // (2) documentView gets unmounted as you remove it from the list
     @computed get Sections() {
@@ -146,21 +136,17 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         const docs = this.childDocs.filter(d => !DragManager.docsBeingDragged.includes(d));
         const sections = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
         const rowCol = this.docsDraggedRowCol;
-
         // this will sort the docs into the correct columns (minus the ones you're currently dragging)
         docs.map(d => {
             const sectionValue = (d[this.notetakingCategoryField] as object) ?? `unset`;
-
             // look for if header exists already
             const existingHeader = columnHeaders.find(sh => sh.heading === sectionValue.toString());
             if (existingHeader) {
                 sections.get(existingHeader)!.push(d);
             }
         });
-
         // now we add back in the docs that we're dragging
         if (rowCol.length) {
-            // TODO: get the actual offset that occurs if the docs were in that column
             const offset = 0;
             sections.get(columnHeaders[rowCol[1]])?.splice(rowCol[0] - offset, 0, ...DragManager.docsBeingDragged);
         }
@@ -173,6 +159,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             100
         );
     };
+
     componentDidMount() {
         super.componentDidMount?.();
         document.addEventListener('pointerup', this.removeDocDragHighlight, true);
@@ -180,12 +167,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             () => 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(),
-        //     // TODO: is this correct?
-        //     headers => this.resizeColumns(headers.length, false),
-        //     { fireImmediately: true }
-        // );
     }
 
     componentWillUnmount() {
@@ -207,6 +188,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     @computed get onChildClickHandler() {
         return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
     }
+
     @computed get onChildDoubleClickHandler() {
         return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
     }
@@ -226,7 +208,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     // let's dive in and get the actual document we want to drag/move around
     focusDocument = (doc: Doc, options?: DocFocusOptions) => {
         Doc.BrushDoc(doc);
-
         let focusSpeed = 0;
         const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
         if (found) {
@@ -261,7 +242,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
 
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
 
-    // rules for displaying the documents
+    // getDisplayDoc returns the rules for displaying a document in this view (ie. DocumentView)
     getDisplayDoc(doc: Doc, width: () => number) {
         const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
         const height = () => this.getDocHeight(doc);
@@ -317,7 +298,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         );
     }
 
-    // This is used to get the coordinates of a document when we go from a view like freeform to columns
+    // getDocTransform 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);
@@ -332,9 +313,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         const existingHeader = this.columnHeaders.find(sh => sh.heading === heading);
         const existingWidth = existingHeader?.width ? existingHeader.width : 0;
         const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth - 2 * this.xMargin : this.maxColWidth - 2 * this.xMargin;
-        // const index = existingHeader ? this.columnHeaders.indexOf(existingHeader) : 0;
-        // const endColValue = index === this.columnHeaders.length - 1 || index > this.columnStartXCoords.length - 1 ? this.PanelWidth : this.columnStartXCoords[index + 1];
-        // const maxWidth = index > this.columnStartXCoords.length - 1 ? this.PanelWidth : endColValue - this.columnStartXCoords[index] - 3 * this.xMargin;
         if (d.type === DocumentType.RTF) {
             return maxWidth;
         }
@@ -361,8 +339,15 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         return Math.min(childHeight, maxHeight, panelHeight);
     }
 
-    // called when a column is either added or deleted.
-    // TODO: this needs help still
+    // resizeColumns is called whenever a user adds or removes a column. When removing, 
+    // this function renormalizes the column widths to fill the newly available space
+    // in the panel. When adding, this function renormalizes the existing columns to take up
+    // (n - 1)/n space, since the new column will be allocated 1/n of the total space.
+    // Column widths are relative (portion of available space) and stored  in the 'width' 
+    // field of SchemaHeaderFields.
+    //
+    // Removing example: column widths are [0.5, 0.30, 0.20] --> user deletes the final column --> column widths are [0.625, 0.375].
+    // Adding example: column widths are [0.6, 0.4] --> user adds column at end --> column widths are [0.4, 0.267, 0.33]
     @action
     resizeColumns = (isAdd: boolean, colWidth: number, colIndex: number) => {
         const n = this.columnHeaders.length;
@@ -377,28 +362,13 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             }
         });
         return true;
-        // let scaleFactor = isAdd ? (n - 1) / n : (n + 1) / n;
-        // // if (isAdd && n == 1) scaleFactor = 1;
-        // this.columnHeaders.forEach(h => {
-        //     h.width < 0 ? h.setWidth(1 / n) : h.setWidth(h.width * scaleFactor);
-        // });
-        // if we're adding, need to
-
-        // const newColXCoords: number[] = [];
-        // let colStart = 0;
-        // for (let i = 0; i < n; i++) {
-        //     newColXCoords.push(colStart);
-        //     colStart += colWidth + dividerWidth;
-        // }
-        // this.columnStartXCoords = newColXCoords;
     };
 
-    // This function is used to preview where a document will drop in a column once a drag is complete.
+    // onPointerMove is used to preview where a document will drop in a column once a drag is complete.
     @action
     onPointerMove = (force: boolean, ex: number, ey: number) => {
         if (this.childDocList && (this.childDocList.includes(DragManager.DocDragData?.draggedDocuments.lastElement()!) || force || this.isContentActive())) {
             // 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;
             const colDocs = this.getDocsFromXCoord(xCoord);
             // get the index for where you need to insert the doc you are currently dragging
@@ -427,7 +397,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         }
     };
 
-    // returns the column index for a given x-coordinate
+    // getColumnFromXCoord returns the column index for a given x-coordinate (currently always the client's mouse coordinate). 
+    // This function is used to know which document a column SHOULD be in while it is being dragged.
     getColumnFromXCoord = (xCoord: number): number => {
         const numColumns = this.columnHeaders.length;
         const coords = [];
@@ -436,7 +407,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             coords.push(colStartXCoord);
             colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.dividerWidth;
         }
-
         coords.push(this.PanelWidth);
         let colIndex = 0;
         for (let i = 0; i < numColumns; i++) {
@@ -448,7 +418,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         return colIndex;
     };
 
-    // returns the docs of a column based on the x-coordinate provided.
+    // getDocsFromXCoord returns the docs of a column based on the x-coordinate provided.
     getDocsFromXCoord = (xCoord: number): Doc[] => {
         const colIndex = this.getColumnFromXCoord(xCoord);
         const colHeader = StrCast(this.columnHeaders[colIndex].heading);
@@ -480,6 +450,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         }
     };
 
+    // onInternalDrop is used when dragging and dropping a document within the view, such as dragging
+    // a document to a new column or changing its order within the column.
     @undoBatch
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
@@ -489,14 +461,11 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                 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
                 const docs = this.childDocList;
                 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 front. Otherwise we need to add it to the column properly
-                    //TODO: you need to update childDocList instead. It seems that childDocs is a copy of the actual array we want to modify
                     if (rowCol[0] <= 0) {
                         docs.splice(0, 0, ...newDocs);
                     } else {
@@ -507,7 +476,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                     }
                 }
             }
-        } // it seems like we're creating a link here. Weird. I didn't know that you could establish links by dragging
+        }
         else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
             const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' });
             this.props.addDocument?.(source);
@@ -527,28 +496,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         return true;
     }
 
-    // Used in CollectionNoteTakingView to delete a column when the user clicks the delete button
-    // @action
-    // @undoBatch
-    // deleteColumn = (headingObject: SchemaHeaderField | undefined, docList: Doc[]) => {
-    //     if (!this.columnHeaders) {
-    //       return
-    //     }
-    //     if (headingObject) {
-    //       const index = this.columnHeaders.indexOf(headingObject);
-    //       const newIndex = index == 0 ? 1 : index - 1
-    //       const newHeader = this.columnHeaders[newIndex];
-    //       docList.forEach(d => d[this.pivotField] = newHeader.heading.toString())
-    //       // this.props.columnHeaders.splice(index, 1);
-    //       const newHeaders = this.columnHeaders;
-    //       newHeaders.splice(index, 1);
-    //       const test = this.layoutDoc._columnHeaders;
-    //       this.columnHeaders = newHeaders;
-    //       this.resizeColumns(newHeaders.length)
-    //     }
-    // }
-
-    // when dropping outside of the current noteTaking context (like a new tab, freeform view, etc...)
+    // onExternalDrop is used when dragging a document out from a CollectionNoteTakingView
+    // to another tab/view/collection
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
         const targInd = this.docsDraggedRowCol?.[0] || 0;
         const colInd = this.docsDraggedRowCol?.[1] || 0;
@@ -576,12 +525,14 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     headings = () => Array.from(this.Sections);
 
     refList: any[] = [];
+
     editableViewProps = () => ({
         GetValue: () => '',
         SetValue: this.addGroup,
         contents: '+ New Column',
     });
 
+    // sectionNoteTaking returns a CollectionNoteTakingViewColumn (which is an individual column) 
     sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const type = 'number';
         return (
@@ -604,8 +555,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                     }
                 }}
                 addDocument={this.addDocument}
-                // docsByColumnHeader={this._docsByColumnHeader}
-                // setDocsForColHeader={this.setDocsForColHeader}
                 chromeHidden={this.chromeHidden}
                 columnHeaders={this.columnHeaders}
                 Document={this.props.Document}
@@ -615,7 +564,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                 numGroupColumns={this.numGroupColumns}
                 gridGap={this.gridGap}
                 pivotField={this.notetakingCategoryField}
-                // columnStartXCoords={this.columnStartXCoords}
                 dividerWidth={this.dividerWidth}
                 maxColWidth={this.maxColWidth}
                 availableWidth={this.availableWidth}
@@ -634,7 +582,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         );
     };
 
-    // called when adding a new columnHeader
+    // addGroup is called when adding a new columnHeader, adding a SchemaHeaderField to our list of 
+    // columnHeaders and resizing the existing columns to make room for our new one.
     @undoBatch
     @action
     @undoBatch
@@ -644,13 +593,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         return value && columnHeaders?.push(new SchemaHeaderField(value, undefined, undefined, newColWidth)) && this.resizeColumns(true, newColWidth, this.columnHeaders.length - 1) ? true : false;
     };
 
-    sortFunc = (a: [SchemaHeaderField, Doc[]], b: [SchemaHeaderField, Doc[]]): 1 | -1 => {
-        const descending = StrCast(this.layoutDoc._columnsSort) === 'descending';
-        const firstEntry = descending ? b : a;
-        const secondEntry = descending ? a : b;
-        return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1;
-    };
-
     onContextMenu = (e: React.MouseEvent): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
         if (!e.isPropagationStopped()) {
@@ -662,7 +604,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         }
     };
 
-    // used to reset column sizes when using the drag handlers
+    // setColumnStartXCoords is used to update column sizes when using the drag handlers between columns
     @action
     setColumnStartXCoords = (movementXScreen: number, colIndex: number) => {
         const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0];
@@ -670,20 +612,15 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
         const rightHeader = this.columnHeaders[colIndex + 1];
         leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth);
         rightHeader.setWidth(rightHeader.width - movementX / this.availableWidth);
-        // const coords = [...this.columnStartXCoords];
-        // coords[colIndex] += movementX;
-        // this.columnStartXCoords = coords;
     };
 
+    // renderedSections returns a list of all of the JSX elements used (columns and dividers). If the view
+    // has more than one column, those columns will be separated by a CollectionNoteTakingViewDivider that 
+    // allows the user to adjust the column widths.
     @computed get renderedSections() {
         TraceMobx();
-        // 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 entries = Array.from(this.Sections.entries());
-        const sections = entries; //.sort(this.sortFunc);
+        const sections = entries;
         const eles: JSX.Element[] = [];
         for (let i = 0; i < sections.length; i++) {
             const col = this.sectionNoteTaking(sections[i][0], sections[i][1]);
@@ -697,7 +634,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
 
     @computed get buttonMenu() {
         const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
-        // TODO:glr Allow support for multiple buttons
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
             const height: number = NumCast(menuDoc._height, 30);
@@ -748,7 +684,9 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     @computed get backgroundEvents() {
         return SnappingManager.GetIsDragging();
     }
+
     observer: any;
+
     render() {
         TraceMobx();
         const buttonMenu = this.rootDoc.buttonMenu;
-- 
cgit v1.2.3-70-g09d2

