diff options
| author | bobzel <zzzman@gmail.com> | 2024-04-17 12:27:21 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-04-17 12:27:21 -0400 |
| commit | 2a313f28fcb8675223708b0657de7517a3281095 (patch) | |
| tree | ed6db226cc7d323aee378eddee43dc5f3bdb1ef9 /src/client/views/collections/collectionFreeForm | |
| parent | 62937027183dc8acf14e489fbb4590aff6fce2cd (diff) | |
restoring eslint - updates not complete yet
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
6 files changed, 137 insertions, 108 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index cc729decc..29d835b28 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -1,7 +1,7 @@ import { makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Field, FieldResult } from '../../../../fields/Doc'; +import { Doc, DocListCast, FieldType, FieldResult } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { StrCast } from '../../../../fields/Types'; import { DocumentManager } from '../../../util/DocumentManager'; @@ -10,13 +10,14 @@ import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { TopBar } from '../../topbar/TopBar'; import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; -import { CollectionFreeFormView } from './CollectionFreeFormView'; import './CollectionFreeFormView.scss'; +import { DocData } from '../../../../fields/DocSymbols'; export interface CollectionFreeFormInfoUIProps { Document: Doc; - Freeform: CollectionFreeFormView; - close: () => boolean; + LayoutDoc: Doc; + childDocs: () => Doc[]; + close: () => void; } @observer @@ -32,10 +33,10 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio @observable _currState: infoState | undefined = undefined; get currState() { return this._currState; } // prettier-ignore - set currState(val) { runInAction(() => (this._currState = val)); } // prettier-ignore + set currState(val) { runInAction(() => {this._currState = val;}); } // prettier-ignore componentWillUnmount(): void { - this._props.Freeform.dataDoc.backgroundColor = this._originalbackground; + this._props.Document[DocData].backgroundColor = this._originalbackground; } setCurrState = (state: infoState) => { @@ -46,16 +47,16 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio }; setupStates = () => { - this._originalbackground = StrCast(this._props.Freeform.dataDoc.backgroundColor); + this._originalbackground = StrCast(this._props.Document[DocData].backgroundColor); // state entry functions - const setBackground = (colour: string) => () => (this._props.Freeform.dataDoc.backgroundColor = colour); - const setOpacity = (opacity: number) => () => (this._props.Freeform.layoutDoc.opacity = opacity); + const setBackground = (colour: string) => () => {this._props.Document[DocData].backgroundColor = colour;} // prettier-ignore + const setOpacity = (opacity: number) => () => {this._props.LayoutDoc.opacity = opacity;} // prettier-ignore // arc transition trigger conditions - const firstDoc = () => (this._props.Freeform.childDocs.length ? this._props.Freeform.childDocs[0] : undefined); - const numDocs = () => this._props.Freeform.childDocs.length; + const firstDoc = () => (this._props.childDocs().length ? this._props.childDocs()[0] : undefined); + const numDocs = () => this._props.childDocs().length; - let docX: FieldResult<Field>; - let docY: FieldResult<Field>; + let docX: FieldResult<FieldType>; + let docY: FieldResult<FieldType>; const docNewX = () => firstDoc()?.x; const docNewY = () => firstDoc()?.y; @@ -244,12 +245,12 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio // editPresentation: [() => presentationMode() === 'edit', () => editPresentationMode], manualPresentation: [() => presentationMode() === 'manual', () => manualPresentationMode], docRemoved: [() => numDocs() < 3, () => viewedLink], - docCreated: [() => numDocs() == 4, () => completed], + docCreated: [() => numDocs() === 4, () => completed], }); const completed = InfoState( 'Eager to learn more? Click the ? icon in the top right corner to read our full documentation.', - { docRemoved: [() => numDocs() == 1, () => oneDoc] }, + { docRemoved: [() => numDocs() === 1, () => oneDoc] }, 'documentation.png', () => TopBar.Instance.FlipDocumentationIcon() ); // prettier-ignore diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index c83c26509..a0b96c75a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -1,4 +1,4 @@ -import { Doc, Field, FieldResult } from '../../../../fields/Doc'; +import { Doc, Field, FieldType, FieldResult } from '../../../../fields/Doc'; import { Id, ToString } from '../../../../fields/FieldSymbols'; import { ObjectField } from '../../../../fields/ObjectField'; import { RefField } from '../../../../fields/RefField'; @@ -50,7 +50,7 @@ export interface ViewDefResult { bounds?: ViewDefBounds; inkMask?: number; //sort elements into either the mask layer (which has a mixedBlendMode appropriate for transparent masks), or the regular documents layer; -1 = no mask, 0 = mask layer but stroke is transparent (hidden, as in during a presentation when you want to smoothly animate it into being a mask), >0 = mask layer and not hidden } -function toLabel(target: FieldResult<Field>) { +function toLabel(target: FieldResult<FieldType>) { if (typeof target === 'number' || Number(target)) { const truncated = Number(Number(target).toFixed(0)); const precise = Number(Number(target).toFixed(2)); @@ -128,7 +128,7 @@ export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { const docMap = new Map<string, PoolData>(); const fieldKey = 'data'; - const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>(); + const pivotColumnGroups = new Map<FieldResult<FieldType>, PivotColumn>(); let nonNumbers = 0; const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField) || 'author'; @@ -136,10 +136,10 @@ export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Do const listValue = Cast(pair.layout[pivotFieldKey], listSpec('string'), null); const num = toNumber(pair.layout[pivotFieldKey]); - if (num === undefined || Number.isNaN(num)) { + if (num === undefined || isNaN(num)) { nonNumbers++; } - const val = Field.toString(pair.layout[pivotFieldKey] as Field); + const val = Field.toString(pair.layout[pivotFieldKey] as FieldType); if (listValue) { listValue.forEach((val, i) => { !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] }); @@ -265,7 +265,7 @@ export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Do return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } -function toNumber(val: FieldResult<Field>) { +function toNumber(val: FieldResult<FieldType>) { return val === undefined ? undefined : NumCast(val, Number(StrCast(val))); } @@ -274,7 +274,7 @@ export function computeTimelineLayout(poolData: Map<string, PoolData>, pivotDoc: const pivotDateGroups = new Map<number, Doc[]>(); const docMap = new Map<string, PoolData>(); const groupNames: ViewDefBounds[] = []; - const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field); + const timelineFieldKey = Field.toString(pivotDoc._pivotField as FieldType); const curTime = toNumber(pivotDoc[fieldKey + '-timelineCur']); const curTimeSpan = Cast(pivotDoc[fieldKey + '-timelineSpan'], 'number', null); const minTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + '-timelineMinReq'], 'number', null) : curTime && curTime - curTimeSpan; @@ -290,7 +290,7 @@ export function computeTimelineLayout(poolData: Map<string, PoolData>, pivotDoc: let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq; childPairs.forEach(pair => { const num = NumCast(pair.layout[timelineFieldKey], Number(StrCast(pair.layout[timelineFieldKey]))); - if (!Number.isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) { + if (!isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) { !pivotDateGroups.get(num) && pivotDateGroups.set(num, []); pivotDateGroups.get(num)!.push(pair.layout); minTime = Math.min(num, minTime); @@ -400,7 +400,7 @@ function normalizeResults( 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; + if (isNaN(scale)) scale = 1; Array.from(docMap.entries()) .filter(ele => ele[1].pair) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 69cbae86f..707f6c198 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -4,26 +4,28 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; -import { CollectionFreeFormView } from './CollectionFreeFormView'; import './CollectionFreeFormView.scss'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; + export interface CollectionFreeFormPannableContentsProps { Document: Doc; viewDefDivClick?: ScriptField; children?: React.ReactNode | undefined; transition?: string; isAnnotationOverlay: boolean | undefined; + showPresPaths: () => boolean; transform: () => string; brushedView: () => { panX: number; panY: number; width: number; height: number } | undefined; } @observer -export class CollectionFreeFormPannableContents extends React.Component<CollectionFreeFormPannableContentsProps> { +export class CollectionFreeFormPannableContents extends ObservableReactComponent<CollectionFreeFormPannableContentsProps> { constructor(props: CollectionFreeFormPannableContentsProps) { super(props); makeObservable(this); } @computed get presPaths() { - return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null; + return this._props.showPresPaths() ? PresBox.Instance.pathLines(this._props.Document) : null; } // rectangle highlight used when following trail/link to a region of a collection that isn't a document showViewport = (viewport: { panX: number; panY: number; width: number; height: number } | undefined) => @@ -42,7 +44,7 @@ export class CollectionFreeFormPannableContents extends React.Component<Collecti render() { return ( <div - className={'collectionfreeformview' + (this.props.viewDefDivClick ? '-viewDef' : '-none')} + className={'collectionfreeformview' + (this._props.viewDefDivClick ? '-viewDef' : '-none')} onScroll={e => { const target = e.target as any; if (getComputedStyle(target)?.overflow === 'visible') { @@ -50,13 +52,13 @@ export class CollectionFreeFormPannableContents extends React.Component<Collecti } }} style={{ - transform: this.props.transform(), - transition: this.props.transition, - width: this.props.isAnnotationOverlay ? undefined : 0, // if not an overlay, then this will be the size of the collection, but panning and zooming will move it outside the visible border of the collection and make it selectable. This problem shows up after zooming/panning on a background collection -- you can drag the collection by clicking on apparently empty space outside the collection + transform: this._props.transform(), + transition: this._props.transition, + width: this._props.isAnnotationOverlay ? undefined : 0, // if not an overlay, then this will be the size of the collection, but panning and zooming will move it outside the visible border of the collection and make it selectable. This problem shows up after zooming/panning on a background collection -- you can drag the collection by clicking on apparently empty space outside the collection }}> {this.props.children} {this.presPaths} - {this.showViewport(this.props.brushedView())} + {this.showViewport(this._props.brushedView())} </div> ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index fa8218bdd..35394016d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -9,17 +9,17 @@ import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; -import { CollectionViewProps } from '../CollectionView'; +import { CollectionViewProps } from '../CollectionSubView'; import './CollectionFreeFormView.scss'; @observer export class CollectionFreeFormRemoteCursors extends React.Component<CollectionViewProps> { @computed protected get cursors(): CursorField[] { - const doc = this.props.Document; + const { Document } = this.props; let cursors: FieldResult<List<CursorField>>; const id = Doc.UserDoc()[Id]; - if (!id || !(cursors = Cast(doc.cursors, listSpec(CursorField)))) { + if (!id || !(cursors = Cast(Document.cursors, listSpec(CursorField)))) { return []; } const now = mobxUtils.now(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3fab00968..a70713429 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,14 +1,17 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; +import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; -import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; +import { Doc, DocListCast, Field, FieldType, Opt } from '../../../../fields/Doc'; import { DocData, Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; -import { InkData, InkField, InkTool, PointData, Segment } from '../../../../fields/InkField'; +import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; @@ -16,13 +19,15 @@ import { ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; +import { Gestures, PointData } from '../../../../pen-gestures/GestureTypes'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { aggregateBounds, emptyFunction, intersectRect, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; -import { DragManager, dropActionType } from '../../../util/DragManager'; +import { DragManager } from '../../../util/DragManager'; +import { dropActionType } from '../../../util/DropActionTypes'; import { ReplayMovements } from '../../../util/ReplayMovements'; import { CompileScript } from '../../../util/Scripting'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; @@ -33,8 +38,8 @@ import { Transform } from '../../../util/Transform'; import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; +import { PinProps } from '../../DocComponent'; import { GestureOverlay } from '../../GestureOverlay'; -import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; @@ -42,7 +47,7 @@ import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; -import { PinProps, PresBox } from '../../nodes/trails/PresBox'; +import { PresBox } from '../../nodes/trails/PresBox'; import { CreateImage } from '../../nodes/WebBoxRenderer'; import { StyleProp } from '../../StyleProvider'; import { CollectionSubView } from '../CollectionSubView'; @@ -77,7 +82,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); @computed get paintFunc() { const field = this.dataDoc[this.fieldKey]; - const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as Field)).trim(); + const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as FieldType)).trim(); return !paintFunc ? '' : paintFunc.includes('dashDiv') @@ -635,11 +640,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onGesture = (e: Event, ge: GestureUtils.GestureEvent) => { switch (ge.gesture) { default: - case GestureUtils.Gestures.Line: - case GestureUtils.Gestures.Circle: - case GestureUtils.Gestures.Rectangle: - case GestureUtils.Gestures.Triangle: - case GestureUtils.Gestures.Stroke: + case Gestures.Line: + case Gestures.Circle: + case Gestures.Rectangle: + case Gestures.Triangle: + case Gestures.Stroke: const points = ge.points; const B = this.screenToFreeformContentsXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale; @@ -660,7 +665,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.addDocument(inkDoc); e.stopPropagation(); break; - case GestureUtils.Gestures.Rectangle: + case Gestures.Rectangle: const strokes = this.getActiveDocuments() .filter(doc => doc.type === DocumentType.INK) .map(i => { @@ -672,7 +677,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then(results => {}); break; - case GestureUtils.Gestures.Text: + case Gestures.Text: if (ge.text) { const B = this.screenToFreeformContentsXf.transformPoint(ge.points[0].X, ge.points[0].Y); this.addDocument(Docs.Create.TextDocument(ge.text, { title: ge.text, x: B[0], y: B[1] })); @@ -690,7 +695,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @action onClick = (e: React.MouseEvent) => { if (this._lightboxDoc) this._lightboxDoc = undefined; - if (Utils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) { + if (ClientUtils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) { if (this.onBrowseClickHandler()) { this.onBrowseClickHandler().script.run({ documentView: this.DocumentView?.(), clientX: e.clientX, clientY: e.clientY }); e.stopPropagation(); @@ -746,7 +751,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection segments.forEach(segment => this.forceStrokeGesture( e, - GestureUtils.Gestures.Stroke, + Gestures.Stroke, segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) ) ); @@ -759,7 +764,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }); return false; }; - forceStrokeGesture = (e: PointerEvent, gesture: GestureUtils.Gestures, points: InkData, text?: any) => { + forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => { this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, GestureOverlay.getBounds(points), text)); }; @@ -956,7 +961,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection switch ( !e.ctrlKey && !e.shiftKey && !e.metaKey && !e.altKey ?// Doc.UserDoc().freeformScrollMode : // no modifiers, do assigned mode - e.ctrlKey && !CtrlKey? // otherwise, if ctrl key (pinch gesture) try to zoom else pan + e.ctrlKey && !SnappingManager.CtrlKey? // otherwise, if ctrl key (pinch gesture) try to zoom else pan freeformScrollMode.Zoom : freeformScrollMode.Pan // prettier-ignore ) { case freeformScrollMode.Pan: @@ -1030,9 +1035,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection (!this._props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning let newPanY = Math.max(minPanY, Math.min(maxPanY, panY)); if (false && NumCast(this.layoutDoc.layout_scrollTop) && NumCast(this.layoutDoc._freeform_scale, minScale) !== minScale) { - const relTop = NumCast(this.layoutDoc.layout_scrollTop) / maxScrollTop; - this.layoutDoc.layout_scrollTop = undefined; - newPanY = minPanY + relTop * (maxPanY - minPanY); } else if (fitYscroll > 2 && this.layoutDoc.layout_scrollTop === undefined && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) { const maxPanY = minPanY + fitYscroll; const relTop = (panY - minPanY) / (maxPanY - minPanY); @@ -1289,8 +1291,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection : NumCast(this.layoutDoc._rotation_jitter) * random(-1, 1, NumCast(x), NumCast(y)) ); const childProps = { ...this._props, fieldKey: '', styleProvider: this.clusterStyleProvider }; return { - x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x), - y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y), + x: isNaN(NumCast(x)) ? 0 : NumCast(x), + y: isNaN(NumCast(y)) ? 0 : NumCast(y), z: Cast(z, 'number'), autoDim, rotation, @@ -1424,8 +1426,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return anchor; }; - @action closeInfo = () => (Doc.IsInfoUIDisabled = true); - infoUI = () => (Doc.IsInfoUIDisabled || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />); + childDocsFunc = () => this.childDocs; + @action closeInfo = () => { Doc.IsInfoUIDisabled = true }; // prettier-ignore + infoUI = () => (Doc.IsInfoUIDisabled || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} LayoutDoc={this.layoutDoc} childDocs={this.childDocsFunc} close={this.closeInfo} />); componentDidMount() { this._props.setContentViewBox?.(this); @@ -1483,6 +1486,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (!code.includes('dashDiv')) { const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true }); if (script.compiled) script.run({ this: this.DocumentView?.() }); + // eslint-disable-next-line no-eval } else code && !first && eval?.(code); }, { fireImmediately: true } @@ -1491,7 +1495,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._disposers.layoutElements = reaction( // layoutElements can't be a computed value because doLayoutComputation() is an action that has side effect of updating clusters () => this.doInternalLayoutComputation, - computation => (this._layoutElements = this.doLayoutComputation(computation.newPool, computation.computedElementData)), + computation => { + this._layoutElements = this.doLayoutComputation(computation.newPool, computation.computedElementData); + }, { fireImmediately: true } ); } @@ -1512,7 +1518,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const canvas = oldDiv; const img = document.createElement('img'); // create a Image Element try { - img.src = canvas.toDataURL(); //image source + img.src = canvas.toDataURL(); // image source } catch (e) { console.log(e); } @@ -1567,14 +1573,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const htmlString = new XMLSerializer().serializeToString(newDiv); const nativeWidth = width; const nativeHeight = height; - return CreateImage(Utils.prepend(''), document.styleSheets, htmlString, nativeWidth, (nativeWidth * panelHeight) / panelWidth, (scrollTop * panelHeight) / realNativeHeight) - .then(async (data_url: any) => { - const returnedFilename = await Utils.convertDataUri(data_url, filename, noSuffix, replaceRootFilename); + return CreateImage(ClientUtils.prepend(''), document.styleSheets, htmlString, nativeWidth, (nativeWidth * panelHeight) / panelWidth, (scrollTop * panelHeight) / realNativeHeight) + .then(async (dataUrl: any) => { + const returnedFilename = await ClientUtils.convertDataUri(dataUrl, filename, noSuffix, replaceRootFilename); cb(returnedFilename as string, nativeWidth, nativeHeight); }) - .catch(function (error: any) { - console.error('oops, something went wrong!', error); - }); + .catch((error: any) => console.error('oops, something went wrong!', error)); } componentWillUnmount() { @@ -1583,14 +1587,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } @action - onCursorMove = (e: React.PointerEvent) => { + onCursorMove = () => { // super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); }; @undoBatch promoteCollection = () => { const childDocs = this.childDocs.slice(); - childDocs.forEach(doc => { + childDocs.forEach(docIn => { + const doc = docIn; const scr = this.screenToFreeformContentsXf.inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = scr?.[0]; doc.y = scr?.[1]; @@ -1604,7 +1609,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const width = Math.max(...docs.map(doc => NumCast(doc._width))) + 20; const height = Math.max(...docs.map(doc => NumCast(doc._height))) + 20; const dim = Math.ceil(Math.sqrt(docs.length)); - docs.forEach((doc, i) => { + docs.forEach((docIn, i) => { + const doc = docIn; doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); @@ -1704,14 +1710,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to activeDocs - .filter(doc => doc.isGroup && SnappingManager.IsResizing !== doc && !DragManager.docsBeingDragged.includes(doc)) + .filter(doc => doc.isGroup && SnappingManager.IsResizing !== doc[Id] && !DragManager.docsBeingDragged.includes(doc)) .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); const horizLines: number[] = []; const vertLines: number[] = []; const invXf = this.screenToFreeformContentsXf.inverse(); snappableDocs - .filter(doc => !doc.isGroup && (snapToDraggedDoc || (SnappingManager.IsResizing !== doc && !DragManager.docsBeingDragged.includes(doc)))) + .filter(doc => !doc.isGroup && (snapToDraggedDoc || (SnappingManager.IsResizing !== doc[Id] && !DragManager.docsBeingDragged.includes(doc)))) .forEach(doc => { const { left, top, width, height } = docDims(doc); const topLeftInScreen = invXf.transformPoint(left, top); @@ -1727,10 +1733,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection incrementalRender = action(() => { if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) { - const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); + const layoutUnrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); const loadIncrement = this.Document.isTemplateDoc ? Number.MAX_VALUE : 5; - for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { - this._renderCutoffData.set(layout_unrendered[i][Id] + '', true); + for (let i = 0; i < Math.min(layoutUnrendered.length, loadIncrement); i++) { + this._renderCutoffData.set(layoutUnrendered[i][Id] + '', true); } } this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); @@ -1744,6 +1750,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ); } + showPresPaths = () => CollectionFreeFormView.ShowPresPaths; brushedView = () => this._brushedView; gridColor = () => DashColor(lightOrDark(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor))) @@ -1776,6 +1783,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection brushedView={this.brushedView} isAnnotationOverlay={this.isAnnotationOverlay} transform={this.PanZoomCenterXf} + showPresPaths={this.showPresPaths} transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.Document._viewTransition, 'string', null))} viewDefDivClick={this._props.viewDefDivClick}> {this.props.children ?? null} {/* most likely case of children is document content that's being annoated: eg., an image */} @@ -1828,7 +1836,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._brushtimer1 = setTimeout( action(() => { this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2 }; - this._brushtimer = setTimeout(action(() => (this._brushedView = undefined)), holdTime); // prettier-ignore + this._brushtimer = setTimeout(action(() => { this._brushedView = undefined; }), holdTime); // prettier-ignore }), transTime + 1 ); @@ -1912,6 +1920,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observer class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> { render() { + // eslint-disable-next-line react/destructuring-assignment return this.props.elements().filter(ele => ele.bounds?.z).map(ele => ele.ele); // prettier-ignore } } @@ -1923,11 +1932,12 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { if (!focused) { const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; - let containers = dv.containerViewPath?.() ?? []; + const containers = dv.containerViewPath?.() ?? []; let parFfview = dv.CollectionFreeFormView; - for (var cont of containers) { + containers.forEach(cont => { parFfview = parFfview ?? cont.CollectionFreeFormView; - } + }); + while (parFfview?.Document.isGroup) parFfview = parFfview.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); @@ -1936,17 +1946,21 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY }); } ScriptingGlobals.add(CollectionBrowseClick); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(); }); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true); }); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { const selView = SelectionManager.Views; if (readOnly) return selView[0].ComponentView?.getKeyFrameEditing?.() ? Colors.MEDIUM_BLUE : 'transparent'; runInAction(() => selView[0].ComponentView?.setKeyFrameEditing?.(!selView[0].ComponentView?.getKeyFrameEditing?.())); }); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function pinWithView(pinContent: boolean) { SelectionManager.Views.forEach(view => view._props.pinToPres(view.Document, { @@ -1959,15 +1973,19 @@ ScriptingGlobals.add(function pinWithView(pinContent: boolean) { }) ); }); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function bringToFront() { SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document)); }); -ScriptingGlobals.add(function sendToBack(doc: Doc) { +// eslint-disable-next-line prefer-arrow-callback +ScriptingGlobals.add(function sendToBack() { SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true)); }); -ScriptingGlobals.add(function datavizFromSchema(doc: Doc) { +// eslint-disable-next-line prefer-arrow-callback +ScriptingGlobals.add(function datavizFromSchema() { // creating a dataviz doc to represent the schema table - SelectionManager.Views.forEach(view => { + SelectionManager.Views.forEach(viewIn => { + const view = viewIn; if (!view.layoutDoc.schema_columnKeys) { view.layoutDoc.schema_columnKeys = new List<string>(['title', 'type', 'author', 'author_date']); } @@ -1975,13 +1993,13 @@ ScriptingGlobals.add(function datavizFromSchema(doc: Doc) { if (!keys) return; const children = DocListCast(view.Document[Doc.LayoutFieldKey(view.Document)]); - let csvRows = []; + const csvRows = []; csvRows.push(keys.join(',')); for (let i = 0; i < children.length; i++) { - let eachRow = []; + const eachRow = []; for (let j = 0; j < keys.length; j++) { - var cell = children[i][keys[j]]?.toString(); - if (cell) cell = cell.toString().replace(/\,/g, ''); + let cell = children[i][keys[j]]?.toString(); + if (cell) cell = cell.toString().replace(/,/g, ''); eachRow.push(cell); } csvRows.push(eachRow); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6eca91e9d..b03e435ce 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,7 +1,9 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Utils, intersectRect, lightOrDark, returnFalse } from '../../../../Utils'; +import { ClientUtils, lightOrDark, returnFalse } from '../../../../ClientUtils'; +import { intersectRect } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; @@ -20,6 +22,7 @@ import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { MarqueeViewBounds } from '../../DocComponent'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { PreviewCursor } from '../../PreviewCursor'; import { OpenWhere } from '../../nodes/DocumentView'; @@ -28,6 +31,7 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; + interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; @@ -44,13 +48,6 @@ interface MarqueeViewProps { slowLoadDocuments: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise<void>; } -export interface MarqueeViewBounds { - left: number; - top: number; - width: number; - height: number; -} - @observer export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps & MarqueeViewProps> { public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) { @@ -102,7 +99,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps @action onKeyDown = (e: KeyboardEvent) => { - //make textbox and add it to this collection + // make textbox and add it to this collection // tslint:disable-next-line:prefer-const const cm = ContextMenu.Instance; const [x, y] = this.Transform.transformPoint(this._downX, this._downY); @@ -141,7 +138,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps } } let ypos = y; - ns.map(line => { + ns.forEach(line => { const indent = line.search(/\S|$/); const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + (indent / 3) * 10, y: ypos, title: line }); this._props.addDocument?.(newBox); @@ -155,7 +152,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps pasteImageBitmap((data: any, error: any) => { error && console.log(error); data && - Utils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => { + ClientUtils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => { this._props.Document['thumb-frozen'] = new ImageField(returnedfilename); }); }) @@ -169,7 +166,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined }; this._props.addDocument?.(slide); e.stopPropagation(); - }*/ else if (e.key === 'p' && e.ctrlKey) { + } */ else if (e.key === 'p' && e.ctrlKey) { e.preventDefault(); (async () => { const text: string = await navigator.clipboard.readText(); @@ -184,7 +181,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps e.stopPropagation(); } }; - //heuristically converts pasted text into a table. + // heuristically converts pasted text into a table. // assumes each entry is separated by a tab // skips all rows until it gets to a row with more than one entry // assumes that 1st row has header entry for each column @@ -192,7 +189,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps // any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header // assumes each cell is a string or a number pasteTable(ns: string[], x: number, y: number) { - let csvRows = []; + const csvRows = []; const headers = ns[0].split('\t'); csvRows.push(headers.join(',')); ns[0] = ''; @@ -200,7 +197,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps let eachRow = []; for (let i = 1; i < eachCell.length; i++) { eachRow.push(eachCell[i].replace(/\,/g, '')); - if (i % headers.length == 0) { + if (i % headers.length === 0) { csvRows.push(eachRow); eachRow = []; } @@ -233,7 +230,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps this._lastY = e.pageY; this._lassoPts.push([e.clientX, e.clientY]); if (!e.cancelBubble) { - if (!Utils.isClick(this._lastX, this._lastY, this._downX, this._downY, Date.now())) { + if (!ClientUtils.isClick(this._lastX, this._lastY, this._downX, this._downY, Date.now())) { if (!this._commandExecuted) { this.showMarquee(); } @@ -320,7 +317,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps @action onClick = (e: React.MouseEvent): void => { if (this._props.pointerEvents?.() === 'none') return; - if (Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) { + if (ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) { if (Doc.ActiveTool === InkTool.None) { if (!this._props.trySelectCluster(e.shiftKey)) { !SnappingManager.ExploreMode && this.setPreviewCursor(e.clientX, e.clientY, false, false, this._props.Document); @@ -335,15 +332,21 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }; @action - showMarquee = () => (this._visible = true); + showMarquee = () => { + this._visible = true; + }; @action - hideMarquee = () => (this._visible = false); + hideMarquee = () => { + this._visible = false; + }; @undoBatch delete = action((e?: React.PointerEvent<Element> | KeyboardEvent | undefined, hide?: boolean) => { const selected = this.marqueeSelect(false); SelectionManager.DeselectAll(); - selected.forEach(doc => (hide ? (doc.hidden = true) : this._props.removeDocument?.(doc))); + selected.forEach(doc => { + hide ? (doc.hidden = true) : this._props.removeDocument?.(doc); + }); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -540,6 +543,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }; touchesLine(r1: { left: number; top: number; width: number; height: number }) { + // eslint-disable-next-line no-restricted-syntax for (const lassoPt of this._lassoPts) { const topLeft = this.Transform.transformPoint(lassoPt[0], lassoPt[1]); if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width && r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) { @@ -560,6 +564,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps let hasLeft = false; let hasBottom = false; let hasRight = false; + // eslint-disable-next-line no-restricted-syntax for (const lassoPt of this._lassoPts) { const truePoint = this.Transform.transformPoint(lassoPt[0], lassoPt[1]); hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left && truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); @@ -662,6 +667,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }; render() { return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events <div className="marqueeView" ref={r => { @@ -673,7 +679,9 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible ? 'crosshair' : 'pointer', }} onDragOver={e => e.preventDefault()} - onScroll={e => (e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0)} + onScroll={e => { + e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0; + }} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} |
