diff options
Diffstat (limited to 'src/client/views/collections/CollectionNoteTakingView.tsx')
-rw-r--r-- | src/client/views/collections/CollectionNoteTakingView.tsx | 115 |
1 files changed, 74 insertions, 41 deletions
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index d8a0aebb1..3f9eed1d6 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,7 +1,8 @@ import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, Field, Opt } from '../../../fields/Doc'; +import { ClientUtils, DivHeight, lightOrDark, returnZero, smoothScroll } from '../../../ClientUtils'; +import { Doc, Field, FieldType, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Copy, Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; @@ -9,25 +10,29 @@ import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { DivHeight, emptyFunction, lightOrDark, returnZero, smoothScroll, Utils } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; -import { DragManager, dropActionType } from '../../util/DragManager'; +import { emptyFunction } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DocUtils } from '../../documents/DocUtils'; +import { DragManager } from '../../util/DragManager'; +import { dropActionType } from '../../util/DropActionTypes'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoable, undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; +import { FieldsDropdown } from '../FieldsDropdown'; import { Colors } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; +import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; import { DocumentView } from '../nodes/DocumentView'; -import { FieldViewProps, FocusViewOptions } from '../nodes/FieldView'; -import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import { StyleProp } from '../StyleProvider'; +import { FieldViewProps } from '../nodes/FieldView'; +import { FocusViewOptions } from '../nodes/FocusViewOptions'; +import { StyleProp } from '../StyleProp'; import './CollectionNoteTakingView.scss'; import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn'; import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider'; import { CollectionSubView } from './CollectionSubView'; -import { FieldsDropdown } from '../FieldsDropdown'; + const _global = (window /* browser */ || global) /* node */ as any; /** @@ -56,7 +61,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @computed get chromeHidden() { - return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false; + return BoolCast(this.layoutDoc.chromeHidden) || SnappingManager.ExploreMode; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { @@ -65,7 +70,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (needsUnsetCategory || colHeaderData === undefined || colHeaderData.length === 0) { setTimeout(() => { const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null) ?? []); - const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset')); if (needsUnsetCategory || columnHeaders.length === 0) { columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1)); this.resizeColumns(columnHeaders); @@ -109,12 +113,12 @@ export class CollectionNoteTakingView extends CollectionSubView() { // to render the docs you see within an individual column. children = (docs: Doc[]) => { TraceMobx(); - return docs.map((d, i) => { + return docs.map(d => { const height = () => this.getDocHeight(d); const width = () => this.getDocWidth(d); const style = { width: width(), marginTop: this.gridGap, height: height() }; return ( - <div className={`collectionNoteTakingView-columnDoc`} key={d[Id]} style={style}> + <div className="collectionNoteTakingView-columnDoc" key={d[Id]} style={style}> {this.getDisplayDoc(d, width)} </div> ); @@ -133,7 +137,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { 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 => { + docs.forEach(d => { const sectionValue = (d[this.notetakingCategoryField] as object) ?? `unset`; // look for if header exists already const existingHeader = columnHeaders.find(sh => sh.heading === sectionValue.toString()); @@ -151,7 +155,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { removeDocDragHighlight = () => { setTimeout( - action(() => (this.docsDraggedRowCol.length = 0)), + action(() => { + this.docsDraggedRowCol.length = 0; + }), 100 ); }; @@ -189,13 +195,11 @@ export class CollectionNoteTakingView extends CollectionSubView() { Object.keys(this._disposers).forEach(key => this._disposers[key]()); } - moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => { - return this._props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; - }; + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean) => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); createRef = (ele: HTMLDivElement | null) => { this._masonryGridRef = ele; - this.createDashEventsTarget(ele!); //so the whole grid is the drop target? + this.createDashEventsTarget(ele!); }; @computed get onChildClickHandler() { @@ -215,14 +219,15 @@ export class CollectionNoteTakingView extends CollectionSubView() { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { - const top = found.getBoundingClientRect().top; + const { top } = found.getBoundingClientRect(); const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0 && Math.ceil(this._props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) { - let focusSpeed = options.zoomTime ?? 500; + const focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); return focusSpeed; } } + return undefined; }; styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { @@ -237,6 +242,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { return this._props.childOpacity(); } break; + default: } return this._props.styleProvider?.(doc, props, property); }; @@ -252,7 +258,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { const noteTakingDocTransform = () => this.getDocTransform(doc, dref); return ( <DocumentView - ref={r => (dref = r || undefined)} + ref={r => { + dref = r || undefined; + }} Document={doc} TemplateDataDocument={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)} pointerEvents={this.blockPointerEventsWhenDragging} @@ -264,8 +272,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} - //TODO: change this from a prop to a parameter passed into a function - dontHideOnDrag={true} + // TODO: change this from a prop to a parameter passed into a function + dontHideOnDrag isDocumentActive={this.isContentActive} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} @@ -277,7 +285,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { layout_showTitle={this._props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} onClickScript={this.onChildClickHandler} - onBrowseClickScript={this._props.onBrowseClickScript} onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} @@ -299,8 +306,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { // 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 { translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined); + this._scroll; // required for document decorations to update when the text box container is scrolled + const { translateX, translateY } = ClientUtils.GetScreenTransform(dref?.ContentDiv || undefined); // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.ScreenToLocalBoxXf().Scale); } @@ -308,7 +315,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // how to get the width of a document. Currently returns the width of the column (minus margins) // if a note doc. Otherwise, returns the normal width (for graphs, images, etc...) getDocWidth(d: Doc) { - const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as Field); + const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as FieldType); const existingHeader = this.colHeaderData.find(sh => sh.heading === heading); const existingWidth = this.layoutDoc._notetaking_columns_autoSize ? 1 / (this.colHeaderData.length ?? 1) : existingHeader?.width ? existingHeader.width : 0; const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth; @@ -344,7 +351,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { // 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 = (headers: SchemaHeaderField[]) => { - const n = headers.length; const curWidths = headers.reduce((sum, hdr) => sum + Math.abs(hdr.width), 0); const scaleFactor = 1 / curWidths; this.dataDoc[this.fieldKey + '_columnHeaders'] = new List<SchemaHeaderField>( @@ -382,7 +388,11 @@ export class CollectionNoteTakingView extends CollectionSubView() { // we alter the pivot fields of the docs in case they are moved to a new column. const colIndex = this.getColumnFromXCoord(xCoord); const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading); - DragManager.docsBeingDragged.map(doc => doc[DocData]).forEach(d => (d[this.notetakingCategoryField] = colHeader)); + DragManager.docsBeingDragged + .map(doc => doc[DocData]) + .forEach(d => { + d[this.notetakingCategoryField] = colHeader; + }); // used to notify sections to re-render this.docsDraggedRowCol.length = 0; const columnFromCoord = this.getColumnFromXCoord(xCoord); @@ -393,7 +403,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // 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 | undefined => { - let colIndex: number | undefined = undefined; + let colIndex: number | undefined; const numColumns = this.colHeaderData.length; const coords = []; let colStartXCoord = 0; @@ -416,10 +426,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { const docsMatchingHeader: Doc[] = []; const colIndex = this.getColumnFromXCoord(xCoord); const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading); - this.childDocs?.map(d => { + this.childDocs?.forEach(d => { if (d instanceof Promise) return; const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset'; - if (sectionValue.toString() == colHeader) { + if (sectionValue.toString() === colHeader) { docsMatchingHeader.push(d); } }); @@ -432,9 +442,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { e.stopPropagation?.(); const newDoc = Doc.MakeCopy(fieldProps.Document, true); newDoc[DocData].text = undefined; - FormattedTextBox.SetSelectOnLoad(newDoc); + Doc.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } + return undefined; }; // onInternalDrop is used when dragging and dropping a document within the view, such as dragging @@ -463,7 +474,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && CollectionFreeFormDocumentView.from(de.complete.linkDragData?.linkDragView)) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this._props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed @@ -572,6 +583,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { alert('You cannot use an existing column name. Please try a new column name'); return value; } + return undefined; }); const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null)); const newColWidth = 1 / (this.numGroupColumns + 1); @@ -590,17 +602,33 @@ export class CollectionNoteTakingView extends CollectionSubView() { const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.layoutDoc._notetaking_columns_autoCreate ? 'Manually' : 'Automatically'} Create columns`, - event: () => (this.layoutDoc._notetaking_columns_autoCreate = !this.layoutDoc._notetaking_columns_autoCreate), + event: () => { + this.layoutDoc._notetaking_columns_autoCreate = !this.layoutDoc._notetaking_columns_autoCreate; + }, icon: 'computer', }); subItems.push({ description: 'Remove Empty Columns', event: this.removeEmptyColumns, icon: 'computer' }); subItems.push({ description: `${this.layoutDoc._notetaking_columns_autoSize ? 'Variable Size' : 'Autosize'} Columns`, - event: () => (this.layoutDoc._notetaking_columns_autoSize = !this.layoutDoc._notetaking_columns_autoSize), + event: () => { + this.layoutDoc._notetaking_columns_autoSize = !this.layoutDoc._notetaking_columns_autoSize; + }, icon: 'plus', }); - subItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: 'plus' }); - subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' }); + subItems.push({ + description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, + event: () => { + this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight; + }, + icon: 'plus', + }); + subItems.push({ + description: 'Clear All', + event: () => { + this.dataDoc.data = new List([]); + }, + icon: 'times', + }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' }); } }; @@ -625,6 +653,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const sections = Array.from(this.Sections.entries()); return sections.reduce((list, sec, i) => { list.push(this.sectionNoteTaking(sec[0], sec[1])); + // eslint-disable-next-line react/no-array-index-key i !== sections.length - 1 && list.push(<CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />); return list; }, [] as JSX.Element[]); @@ -658,14 +687,18 @@ export class CollectionNoteTakingView extends CollectionSubView() { background: this.backgroundColor(), pointerEvents: this.backgroundEvents, }} - onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))} - onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))} + onScroll={action(e => { + this._scroll = e.currentTarget.scrollTop; + })} + onPointerLeave={action(() => { + this.docsDraggedRowCol.length = 0; + })} onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)} onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={e => this._props.isContentActive() && e.stopPropagation()}> - <>{this.renderedSections}</> + {this.renderedSections} <div className="collectionNotetaking-pivotField" style={{ right: 0, top: 0, position: 'absolute' }}> <FieldsDropdown Document={this.Document} |