import * as React from 'react' ; import { FlashcardType } from 'polar-shared/src/metadata/FlashcardType' ; import { FlashcardButtons } from './FlashcardButtons' ; import { FlashcardTypeSelector } from './FlashcardTypeSelector' ; import { RichTextArea } from '../../../RichTextArea' ; import { RichTextMutator } from '../../../../apps/card_creator/elements/schemaform/RichTextMutator' ; import { ClozeFields , FlashcardInputFieldsType , FlashcardInputs } from './FlashcardInputs' ; import { Ranges } from '../../../../highlights/text/selection/Ranges' ; import { Flashcard } from '../../../../metadata/Flashcard' ; import { FlashcardStyles } from './FlashcardStyles' ; import IconButton from '@material-ui/core/IconButton' ; import { ClozeDeletions } from "./ClozeDeletions" ; import { MUITooltip } from "../../../../mui/MUITooltip" ; import { InputCompleteListener } from "../../../../mui/complete_listeners/InputCompleteListener" ; export class FlashcardInputForCloze extends React . Component < IProps , IState > { private readonly flashcardType : FlashcardType = FlashcardType . CLOZE ; private fields : ClozeFields = { text : "" } ; private richTextMutator ? : RichTextMutator ; constructor ( props , context ) { super ( props , context ) ; this . onCreate = this . onCreate . bind ( this ) ; this . state = { iter : 0 , } ; this . fields = this . toFields ( ) ; } public render ( ) { const fields = this . toFields ( ) ; return ( < div id = "annotation-flashcard-box" className = "m-1" > < InputCompleteListener type = 'meta+enter' onCancel = { this . props . onCancel } onComplete = { ( ) => this . onCreate ( ) } > < RichTextArea id = { `text-${ this . props . id }` } value = { fields . text } defaultValue = { this . props . defaultValue } autofocus = { true } onKeyDown = { event => this . onKeyDown ( event ) } onRichTextMutator = { richTextMutator => this . richTextMutator = richTextMutator } onChange = { ( html ) => this . fields . text = html } /> < /InputCompleteListener> < div style = { FlashcardStyles . BottomBar } > < div style = { FlashcardStyles . BottomBarItem } > < FlashcardTypeSelector flashcardType = { this . flashcardType } onChangeFlashcardType = { flashcardType => this . props . onFlashcardChangeType ( flashcardType ) } / > < /div> < div style = { FlashcardStyles . BottomBarItem } className = "ml-1" > < MUITooltip title = "Create cloze deletion for text" > < IconButton id = { `button-${ this . props . id }` } onClick = { ( ) => this . onClozeDelete ( ) } > [ … ] < /IconButton> < /MUITooltip> < /div> < div style = { { display : 'flex' , flexGrow : 1 , justifyContent : 'flex-end' , alignItems : 'center' } } > < FlashcardButtons onCancel = { this . props . onCancel } existingFlashcard = { this . props . existingFlashcard } onCreate = { ( ) => this . onCreate ( ) } /> < /div> < /div> < /div>); } private toFields ( ) { const text = FlashcardInputs . fieldToString ( 'text' , this . props . existingFlashcard , this . props . defaultValue ) ; return { text } ; } private onClozeDelete ( ) { const sel = window . getSelection ( ) ; if ( ! sel ) { return ; } const range = sel . getRangeAt ( 0 ) ; const textNodes = Ranges . getTextNodes ( range ) ; if ( textNodes . length === 0 ) { return ; } const c = ClozeDeletions . next ( this . fields . text ) ; const prefix = document . createTextNode ( `{{c${ c }::` ) ; const suffix = document . createTextNode ( '}}' ) ; const firstNode = textNodes [ 0 ] ; const lastNode = textNodes [ textNodes . length - 1 ] ; firstNode . parentNode ! . insertBefore ( prefix , firstNode ) ; lastNode . parentNode ! . insertBefore ( suffix , lastNode . nextSibling ) ; sel . removeAllRanges ( ) ; this . fields . text = this . richTextMutator ! . currentValue ( ) ; this . richTextMutator ! . focus ( ) ; } private onKeyDown ( event ) { if ( this . isKeyboardControlShiftC ( event ) ) { this . onClozeDelete ( ) ; event . stopPropagation ( ) ; event . preventDefault ( ) ; } if ( event . getModifierState ( "Control" ) && event . key === "Enter" ) { this . onCreate ( ) ; event . stopPropagation ( ) ; event . preventDefault ( ) ; } } private isKeyboardControlShiftC ( event ) { return event . getModifierState ( "Control" ) && event . getModifierState ( "Shift" ) && event . key === "C" ; } private onCreate ( ) { if ( this . props . onFlashcard ) { this . props . onFlashcard ( this . flashcardType , this . fields ) ; } this . setState ( { iter : this . state . iter + 1 } ) ; } } interface IProps { readonly id : string ; readonly onFlashcard : ( flashcardType : FlashcardType , fields : Readonly < FlashcardInputFieldsType > ) => void ; readonly onFlashcardChangeType : ( flashcardType : FlashcardType ) => void ; readonly onCancel : ( ) => void ; readonly existingFlashcard ? : Flashcard ; readonly defaultValue ? : string ; } interface IState { readonly iter : number ; }