Add prettier for codestyle and re-format everything (#1294)

This commit is contained in:
Erik Michelson 2021-06-06 23:14:00 +02:00 committed by GitHub
parent 8b78154075
commit 0aae1f70d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
319 changed files with 4809 additions and 3936 deletions

View file

@ -19,28 +19,33 @@ export interface EditorPreferenceBooleanProps {
}
export const EditorPreferenceBooleanProperty: React.FC<EditorPreferenceBooleanProps> = ({ property }) => {
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
const preference = useSelector(
(state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '',
equal
)
const { t } = useTranslation()
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: boolean = event.target.value === 'true'
const selectItem = useCallback(
(event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: boolean = event.target.value === 'true'
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
}, [property])
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
},
[property]
)
const i18nPrefix = `editor.modal.preferences.${ property }`
const i18nPrefix = `editor.modal.preferences.${property}`
return (
<EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.SELECT }
value={ preference }>
<option value={ 'true' }>
{ t(`${ i18nPrefix }.on`) }
</option>
<option value={ 'false' }>
{ t(`${ i18nPrefix }.off`) }
</option>
<EditorPreferenceInput
onChange={selectItem}
property={property}
type={EditorPreferenceInputType.SELECT}
value={preference}>
<option value={'true'}>{t(`${i18nPrefix}.on`)}</option>
<option value={'false'}>{t(`${i18nPrefix}.off`)}</option>
</EditorPreferenceInput>
)
}

View file

@ -20,21 +20,28 @@ export interface EditorPreferenceInputProps {
value?: string | number | string[]
}
export const EditorPreferenceInput: React.FC<EditorPreferenceInputProps> = ({ property, type, onChange, value, children }) => {
export const EditorPreferenceInput: React.FC<EditorPreferenceInputProps> = ({
property,
type,
onChange,
value,
children
}) => {
useTranslation()
return (
<Form.Group controlId={ `editor-pref-${ property }` }>
<Form.Group controlId={`editor-pref-${property}`}>
<Form.Label>
<Trans
i18nKey={ `editor.modal.preferences.${ property }${ type === EditorPreferenceInputType.NUMBER ? '' : '.label' }` }/>
i18nKey={`editor.modal.preferences.${property}${type === EditorPreferenceInputType.NUMBER ? '' : '.label'}`}
/>
</Form.Label>
<Form.Control
as={ type === EditorPreferenceInputType.NUMBER ? 'input' : 'select' }
as={type === EditorPreferenceInputType.NUMBER ? 'input' : 'select'}
size='sm'
value={ value }
onChange={ onChange }
type={ type === EditorPreferenceInputType.NUMBER ? 'number' : '' }>
{ children }
value={value}
onChange={onChange}
type={type === EditorPreferenceInputType.NUMBER ? 'number' : ''}>
{children}
</Form.Control>
</Form.Group>
)

View file

@ -11,8 +11,7 @@ import { setEditorLigatures } from '../../../../../redux/editor/methods'
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
export const EditorPreferenceLigaturesSelect: React.FC = () => {
const ligaturesEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.ligatures)
.toString())
const ligaturesEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.ligatures).toString())
const saveLigatures = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const ligaturesActivated: boolean = event.target.value === 'true'
setEditorLigatures(ligaturesActivated)
@ -20,10 +19,13 @@ export const EditorPreferenceLigaturesSelect: React.FC = () => {
const { t } = useTranslation()
return (
<EditorPreferenceInput onChange={ saveLigatures } value={ ligaturesEnabled } property={ 'ligatures' }
type={ EditorPreferenceInputType.BOOLEAN }>
<option value='true'>{ t(`common.yes`) }</option>
<option value='false'>{ t(`common.no`) }</option>
<EditorPreferenceInput
onChange={saveLigatures}
value={ligaturesEnabled}
property={'ligatures'}
type={EditorPreferenceInputType.BOOLEAN}>
<option value='true'>{t(`common.yes`)}</option>
<option value='false'>{t(`common.no`)}</option>
</EditorPreferenceInput>
)
}

View file

@ -18,18 +18,28 @@ export interface EditorPreferenceNumberProps {
}
export const EditorPreferenceNumberProperty: React.FC<EditorPreferenceNumberProps> = ({ property }) => {
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
const preference = useSelector(
(state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '',
equal
)
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: number = Number.parseInt(event.target.value)
const selectItem = useCallback(
(event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: number = Number.parseInt(event.target.value)
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
}, [property])
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
},
[property]
)
return (
<EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.NUMBER }
value={ preference }/>
<EditorPreferenceInput
onChange={selectItem}
property={property}
type={EditorPreferenceInputType.NUMBER}
value={preference}
/>
)
}

View file

