diff options
author | bobzel <zzzman@gmail.com> | 2024-09-30 16:20:43 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-09-30 16:20:43 -0400 |
commit | 92d13a93ec871f3f3048b7344528e618845ad76f (patch) | |
tree | d98b5a773dcd0952b349a751ca3aba7755e7384f | |
parent | 588951d4e7e392ca1ce3beacded7d01b6fbd480f (diff) |
a bunch of comparisonBox cleanup and restoring of original click to animate between before/after.
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 157 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 7 |
2 files changed, 54 insertions, 110 deletions
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index cc20f0c57..d2a032d79 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,11 +1,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import axios from 'axios'; -import { action, computed, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; -import { returnFalse, returnNone, returnTrue, setupMoveUpEvents } from '../../../ClientUtils'; +import { returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -37,7 +37,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } + private SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; + private _closeRef = React.createRef<HTMLDivElement>(); private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; + private _reactDisposer: IReactionDisposer | undefined; constructor(props: FieldViewProps) { super(props); makeObservable(this); @@ -48,38 +51,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() @observable private _outputValue = ''; @observable private _loading = false; @observable private _isEmpty = false; - @observable private _audio: Doc = Docs.Create.TextDocument(''); - @observable childActive = false; - @observable _yRelativeToTop: boolean = true; - @observable _animating = ''; - @observable mathJaxConfig = { - loader: { load: ['input/asciimath'] }, - }; + @observable private _childActive = false; + @observable private _animating = ''; @observable private _listening = false; - @observable transcriptElement = ''; - @observable private frontSide = false; - SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; + @observable private _frontSide = false; @observable recognition = new this.SpeechRecognition(); - _closeRef = React.createRef<HTMLDivElement>(); - - get revealOp() { - return this.layoutDoc[`_${this._props.fieldKey}_revealOp`]; - } - get clipHeightKey() { - return '_' + this._props.fieldKey + '_clipHeight'; - } - - get clipWidthKey() { - return '_' + this._props.fieldKey + '_clipWidth'; - } - - @computed get clipWidth() { - return NumCast(this.layoutDoc[this.clipWidthKey], 50); - } - @computed get clipHeight() { - return NumCast(this.layoutDoc[this.clipHeightKey], 200); - } + @computed get revealOpKey() { return `_${this._props.fieldKey}_revealOp`; } // prettier-ignore + @computed get clipHeightKey() { return `_${this._props.fieldKey}_clipHeight`; } // prettier-ignore + @computed get clipWidthKey() { return `_${this._props.fieldKey}_clipWidth`; } // prettier-ignore + @computed get clipWidth() { return NumCast(this.layoutDoc[this.clipWidthKey], 50); } // prettier-ignore + @computed get clipHeight() { return NumCast(this.layoutDoc[this.clipHeightKey], 200); } // prettier-ignore + @computed get revealOp() { return StrCast(this.layoutDoc[this.revealOpKey]); } // prettier-ignore + set revealOp(value:string) { this.layoutDoc[this.revealOpKey] = value; } // prettier-ignore @computed get overlayAlternateIcon() { return ( @@ -94,8 +78,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }) } style={{ - background: this.revealOp === 'hover' ? 'gray' : this.frontSide ? 'white' : 'black', - color: this.revealOp === 'hover' ? 'black' : this.frontSide ? 'black' : 'white', + background: this.revealOp === 'hover' ? 'gray' : this._frontSide ? 'white' : 'black', + color: this.revealOp === 'hover' ? 'black' : this._frontSide ? 'black' : 'white', display: 'inline-block', }}> <div key="alternate" className="formattedTextBox-flip"> @@ -110,8 +94,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return ( <div> <Tooltip - title={this.frontSide ? <div className="dash-tooltip">Flip to front side to use GPT</div> : <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard based on your question on the front</div>}> - <div style={{ position: 'absolute', bottom: '3px', right: '50px', cursor: 'pointer' }} onPointerDown={() => (!this.frontSide ? this.findImageTags() : null)}> + title={this._frontSide ? <div className="dash-tooltip">Flip to front side to use GPT</div> : <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard based on your question on the front</div>}> + <div style={{ position: 'absolute', bottom: '3px', right: '50px', cursor: 'pointer' }} onPointerDown={() => (!this._frontSide ? this.findImageTags() : null)}> <FontAwesomeIcon icon="lightbulb" size="xl" /> </div> </Tooltip> @@ -140,40 +124,37 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() @action handleHover = () => { if (this.revealOp === 'hover') { - this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip'; + this.revealOp = 'flip'; this.Document.forceActive = false; } else { - this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'; + this.revealOp = 'hover'; this.Document.forceActive = true; } }; @action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { this._inputValue = e.target.value; - console.log(this._inputValue); }; @action activateContent = () => { - this.childActive = true; + this._childActive = true; }; @action handleRenderClick = () => { - this.frontSide = !this.frontSide; + this._frontSide = !this._frontSide; }; @action handleRenderGPTClick = async () => { const phonTrans = DocCast(this.Document.audio) ? DocCast(this.Document.audio).phoneticTranscription : undefined; if (phonTrans) { this._inputValue = StrCast(phonTrans); - console.log('INPUT:' + this._inputValue); this.askGPTPhonemes(this._inputValue); } else if (this._inputValue) this.askGPT(GPTCallType.QUIZ); - this.frontSide = false; + this._frontSide = false; this._outputValue = ''; }; - @action - private onPointerMove = ({ movementX }: PointerEvent) => { + onPointerMove = ({ movementX }: PointerEvent) => { const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); if (width && width > 5 && width < this._props.PanelWidth()) { this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth(); @@ -183,12 +164,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() componentDidMount() { this._props.setContentViewBox?.(this); - reaction( + this._reactDisposer = reaction( () => this._props.isSelected(), // when this reaction should update - selected => !selected && (this.childActive = false) // what it should update to + selected => !selected && (this._childActive = false) // what it should update to ); } + componentWillUnmount() { + this._reactDisposer?.(); + } + protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => { this._disposers[disposerId]?.(); if (ele) { @@ -241,7 +226,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() this.dataDoc[which] = undefined; return true; } - console.log('FALSE'); return false; }; @@ -271,7 +255,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() remDoc1 = (docs: Doc | Doc[]) => toList(docs).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); remDoc2 = (docs: Doc | Doc[]) => toList(docs).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_2'), true); - private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => { + registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => { if (e.button !== 2) { setupMoveUpEvents( this, @@ -280,7 +264,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() emptyFunction, action((moveEv, doubleTap) => { if (doubleTap) { - this.childActive = true; + this._childActive = true; if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); } @@ -288,7 +272,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() false, undefined, action(() => { - if (this.childActive) return; + if (this._childActive) return; this._animating = 'all 200ms'; // on click, animate slider movement to the targetWidth this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth(); @@ -308,8 +292,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() * Set up speech to text tool. */ setListening = () => { - const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; - if (SpeechRecognition) { + if (this.SpeechRecognition) { this.recognition.continuous = true; this.recognition.interimResults = true; this.recognition.lang = 'en-US'; @@ -340,8 +323,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() case 'fr-FR': return 'French'; //prettier-ignore case 'it-IT': return 'Italian'; //prettier-ignore case 'zh-CH': return 'Mandarin Chinese'; //prettier-ignore - case 'ja': return 'Japanese'; //prettier-ignore - default: return 'Korean'; //prettier-ignore + case 'ja': return 'Japanese'; //prettier-ignore + default: return 'Korean'; //prettier-ignore } }; @@ -363,44 +346,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() this._props.DocumentView?.()._props.addDocument?.(newAudio); }; - /** - * Gets the transcription of an audio recording by sending the - * recording to backend. - */ - pushInfo = async () => { - const audio = { - file: this._audio.url, - }; - const response = await axios.post('http://localhost:105/recognize/', audio, { - headers: { - 'Content-Type': 'application/json', - }, - }); - this.Document.phoneticTranscription = response.data['transcription']; - }; - - getYouTubeVideoId = (url: string) => { - const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=|\?v=)([^#&?]*).*/; - const match = url.match(regExp); - return match && match[2].length === 11 ? match[2] : null; - }; - - /** - * Gets the transcript of a youtube video by sending the video url to the backend. - * @returns transcription of youtube recording - */ - youtubeUpload = async () => { - const audio = { - file: this.getYouTubeVideoId(StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)), - }; - const response = await axios.post('http://localhost:105/youtube/', audio, { - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data['transcription']; - }; - createFlashcardPile(collectionArr: Doc[], gpt: boolean) { const newCol = Docs.Create.CarouselDocument(collectionArr, { _width: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 250) + 50, @@ -497,7 +442,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res; } else if (callType == GPTCallType.QUIZ) { console.log(this._inputValue); - this.frontSide = true; + this._frontSide = true; this._outputValue = res.replace(/UserAnswer/g, "user's answer").replace(/Rubric/g, 'rubric'); } else if (callType === GPTCallType.FLASHCARD) { this._loading = false; @@ -652,11 +597,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() @action flipFlashcard = () => { - this.frontSide = !this.frontSide; + this._frontSide = !this._frontSide; }; hoverFlip = (side: boolean) => { - if (this.revealOp === 'hover') this.frontSide = side; + if (this.revealOp === 'hover') this._frontSide = side; }; testForTextFields = (whichSlot: string) => { @@ -685,7 +630,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return layoutTemplateString; }; - childActiveFunc = () => this.childActive; + childActiveFunc = () => this._childActive; render() { const clearButton = (which: string) => ( @@ -709,7 +654,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <DocumentView {...this._props} showTags={undefined} - fitWidth={undefined} + fitWidth={undefined} // set to returnTrue to make images fill the comparisonBox-- should be a user option ignoreUsePath={layoutString ? true : undefined} renderDepth={this.props.renderDepth + 1} LayoutTemplateString={layoutString} @@ -717,15 +662,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() containerViewPath={this._props.docViewPath} moveDocument={whichSlot.endsWith('1') ? this.moveDoc1 : this.moveDoc2} removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2} - NativeWidth={this.layoutWidth} - NativeHeight={this.layoutHeight} + NativeWidth={returnZero} + NativeHeight={returnZero} isContentActive={this.childActiveFunc} isDocumentActive={returnFalse} dontSelect={returnTrue} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} - styleProvider={this.childActive ? this._props.styleProvider : this.docStyleProvider} + styleProvider={this._childActive ? this._props.styleProvider : this.docStyleProvider} hideLinkButton - pointerEvents={this.childActive ? undefined : returnNone} + pointerEvents={this._childActive ? undefined : returnNone} /> {!this.Document._layout_isFlashcard ? clearButton(whichSlot) : null} </> @@ -742,7 +687,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() style={{ width: this._props.PanelWidth() }} onPointerDown={e => { this.registerSliding(e, cover); - this.activateContent(); + this.Document._layout_isFlashcard && this.activateContent(); }} ref={ele => this.createDropTarget(ele, which, index)}> {!this._isEmpty ? displayDoc(which) : null} @@ -750,7 +695,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() ); if (this.Document._layout_isFlashcard) { - const side = this.frontSide ? 1 : 0; + const side = this._frontSide ? 1 : 0; // add text box to each side when comparison box is first created if (!this.dataDoc[this.fieldKey + '_0'] && !this._isEmpty) { @@ -773,14 +718,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <p style={{ display: text === '' ? 'flex' : 'none', color: 'white', marginLeft: '10px' }}>Return to all flashcards and add text to both sides. </p> <div className="input-box"> <textarea - value={this.frontSide ? this._outputValue : this._inputValue} + value={this._frontSide ? this._outputValue : this._inputValue} onChange={this.handleInputChange} onScroll={e => { e.stopPropagation(); e.preventDefault(); }} placeholder={!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? 'Enter a response for GPT to evaluate.' : ''} - readOnly={this.frontSide}></textarea> + readOnly={this._frontSide}></textarea> {this._loading ? ( <div className="loading-spinner" style={{ position: 'absolute' }}> @@ -812,7 +757,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() Evaluate Pronunciation </button> - {!this.frontSide ? ( + {!this._frontSide ? ( <button className="submit-buttonsubmit" type="button" onClick={this.handleRenderGPTClick} style={{ borderRadius: '2px', marginBottom: '3px', width: '100%' }}> Submit </button> diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ae9e70e8d..509a0c8d7 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -25,7 +25,7 @@ import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { SnappingManager } from '../../util/SnappingManager'; -import { undoBatch } from '../../util/UndoManager'; +import { undoable, undoBatch } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; @@ -195,8 +195,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const images = await this.fetchImages(); }; - @undoBatch - drop = (e: Event, de: DragManager.DropEvent) => { + drop = undoable((e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData) { let added: boolean | undefined; const targetIsBullseye = (ele: HTMLElement): boolean => { @@ -225,7 +224,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { return added; } return false; - }; + }, 'image drop'); @undoBatch resolution = () => { |