diff options
| author | bobzel <zzzman@gmail.com> | 2024-05-19 02:08:43 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-05-19 02:08:43 -0400 |
| commit | 6841dc0fd2aecf31eda2102e660c58905d1e6f44 (patch) | |
| tree | 821b79178aa07001274759c716badb2a8a170056 /src/client/views/collections/collectionFreeForm/MarqueeView.tsx | |
| parent | 2fc1fb7d322ab0950afb0d334c17aa93bd16f6c0 (diff) | |
| parent | 13dc6de0e0099f699ad0d2bb54401e6a0aa25018 (diff) | |
merged with soon-to-be-master
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 138 |
1 files changed, 73 insertions, 65 deletions
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 887fa17a8..768270c09 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,8 +1,10 @@ +/* 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, convertImageToBase64 } from '../../../../Utils'; -import { Doc, FieldResult, NumListCast, Opt } from '../../../../fields/Doc'; +import { ClientUtils, lightOrDark, returnFalse } from '../../../../ClientUtils'; +import { intersectRect } from '../../../../Utils'; +import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool } from '../../../../fields/InkField'; @@ -11,27 +13,27 @@ import { RichTextField } from '../../../../fields/RichTextField'; import { Cast, FieldValue, NumCast, StrCast } from '../../../../fields/Types'; import { ImageField, URLField } from '../../../../fields/URLField'; import { GetEffectiveAcl } from '../../../../fields/util'; +import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; +import { DocUtils } from '../../../documents/DocUtils'; import { DocumentType } from '../../../documents/DocumentTypes'; -import { DocUtils, Docs, DocumentOptions } from '../../../documents/Documents'; -import { SelectionManager } from '../../../util/SelectionManager'; -import { freeformScrollMode } from '../../../util/SettingsManager'; -import { SnappingManager } from '../../../util/SnappingManager'; +import { Docs, DocumentOptions } from '../../../documents/Documents'; +import { SnappingManager, freeformScrollMode } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { MarqueeViewBounds } from '../../PinFuncs'; import { PreviewCursor } from '../../PreviewCursor'; -import { OpenWhere } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; +import { OpenWhere } from '../../nodes/OpenWhere'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; +import { ImageLabelHandler } from './ImageLabelHandler'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import { ObjectField } from '../../../../fields/ObjectField'; -import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; -import { ImageLabelHandler } from './ImageLabelHandler'; -import { listSpec } from '../../../../fields/Schema'; +import { ImageUtility } from '../../nodes/generativeFill/generativeFillUtils/ImageHandler'; interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; @@ -48,13 +50,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) { @@ -108,7 +103,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); @@ -147,7 +142,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); @@ -161,7 +156,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); }); }) @@ -171,11 +166,11 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!; slide.x = x; slide.y = y; - FormattedTextBox.SelectOnLoad = slide[Id]; + Doc.SetSelectOnLoad(slide); 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(); @@ -183,14 +178,14 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps this.pasteTable(ns, x, y); })(); e.stopPropagation(); - } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views.length < 2) { + } else if (!e.ctrlKey && !e.metaKey && DocumentView.Selected().length < 2) { FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this._props.childLayoutString ? e.key : ''; FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note'); this._props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100)); 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 @@ -198,15 +193,15 @@ 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] = ''; const eachCell = ns.join('\t').split('\t'); let eachRow = []; for (let i = 1; i < eachCell.length; i++) { - eachRow.push(eachCell[i].replace(/\,/g, '')); - if (i % headers.length == 0) { + eachRow.push(eachCell[i].replace(/,/g, '')); + if (i % headers.length === 0) { csvRows.push(eachRow); eachRow = []; } @@ -239,7 +234,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(); } @@ -257,7 +252,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps if (this._visible) { const mselect = this.marqueeSelect(); if (!e.shiftKey) { - SelectionManager.DeselectAll(mselect.length ? undefined : this._props.Document); + DocumentView.DeselectAll(mselect.length ? undefined : this._props.Document); } const docs = mselect.length ? mselect : [this._props.Document]; this._props.selectDocuments(docs); @@ -328,7 +323,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); @@ -343,15 +338,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))); + DocumentView.DeselectAll(); + selected.forEach(doc => { + hide ? (doc.hidden = true) : this._props.removeDocument?.(doc); + }); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -382,9 +383,9 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }); @undoBatch - pileup = action((e: KeyboardEvent | React.PointerEvent | undefined) => { + pileup = action(() => { const selected = this.marqueeSelect(false); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); selected.forEach(d => this._props.removeDocument?.(d)); const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2)!; this._props.addDocument?.(newCollection); @@ -394,7 +395,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }); /** - * This triggers the TabDocView.PinDoc method which is the universal method + * This triggers the DocumentView.PinDoc method which is the universal method * used to pin documents to the currently active presentation trail. * * This one is unique in that it includes the bounds associated with marquee view. @@ -434,32 +435,34 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps this._selectedDocs = selected; const imagePromises = selected.map(doc => { - let href = (doc['data'] as URLField).url.href; - let hrefParts = href.split('.'); - let hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; - return convertImageToBase64(hrefComplete).then(hrefBase64 => { - return gptImageLabel(hrefBase64).then(response => { - console.log(response); - const labels = response.split('\n'); - console.log(labels); - doc.image_labels = new List<string>(Array.from(labels!)); - return Promise.all(labels!.map(label => gptGetEmbedding(label))).then(embeddings => { - return { doc, embeddings }; - }); - }); - }); + const href = (doc['data'] as URLField).url.href; + const hrefParts = href.split('.'); + const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; + return ImageUtility.urlToBase64(hrefComplete).then(hrefBase64 => + !hrefBase64 + ? undefined + : gptImageLabel(hrefBase64).then(response => { + const labels = response.split('\n'); + doc.image_labels = new List<string>(Array.from(labels!)); + return Promise.all(labels!.map(label => gptGetEmbedding(label))).then(embeddings => { + return { doc, embeddings }; + }); + }) + ); }); - let docsAndEmbeddings = await Promise.all(imagePromises); - - for (const docAndEmbedding of docsAndEmbeddings) { - if (Array.isArray(docAndEmbedding.embeddings)) { - let doc = docAndEmbedding.doc; - for (let i = 0; i < 3; i++) { - doc[`label_embedding_${i + 1}`] = new List<number>(docAndEmbedding.embeddings[i]); + const docsAndEmbeddings = await Promise.all(imagePromises); + docsAndEmbeddings + .filter(d => d) + .map(d => d!) + .forEach(docAndEmbedding => { + if (Array.isArray(docAndEmbedding.embeddings)) { + let doc = docAndEmbedding.doc; + for (let i = 0; i < 3; i++) { + doc[`label_embedding_${i + 1}`] = new List<number>(docAndEmbedding.embeddings[i]); + } } - } - } + }); if (e) { ImageLabelHandler.Instance.displayLabelHandler(e.pageX, e.pageY); @@ -584,7 +587,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }); @undoBatch - summary = action((e: KeyboardEvent | React.PointerEvent | undefined) => { + summary = action(() => { const selected = this.marqueeSelect(false).map(d => { this._props.removeDocument?.(d); d.x = NumCast(d.x) - this.Bounds.left; @@ -629,8 +632,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps (e as any).propagationIsStopped = true; if (e.key === 'g') this.collection(e, true); if (e.key === 'c' || e.key === 't') this.collection(e); - if (e.key === 's' || e.key === 'S') this.summary(e); - if (e.key === 'p') this.pileup(e); + if (e.key === 's' || e.key === 'S') this.summary(); + if (e.key === 'p') this.pileup(); this.cleanupInteractions(false); } if (e.key === 'r' || e.key === ' ') { @@ -642,6 +645,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) { @@ -662,6 +666,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); @@ -775,6 +780,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 => { @@ -786,7 +792,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} |