@ -19,28 +19,41 @@ export interface EditorPreferenceSelectPropertyProps {
selections: string[]
}
export const EditorPreferenceSelectProperty: React.FC<EditorPreferenceSelectPropertyProps> = ({ property, selections }) => {
const preference = useSelector((state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '', equal)
export const EditorPreferenceSelectProperty: React.FC<EditorPreferenceSelectPropertyProps> = ({
property,
selections
}) => {
const preference = useSelector(
(state: ApplicationState) => state.editorConfig.preferences[property]?.toString() || '',
equal
)
const { t } = useTranslation()
const selectItem = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: string = event.target.value
const selectItem = useCallback(
(event: ChangeEvent<HTMLSelectElement>) => {
const selectedItem: string = event.target.value
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
}, [property])
mergeEditorPreferences({
[property]: selectedItem
} as EditorConfiguration)
},
[property]
)
const i18nPrefix = `editor.modal.preferences.${ property }`
const i18nPrefix = `editor.modal.preferences.${property}`
return (
<EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.SELECT }
value={ preference }>
{ selections.map(selection =>
<option key={ selection } value={ selection }>
{ t(`${ i18nPrefix }.${ selection }`) }
</option>) }
<EditorPreferenceInput
onChange={selectItem}
property={property}
type={EditorPreferenceInputType.SELECT}
value={preference}>
{selections.map((selection) => (
<option key={selection} value={selection}>
{t(`${i18nPrefix}.${selection}`)}
</option>
))}
</EditorPreferenceInput>
)
}

View file

@ -11,8 +11,7 @@ import { setEditorSmartPaste } from '../../../../../redux/editor/methods'
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
export const EditorPreferenceSmartPasteSelect: React.FC = () => {
const smartPasteEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.smartPaste)
.toString())
const smartPasteEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.smartPaste).toString())
const saveSmartPaste = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const smartPasteActivated: boolean = event.target.value === 'true'
setEditorSmartPaste(smartPasteActivated)
@ -21,13 +20,12 @@ export const EditorPreferenceSmartPasteSelect: React.FC = () => {
return (
<EditorPreferenceInput
onChange={ saveSmartPaste }
value={ smartPasteEnabled }
property={ 'smartPaste' }
type={ EditorPreferenceInputType.BOOLEAN }
>
<option value='true'>{ t(`common.yes`) }</option>
<option value='false'>{ t(`common.no`) }</option>
onChange={saveSmartPaste}
value={smartPasteEnabled}
property={'smartPaste'}
type={EditorPreferenceInputType.BOOLEAN}>
<option value='true'>{t(`common.yes`)}</option>
<option value='false'>{t(`common.no`)}</option>
</EditorPreferenceInput>
)
}

View file

@ -24,47 +24,55 @@ import { EditorPreferenceSmartPasteSelect } from './editor-preference-smart-past
export const EditorPreferences: React.FC = () => {
const { t } = useTranslation()
const [showModal, setShowModal] = useState(false)
const indentWithTabs = useSelector((state: ApplicationState) => state.editorConfig.preferences.indentWithTabs ?? false, equal)
const indentWithTabs = useSelector(
(state: ApplicationState) => state.editorConfig.preferences.indentWithTabs ?? false,
equal
)
return (
<Fragment>
<Button variant='light' onClick={ () => setShowModal(true) } title={ t('editor.editorToolbar.preferences') }>
<ForkAwesomeIcon icon="wrench"/>
<Button variant='light' onClick={() => setShowModal(true)} title={t('editor.editorToolbar.preferences')}>
<ForkAwesomeIcon icon='wrench' />
</Button>
<CommonModal
show={ showModal }
onHide={ () => setShowModal(false) }
titleI18nKey={ 'editor.modal.preferences.title' }
closeButton={ true }
icon={ 'wrench' }>
show={showModal}
onHide={() => setShowModal(false)}
titleI18nKey={'editor.modal.preferences.title'}
closeButton={true}
icon={'wrench'}>
<Form>
<ListGroup>
<ListGroup.Item>
<EditorPreferenceSelectProperty property={ EditorPreferenceProperty.THEME }
selections={ ['one-dark', 'neat'] }/>
<EditorPreferenceSelectProperty
property={EditorPreferenceProperty.THEME}
selections={['one-dark', 'neat']}
/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSelectProperty property={ EditorPreferenceProperty.KEYMAP }
selections={ ['sublime', 'emacs', 'vim'] }/>
<EditorPreferenceSelectProperty
property={EditorPreferenceProperty.KEYMAP}
selections={['sublime', 'emacs', 'vim']}
/>
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceBooleanProperty property={ EditorPreferenceProperty.INDENT_WITH_TABS }/>
<EditorPreferenceBooleanProperty property={EditorPreferenceProperty.INDENT_WITH_TABS} />
</ListGroup.Item>
<ShowIf condition={ !indentWithTabs }>
<ShowIf condition={!indentWithTabs}>
<ListGroup.Item>
<EditorPreferenceNumberProperty property={ EditorPreferenceProperty.INDENT_UNIT }/>
<EditorPreferenceNumberProperty property={EditorPreferenceProperty.INDENT_UNIT} />
</ListGroup.Item>
</ShowIf>
<ListGroup.Item>
<EditorPreferenceLigaturesSelect/>
<EditorPreferenceLigaturesSelect />
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceSmartPasteSelect/>
<EditorPreferenceSmartPasteSelect />
</ListGroup.Item>
<ListGroup.Item>
<EditorPreferenceInput onChange={ () => alert('This feature is not yet implemented.') }
property={ EditorPreferenceProperty.SPELL_CHECK }
type={ EditorPreferenceInputType.SELECT }>
<EditorPreferenceInput
onChange={() => alert('This feature is not yet implemented.')}
property={EditorPreferenceProperty.SPELL_CHECK}
type={EditorPreferenceInputType.SELECT}>
<option value='off'>Off</option>
<option value='en'>English</option>
</EditorPreferenceInput>

View file

@ -23,15 +23,19 @@ export const EmojiPickerButton: React.FC<EmojiPickerButtonProps> = ({ editor })
return (
<Fragment>
<EmojiPicker
show={ showEmojiPicker }
onEmojiSelected={ (emoji) => {
show={showEmojiPicker}
onEmojiSelected={(emoji) => {
setShowEmojiPicker(false)
addEmoji(emoji, editor)
} }
onDismiss={ () => setShowEmojiPicker(false) }/>
<Button data-cy={ 'show-emoji-picker' } variant='light' onClick={ () => setShowEmojiPicker(old => !old) }
title={ t('editor.editorToolbar.emoji') }>
<ForkAwesomeIcon icon="smile-o"/>
}}
onDismiss={() => setShowEmojiPicker(false)}
/>
<Button
data-cy={'show-emoji-picker'}
variant='light'
onClick={() => setShowEmojiPicker((old) => !old)}
title={t('editor.editorToolbar.emoji')}>
<ForkAwesomeIcon icon='smile-o' />
</Button>
</Fragment>
)

View file

@ -19,13 +19,12 @@ export interface EmojiPickerProps {
onDismiss: () => void
}
export const customEmojis: CustomEmoji[] = Object.keys(ForkAwesomeIcons)
.map((name) => ({
name: `fa-${ name }`,
shortcodes: [`fa-${ name.toLowerCase() }`],
url: forkawesomeIcon,
category: 'ForkAwesome'
}))
export const customEmojis: CustomEmoji[] = Object.keys(ForkAwesomeIcons).map((name) => ({
name: `fa-${name}`,
shortcodes: [`fa-${name.toLowerCase()}`],
url: forkawesomeIcon,
category: 'ForkAwesome'
}))
export const EMOJI_DATA_PATH = '/static/js/emoji-data.json'
@ -93,7 +92,6 @@ export const EmojiPicker: React.FC<EmojiPickerProps> = ({ show, onEmojiSelected,
}, [darkModeEnabled])
return (
<div className={ `position-absolute emoji-picker-container ${ !show ? 'd-none' : '' }` }
ref={ pickerContainerRef }/>
<div className={`position-absolute emoji-picker-container ${!show ? 'd-none' : ''}`} ref={pickerContainerRef} />
)
}

View file

@ -38,42 +38,43 @@ export const CustomTableSizeModal: React.FC<CustomTableSizeModalProps> = ({ show
return (
<CommonModal
show={ showModal }
onHide={ () => onDismiss() }
titleI18nKey={ 'editor.editorToolbar.table.customSize' }
closeButton={ true }
icon={ 'table' }>
<div className={ 'col-lg-10 d-flex flex-row p-3 align-items-center' }>
show={showModal}
onHide={() => onDismiss()}
titleI18nKey={'editor.editorToolbar.table.customSize'}
closeButton={true}
icon={'table'}>
<div className={'col-lg-10 d-flex flex-row p-3 align-items-center'}>
<Form.Control
type={ 'number' }
min={ 1 }
placeholder={ t('editor.editorToolbar.table.cols') }
isInvalid={ tableSize.columns <= 0 }
onChange={ (event) => {
type={'number'}
min={1}
placeholder={t('editor.editorToolbar.table.cols')}
isInvalid={tableSize.columns <= 0}
onChange={(event) => {
const value = Number.parseInt(event.currentTarget.value)
setTableSize(old => ({
setTableSize((old) => ({
rows: old.rows,
columns: isNaN(value) ? 0 : value
}))
} }
}}
/>
<ForkAwesomeIcon icon='times' className='mx-2' fixedWidth={ true }/>
<ForkAwesomeIcon icon='times' className='mx-2' fixedWidth={true} />
<Form.Control
type={ 'number' }
min={ 1 }
placeholder={ t('editor.editorToolbar.table.rows') }
isInvalid={ tableSize.rows <= 0 }
onChange={ (event) => {
type={'number'}
min={1}
placeholder={t('editor.editorToolbar.table.rows')}
isInvalid={tableSize.rows <= 0}
onChange={(event) => {
const value = Number.parseInt(event.currentTarget.value)
setTableSize(old => ({
setTableSize((old) => ({
rows: isNaN(value) ? 0 : value,
columns: old.columns
}))
} }/>
}}
/>
</div>
<ModalFooter>
<Button onClick={ onClick } disabled={ tableSize.rows <= 0 || tableSize.columns <= 0 }>
{ t('editor.editorToolbar.table.create') }
<Button onClick={onClick} disabled={tableSize.rows <= 0 || tableSize.columns <= 0}>
{t('editor.editorToolbar.table.create')}
</Button>
</ModalFooter>
</CommonModal>

View file

@ -23,16 +23,19 @@ export const TablePickerButton: React.FC<TablePickerButtonProps> = ({ editor })
return (
<Fragment>
<TablePicker
show={ showTablePicker }
onDismiss={ () => setShowTablePicker(false) }
onTablePicked={ (rows, cols) => {
show={showTablePicker}
onDismiss={() => setShowTablePicker(false)}
onTablePicked={(rows, cols) => {
setShowTablePicker(false)
addTable(editor, rows, cols)
} }
}}
/>
<Button data-cy={ 'show-table-overlay' } variant='light' onClick={ () => setShowTablePicker(old => !old) }
title={ t('editor.editorToolbar.table.title') }>
<ForkAwesomeIcon icon="table"/>
<Button
data-cy={'show-table-overlay'}
variant='light'
onClick={() => setShowTablePicker((old) => !old)}
title={t('editor.editorToolbar.table.title')}>
<ForkAwesomeIcon icon='table' />
</Button>
</Fragment>
)

View file

@ -20,7 +20,7 @@ export interface TablePickerProps {
}
export type TableSize = {
rows: number,
rows: number
columns: number
}
@ -45,43 +45,44 @@ export const TablePicker: React.FC<TablePickerProps> = ({ show, onDismiss, onTab
}, [onTablePicked, tableSize])
return (
<div className={ `position-absolute table-picker-container p-2 ${ !show || showDialog ? 'd-none' : '' } bg-light` }
ref={ containerRef } role="grid">
<p className={ 'lead' }>
{ tableSize
<div
className={`position-absolute table-picker-container p-2 ${!show || showDialog ? 'd-none' : ''} bg-light`}
ref={containerRef}
role='grid'>
<p className={'lead'}>
{tableSize
? t('editor.editorToolbar.table.size', { cols: tableSize?.columns, rows: tableSize.rows })
: t('editor.editorToolbar.table.title')
}
: t('editor.editorToolbar.table.title')}
</p>
<div className={ 'table-container' }>
{ createNumberRangeArray(8)
.map((row: number) => (
createNumberRangeArray(10)
.map((col: number) => (
<div
key={ `${ row }_${ col }` }
className={ `table-cell ${ tableSize && row < tableSize.rows && col < tableSize.columns ? 'bg-primary border-primary' : '' }` }
onMouseEnter={ () => {
setTableSize({
rows: row + 1,
columns: col + 1
})
} }
title={ t('editor.editorToolbar.table.size', { cols: col + 1, rows: row + 1 }) }
onClick={ onClick }
/>
)
)
)) }
<div className={'table-container'}>
{createNumberRangeArray(8).map((row: number) =>
createNumberRangeArray(10).map((col: number) => (
<div
key={`${row}_${col}`}
className={`table-cell ${
tableSize && row < tableSize.rows && col < tableSize.columns ? 'bg-primary border-primary' : ''
}`}
onMouseEnter={() => {
setTableSize({
rows: row + 1,
columns: col + 1
})
}}
title={t('editor.editorToolbar.table.size', { cols: col + 1, rows: row + 1 })}
onClick={onClick}
/>
))
)}
</div>
<div className="d-flex justify-content-center mt-2">
<Button data-cy={ 'show-custom-table-modal' } className={ 'text-center' } onClick={ () => setShowDialog(true) }>
<ForkAwesomeIcon icon="table"/>&nbsp;{ t('editor.editorToolbar.table.customSize') }
<div className='d-flex justify-content-center mt-2'>
<Button data-cy={'show-custom-table-modal'} className={'text-center'} onClick={() => setShowDialog(true)}>
<ForkAwesomeIcon icon='table' />
&nbsp;{t('editor.editorToolbar.table.customSize')}
</Button>
<CustomTableSizeModal
showModal={ showDialog }
onDismiss={ () => setShowDialog(false) }
onTablePicked={ onTablePicked }
showModal={showDialog}
onDismiss={() => setShowDialog(false)}
onTablePicked={onTablePicked}
/>
</div>
</div>

View file

@ -47,87 +47,138 @@ export const ToolBar: React.FC<ToolBarProps> = ({ editor }) => {
return (
<ButtonToolbar className='bg-light'>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={ 'format-bold' } variant='light' onClick={ () => makeSelectionBold(editor) }
title={ t('editor.editorToolbar.bold') }>
<ForkAwesomeIcon icon="bold"/>
<ButtonGroup className={'mx-1 flex-wrap'}>
<Button
data-cy={'format-bold'}
variant='light'
onClick={() => makeSelectionBold(editor)}
title={t('editor.editorToolbar.bold')}>
<ForkAwesomeIcon icon='bold' />
</Button>
<Button data-cy={ 'format-italic' } variant='light' onClick={ () => makeSelectionItalic(editor) }
title={ t('editor.editorToolbar.italic') }>
<ForkAwesomeIcon icon="italic"/>
<Button
data-cy={'format-italic'}
variant='light'
onClick={() => makeSelectionItalic(editor)}
title={t('editor.editorToolbar.italic')}>
<ForkAwesomeIcon icon='italic' />
</Button>
<Button data-cy={ 'format-underline' } variant='light' onClick={ () => underlineSelection(editor) }
title={ t('editor.editorToolbar.underline') }>
<ForkAwesomeIcon icon="underline"/>
<Button
data-cy={'format-underline'}
variant='light'
onClick={() => underlineSelection(editor)}
title={t('editor.editorToolbar.underline')}>
<ForkAwesomeIcon icon='underline' />
</Button>
<Button data-cy={ 'format-strikethrough' } variant='light' onClick={ () => strikeThroughSelection(editor) }
title={ t('editor.editorToolbar.strikethrough') }>
<ForkAwesomeIcon icon="strikethrough"/>
<Button
data-cy={'format-strikethrough'}
variant='light'
onClick={() => strikeThroughSelection(editor)}
title={t('editor.editorToolbar.strikethrough')}>
<ForkAwesomeIcon icon='strikethrough' />
</Button>
<Button data-cy={ 'format-subscript' } variant='light' onClick={ () => subscriptSelection(editor) }
title={ t('editor.editorToolbar.subscript') }>
<ForkAwesomeIcon icon="subscript"/>
<Button
data-cy={'format-subscript'}
variant='light'
onClick={() => subscriptSelection(editor)}
title={t('editor.editorToolbar.subscript')}>
<ForkAwesomeIcon icon='subscript' />
</Button>
<Button data-cy={ 'format-superscript' } variant='light' onClick={ () => superscriptSelection(editor) }
title={ t('editor.editorToolbar.superscript') }>
<ForkAwesomeIcon icon="superscript"/>
<Button
data-cy={'format-superscript'}
variant='light'
onClick={() => superscriptSelection(editor)}
title={t('editor.editorToolbar.superscript')}>
<ForkAwesomeIcon icon='superscript' />
</Button>
</ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={ 'format-heading' } variant='light' onClick={ () => addHeaderLevel(editor) }
title={ t('editor.editorToolbar.header') }>
<ForkAwesomeIcon icon="header"/>
<ButtonGroup className={'mx-1 flex-wrap'}>
<Button
data-cy={'format-heading'}
variant='light'
onClick={() => addHeaderLevel(editor)}
title={t('editor.editorToolbar.header')}>
<ForkAwesomeIcon icon='header' />
</Button>
<Button data-cy={ 'format-code-block' } variant='light' onClick={ () => addCodeFences(editor) }
title={ t('editor.editorToolbar.code') }>
<ForkAwesomeIcon icon="code"/>
<Button
data-cy={'format-code-block'}
variant='light'
onClick={() => addCodeFences(editor)}
title={t('editor.editorToolbar.code')}>
<ForkAwesomeIcon icon='code' />
</Button>
<Button data-cy={ 'format-block-quote' } variant='light' onClick={ () => addQuotes(editor) }
title={ t('editor.editorToolbar.blockquote') }>
<ForkAwesomeIcon icon="quote-right"/>
<Button
data-cy={'format-block-quote'}
variant='light'
onClick={() => addQuotes(editor)}
title={t('editor.editorToolbar.blockquote')}>
<ForkAwesomeIcon icon='quote-right' />
</Button>
<Button data-cy={ 'format-unordered-list' } variant='light' onClick={ () => addList(editor) }
title={ t('editor.editorToolbar.unorderedList') }>
<ForkAwesomeIcon icon="list"/>
<Button
data-cy={'format-unordered-list'}
variant='light'
onClick={() => addList(editor)}
title={t('editor.editorToolbar.unorderedList')}>
<ForkAwesomeIcon icon='list' />
</Button>
<Button data-cy={ 'format-ordered-list' } variant='light' onClick={ () => addOrderedList(editor) }
title={ t('editor.editorToolbar.orderedList') }>
<ForkAwesomeIcon icon="list-ol"/>
<Button
data-cy={'format-ordered-list'}
variant='light'
onClick={() => addOrderedList(editor)}
title={t('editor.editorToolbar.orderedList')}>
<ForkAwesomeIcon icon='list-ol' />
</Button>
<Button data-cy={ 'format-check-list' } variant='light' onClick={ () => addTaskList(editor) }
title={ t('editor.editorToolbar.checkList') }>
<ForkAwesomeIcon icon="check-square"/>
<Button
data-cy={'format-check-list'}
variant='light'
onClick={() => addTaskList(editor)}
title={t('editor.editorToolbar.checkList')}>
<ForkAwesomeIcon icon='check-square' />
</Button>
</ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={ 'format-link' } variant='light' onClick={ () => addLink(editor) }
title={ t('editor.editorToolbar.link') }>
<ForkAwesomeIcon icon="link"/>
<ButtonGroup className={'mx-1 flex-wrap'}>
<Button
data-cy={'format-link'}
variant='light'
onClick={() => addLink(editor)}
title={t('editor.editorToolbar.link')}>
<ForkAwesomeIcon icon='link' />
</Button>
<Button data-cy={ 'format-image' } variant='light' onClick={ () => addImage(editor) }
title={ t('editor.editorToolbar.image') }>
<ForkAwesomeIcon icon="picture-o"/>
<Button
data-cy={'format-image'}
variant='light'
onClick={() => addImage(editor)}
title={t('editor.editorToolbar.image')}>
<ForkAwesomeIcon icon='picture-o' />
</Button>
<UploadImageButton editor={ editor }/>
<UploadImageButton editor={editor} />
</ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<TablePickerButton editor={ editor }/>
<Button data-cy={ 'format-add-line' } variant='light' onClick={ () => addLine(editor) }
title={ t('editor.editorToolbar.line') }>
<ForkAwesomeIcon icon="minus"/>
<ButtonGroup className={'mx-1 flex-wrap'}>
<TablePickerButton editor={editor} />
<Button
data-cy={'format-add-line'}
variant='light'
onClick={() => addLine(editor)}
title={t('editor.editorToolbar.line')}>
<ForkAwesomeIcon icon='minus' />
</Button>
<Button data-cy={ 'format-collapsable-block' } variant='light' onClick={ () => addCollapsableBlock(editor) }
title={ t('editor.editorToolbar.collapsableBlock') }>
<ForkAwesomeIcon icon="caret-square-o-down"/>
<Button
data-cy={'format-collapsable-block'}
variant='light'
onClick={() => addCollapsableBlock(editor)}
title={t('editor.editorToolbar.collapsableBlock')}>
<ForkAwesomeIcon icon='caret-square-o-down' />
</Button>
<Button data-cy={ 'format-add-comment' } variant='light' onClick={ () => addComment(editor) }
title={ t('editor.editorToolbar.comment') }>
<ForkAwesomeIcon icon="comment"/>
<Button
data-cy={'format-add-comment'}
variant='light'
onClick={() => addComment(editor)}
title={t('editor.editorToolbar.comment')}>
<ForkAwesomeIcon icon='comment' />
</Button>
<EmojiPickerButton editor={ editor }/>
<EmojiPickerButton editor={editor} />
</ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<EditorPreferences/>
<ButtonGroup className={'mx-1 flex-wrap'}>
<EditorPreferences />
</ButtonGroup>
</ButtonToolbar>
)

View file

@ -19,17 +19,20 @@ export interface UploadImageButtonProps {
export const UploadImageButton: React.FC<UploadImageButtonProps> = ({ editor }) => {
const { t } = useTranslation()
const clickRef = useRef<(() => void)>()
const clickRef = useRef<() => void>()
const buttonClick = useCallback(() => {
clickRef.current?.()
}, [])
const onUploadImage = useCallback((file: File) => {
if (editor) {
handleUpload(file, editor)
}
return Promise.resolve()
}, [editor])
const onUploadImage = useCallback(
(file: File) => {
if (editor) {
handleUpload(file, editor)
}
return Promise.resolve()
},
[editor]
)
if (!editor) {
return null
@ -37,10 +40,10 @@ export const UploadImageButton: React.FC<UploadImageButtonProps> = ({ editor })
return (
<Fragment>
<Button variant='light' onClick={ buttonClick } title={ t('editor.editorToolbar.uploadImage') }>
<ForkAwesomeIcon icon={ 'upload' }/>
<Button variant='light' onClick={buttonClick} title={t('editor.editorToolbar.uploadImage')}>
<ForkAwesomeIcon icon={'upload'} />
</Button>
<UploadInput onLoad={ onUploadImage } acceptedFiles={ supportedMimeTypesJoined } onClickRef={ clickRef }/>
<UploadInput onLoad={onUploadImage} acceptedFiles={supportedMimeTypesJoined} onClickRef={clickRef} />
</Fragment>
)
}

View file

@ -30,34 +30,28 @@ const mockEditor = (content: string, line: number) => {
}
describe('Check whether cursor is in codefence', () => {
it('returns false for empty document', () => {
const editor = mockEditor('', 0)
expect(isCursorInCodefence(editor))
.toBe(false)
expect(isCursorInCodefence(editor)).toBe(false)
})
it('returns true with one open codefence directly above', () => {
const editor = mockEditor('```\n', 1)
expect(isCursorInCodefence(editor))
.toBe(true)
expect(isCursorInCodefence(editor)).toBe(true)
})
it('returns true with one open codefence and empty lines above', () => {
const editor = mockEditor('```\n\n\n', 3)
expect(isCursorInCodefence(editor))
.toBe(true)
expect(isCursorInCodefence(editor)).toBe(true)
})
it('returns false with one completed codefence above', () => {
const editor = mockEditor('```\n\n```\n', 3)
expect(isCursorInCodefence(editor))
.toBe(false)
expect(isCursorInCodefence(editor)).toBe(false)
})
it('returns true with one completed and one open codefence above', () => {
const editor = mockEditor('```\n\n```\n\n```\n\n', 6)
expect(isCursorInCodefence(editor))
.toBe(true)
expect(isCursorInCodefence(editor)).toBe(true)
})
})

View file

@ -12,7 +12,7 @@ export const getEmojiIcon = (emoji: EmojiClickEventDetail): string => {
}
if (emoji.name) {
// noinspection CheckTagEmptyBody
return `<i class="fa ${ emoji.name }"></i>`
return `<i class="fa ${emoji.name}"></i>`
}
return ''
}
@ -23,7 +23,7 @@ export const getEmojiShortCode = (emoji: EmojiClickEventDetail): string | undefi
}
let skinToneModifier = ''
if ((emoji.emoji as NativeEmoji).skins && emoji.skinTone !== 0) {
skinToneModifier = `:skin-tone-${ emoji.skinTone as number }:`
skinToneModifier = `:skin-tone-${emoji.skinTone as number}:`
}
return `:${ emoji.emoji.shortcodes[0] }:${ skinToneModifier }`
return `:${emoji.emoji.shortcodes[0]}:${skinToneModifier}`
}

View file

@ -14,9 +14,9 @@ type ClipboardDataFormats = 'text' | 'url' | 'text/plain' | 'text/uri-list' | 't
export interface PasteEvent {
clipboardData: {
files: FileList,
files: FileList
getData: (format: ClipboardDataFormats) => string
},
}
preventDefault: () => void
}

View file

@ -17,31 +17,29 @@ export const subscriptSelection = (editor: Editor): void => wrapTextWith(editor,
export const superscriptSelection = (editor: Editor): void => wrapTextWith(editor, '^')
export const markSelection = (editor: Editor): void => wrapTextWith(editor, '==')
export const addHeaderLevel = (editor: Editor): void => changeLines(editor, line => line.startsWith('#') ? `#${ line }` : `# ${ line }`)
export const addHeaderLevel = (editor: Editor): void =>
changeLines(editor, (line) => (line.startsWith('#') ? `#${line}` : `# ${line}`))
export const addCodeFences = (editor: Editor): void => wrapTextWithOrJustPut(editor, '```\n', '\n```')
export const addQuotes = (editor: Editor): void => insertOnStartOfLines(editor, '> ')
export const addList = (editor: Editor): void => createList(editor, () => '- ')
export const addOrderedList = (editor: Editor): void => createList(editor, j => `${ j }. `)
export const addOrderedList = (editor: Editor): void => createList(editor, (j) => `${j}. `)
export const addTaskList = (editor: Editor): void => createList(editor, () => '- [ ] ')
export const addImage = (editor: Editor): void => addLink(editor, '!')
export const addLine = (editor: Editor): void => changeLines(editor, line => `${ line }\n----`)
export const addCollapsableBlock = (editor: Editor): void => changeLines(editor, line => `${ line }\n:::spoiler Toggle label\n Toggled content\n:::`)
export const addComment = (editor: Editor): void => changeLines(editor, line => `${ line }\n> []`)
export const addLine = (editor: Editor): void => changeLines(editor, (line) => `${line}\n----`)
export const addCollapsableBlock = (editor: Editor): void =>
changeLines(editor, (line) => `${line}\n:::spoiler Toggle label\n Toggled content\n:::`)
export const addComment = (editor: Editor): void => changeLines(editor, (line) => `${line}\n> []`)
export const addTable = (editor: Editor, rows: number, columns: number): void => {
const rowArray = createNumberRangeArray(rows)
const colArray = createNumberRangeArray(columns)
.map(col => col + 1)
const colArray = createNumberRangeArray(columns).map((col) => col + 1)
const head = '| # ' + colArray.join(' | # ') + ' |'
const divider = '| ' + colArray.map(() => '----')
.join(' | ') + ' |'
const body = rowArray.map(() => '| ' + colArray.map(() => 'Text')
.join(' | ') + ' |')
.join('\n')
const table = `${ head }\n${ divider }\n${ body }`
changeLines(editor, line => `${ line }\n${ table }`)
const divider = '| ' + colArray.map(() => '----').join(' | ') + ' |'
const body = rowArray.map(() => '| ' + colArray.map(() => 'Text').join(' | ') + ' |').join('\n')
const table = `${head}\n${divider}\n${body}`
changeLines(editor, (line) => `${line}\n${table}`)
}
export const addEmoji = (emoji: EmojiClickEventDetail, editor: Editor): void => {
@ -76,11 +74,8 @@ const wrapTextWithOrJustPut = (editor: Editor, symbol: string, endSymbol?: strin
const cursor = editor.getCursor()
const lineNumber = cursor.line
const line = editor.getLine(lineNumber)
const replacement = /\s*\\n/.exec(line) ? `${ symbol }${ endSymbol ?? '' }` : `${ symbol }${ line }${ endSymbol ?? '' }`
editor.replaceRange(replacement,
{ line: cursor.line, ch: 0 },
{ line: cursor.line, ch: line.length },
'+input')
const replacement = /\s*\\n/.exec(line) ? `${symbol}${endSymbol ?? ''}` : `${symbol}${line}${endSymbol ?? ''}`
editor.replaceRange(replacement, { line: cursor.line, ch: 0 }, { line: cursor.line, ch: line.length }, '+input')
}
wrapTextWith(editor, symbol, endSymbol ?? symbol)
}
@ -93,8 +88,7 @@ export const insertOnStartOfLines = (editor: Editor, symbol: string): void => {
const to = range.empty() ? { line: cursor.line, ch: editor.getLine(cursor.line).length } : range.to()
const selection = editor.getRange(from, to)
const lines = selection.split('\n')
editor.replaceRange(lines.map(line => `${ symbol }${ line }`)
.join('\n'), from, to, '+input')
editor.replaceRange(lines.map((line) => `${symbol}${line}`).join('\n'), from, to, '+input')
}
editor.setSelections(ranges)
}
@ -105,10 +99,15 @@ export const changeLines = (editor: Editor, replaceFunction: (line: string) => s
for (const range of ranges) {
const lineNumber = range.empty() ? cursor.line : range.from().line
const line = editor.getLine(lineNumber)
editor.replaceRange(replaceFunction(line), { line: lineNumber, ch: 0 }, {
line: lineNumber,
ch: line.length
}, '+input')
editor.replaceRange(
replaceFunction(line),
{ line: lineNumber, ch: 0 },
{
line: lineNumber,
ch: line.length
},
'+input'
)
}
editor.setSelections(ranges)
}
@ -122,8 +121,7 @@ export const createList = (editor: Editor, listMark: (i: number) => string): voi
const selection = editor.getRange(from, to)
const lines = selection.split('\n')
editor.replaceRange(lines.map((line, i) => `${ listMark(i + 1) }${ line }`)
.join('\n'), from, to, '+input')
editor.replaceRange(lines.map((line, i) => `${listMark(i + 1)}${line}`).join('\n'), from, to, '+input')
}
editor.setSelections(ranges)
}
@ -137,9 +135,9 @@ export const addLink = (editor: Editor, prefix?: string): void => {
const selection = editor.getRange(from, to)
const linkRegex = /^(?:https?|ftp|mailto):/
if (linkRegex.exec(selection)) {
editor.replaceRange(`${ prefix || '' }[](${ selection })`, from, to, '+input')
editor.replaceRange(`${prefix || ''}[](${selection})`, from, to, '+input')
} else {
editor.replaceRange(`${ prefix || '' }[${ selection }](https://)`, from, to, '+input')
editor.replaceRange(`${prefix || ''}[${selection}](https://)`, from, to, '+input')
}
}
}
@ -150,6 +148,6 @@ export const insertAtCursor = (editor: Editor, text: string): void => {
for (const range of ranges) {
const from = range.empty() ? { line: cursor.line, ch: cursor.ch } : range.from()
const to = range.empty() ? { line: cursor.line, ch: cursor.ch } : range.to()
editor.replaceRange(`${ text }`, from, to, '+input')
editor.replaceRange(`${text}`, from, to, '+input')
}
}