Adjust editor config (#976)

* Adjust editor config

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Tilman Vatteroth 2021-02-03 22:13:04 +01:00 committed by GitHub
parent 0180c75e55
commit e12dc523f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
301 changed files with 4393 additions and 3741 deletions

View file

@ -5,7 +5,7 @@
*/
import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal"
import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
@ -30,15 +30,16 @@ export const EditorPreferenceBooleanProperty: React.FC<EditorPreferenceBooleanPr
} 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`)}
<EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.SELECT }
value={ preference }>
<option value={ 'true' }>
{ t(`${ i18nPrefix }.on`) }
</option>
<option value={'false'}>
{t(`${i18nPrefix}.off`)}
<option value={ 'false' }>
{ t(`${ i18nPrefix }.off`) }
</option>
</EditorPreferenceInput>
)

View file

@ -23,17 +23,18 @@ export interface EditorPreferenceInputProps {
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'}`}/>
<Trans
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,7 +11,8 @@ 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)
@ -19,10 +20,10 @@ 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

@ -5,7 +5,7 @@
*/
import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal"
import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react'
import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../../../redux'
@ -29,6 +29,7 @@ export const EditorPreferenceNumberProperty: React.FC<EditorPreferenceNumberProp
}, [property])
return (
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.NUMBER} value={preference}/>
<EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.NUMBER }
value={ preference }/>
)
}

View file

@ -5,7 +5,7 @@
*/
import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal"
import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
@ -32,14 +32,15 @@ export const EditorPreferenceSelectProperty: React.FC<EditorPreferenceSelectProp
} 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

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import equal from "fast-deep-equal"
import equal from 'fast-deep-equal'
import React, { Fragment, useState } from 'react'
import { Button, Form, ListGroup } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
@ -17,8 +17,8 @@ import { EditorPreferenceBooleanProperty } from './editor-preference-boolean-pro
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
import { EditorPreferenceLigaturesSelect } from './editor-preference-ligatures-select'
import { EditorPreferenceNumberProperty } from './editor-preference-number-property'
import { EditorPreferenceProperty } from "./editor-preference-property"
import { EditorPreferenceSelectProperty } from "./editor-preference-select-property"
import { EditorPreferenceProperty } from './editor-preference-property'
import { EditorPreferenceSelectProperty } from './editor-preference-select-property'
export const EditorPreferences: React.FC = () => {
const { t } = useTranslation()
@ -27,36 +27,40 @@ export const EditorPreferences: React.FC = () => {
return (
<Fragment>
<Button variant='light' onClick={() => setShowModal(true)} title={t('editor.editorToolbar.preferences')}>
<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/>
</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,13 +23,14 @@ 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')}>
} }
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,12 +19,13 @@ 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'
@ -92,6 +93,7 @@ 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,42 @@ 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 => ({
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 => ({
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,14 +23,15 @@ 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')}>
<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

@ -5,7 +5,6 @@
*/
.table-picker-container {
z-index: 1111;

View file

@ -45,40 +45,43 @@ 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'}>
<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')
}
</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' : ''}`}
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' : '' }` }
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')}
<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,69 +47,86 @@ 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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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')}>
<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'}>
<ButtonGroup className={ 'mx-1 flex-wrap' }>
<EditorPreferences/>
</ButtonGroup>
</ButtonToolbar>

View file

@ -37,10 +37,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

@ -12,18 +12,18 @@ 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 ''
}
export const getEmojiShortCode = (emoji: EmojiClickEventDetail): string|undefined => {
export const getEmojiShortCode = (emoji: EmojiClickEventDetail): string | undefined => {
if (!emoji.emoji.shortcodes) {
return undefined
}
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

@ -119,9 +119,12 @@ const mockListSelections = (positions: FromTo, empty: boolean): (() => CodeMirro
const expectFromToReplacement = (position: FromTo, expectedReplacement: string, done: () => void): ((replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => void) => {
return (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => {
expect(from).toEqual(position.from)
expect(to).toEqual(position.to)
expect(replacement).toEqual(expectedReplacement)
expect(from)
.toEqual(position.from)
expect(to)
.toEqual(position.to)
expect(replacement)
.toEqual(expectedReplacement)
done()
}
}
@ -410,18 +413,19 @@ describe('test addHeaderLevel', () => {
const { cursor, firstLine, multiline, multilineOffset } = buildRanges()
const noHeading = testContent.split('\n')[0]
const firstHeading = `# ${noHeading}`
const secondHeading = `## ${noHeading}`
const firstHeading = `# ${ noHeading }`
const secondHeading = `## ${ noHeading }`
const firstLineNoHeading = testContent.split('\n')[1]
const firstLineFirstHeading = `# ${firstLineNoHeading}`
const firstLineFirstHeading = `# ${ firstLineNoHeading }`
it('no heading before', done => {
const editor = buildEditor({
getCursor: () => cursor.from,
listSelections: mockListSelections(cursor, true),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstHeading)
expect(replacement)
.toEqual(firstHeading)
done()
},
getLine: (): string => (noHeading)
@ -434,7 +438,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(cursor, true),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(secondHeading)
expect(replacement)
.toEqual(secondHeading)
done()
},
getLine: (): string => (firstHeading)
@ -447,7 +452,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading)
expect(replacement)
.toEqual(firstLineFirstHeading)
done()
},
getLine: (): string => (firstLineNoHeading)
@ -460,7 +466,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(multiline, false),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading)
expect(replacement)
.toEqual(firstLineFirstHeading)
done()
},
getLine: (): string => (firstLineNoHeading)
@ -473,7 +480,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(multilineOffset, false),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading)
expect(replacement)
.toEqual(firstLineFirstHeading)
done()
},
getLine: (): string => (firstLineNoHeading)
@ -492,7 +500,8 @@ describe('test addCodeFences', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => '',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('```\n\n```')
expect(replacement)
.toEqual('```\n\n```')
done()
}
})
@ -506,7 +515,8 @@ describe('test addCodeFences', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => '1st line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('```\n1st line\n```')
expect(replacement)
.toEqual('```\n1st line\n```')
done()
}
})
@ -555,7 +565,8 @@ describe('test addQuotes', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`> ${textFirstLine}`)
expect(replacement)
.toEqual(`> ${ textFirstLine }`)
done()
}
})
@ -568,7 +579,7 @@ describe('test addQuotes', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `> ${textFirstLine}`, done)
replaceRange: expectFromToReplacement(firstLine, `> ${ textFirstLine }`, done)
})
addQuotes(editor)
})
@ -602,7 +613,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`- ${textFirstLine}`)
expect(replacement)
.toEqual(`- ${ textFirstLine }`)
done()
}
})
@ -614,7 +626,7 @@ describe('test unordered list', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `- ${textFirstLine}`, done)
replaceRange: expectFromToReplacement(firstLine, `- ${ textFirstLine }`, done)
})
addList(editor)
})
@ -625,7 +637,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- 2nd line3rd line')
expect(replacement)
.toEqual('- 2nd line3rd line')
done()
}
})
@ -638,7 +651,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- line3rd ')
expect(replacement)
.toEqual('- line3rd ')
done()
}
})
@ -655,7 +669,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`1. ${textFirstLine}`)
expect(replacement)
.toEqual(`1. ${ textFirstLine }`)
done()
}
})
@ -667,7 +682,7 @@ describe('test ordered list', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `1. ${textFirstLine}`, done)
replaceRange: expectFromToReplacement(firstLine, `1. ${ textFirstLine }`, done)
})
addOrderedList(editor)
})
@ -678,7 +693,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('1. 2nd line3rd line')
expect(replacement)
.toEqual('1. 2nd line3rd line')
done()
}
})
@ -691,7 +707,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('1. line3rd ')
expect(replacement)
.toEqual('1. line3rd ')
done()
}
})
@ -709,7 +726,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`- [ ] ${textFirstLine}`)
expect(replacement)
.toEqual(`- [ ] ${ textFirstLine }`)
done()
}
})
@ -721,7 +739,7 @@ describe('test todo list', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `- [ ] ${textFirstLine}`, done)
replaceRange: expectFromToReplacement(firstLine, `- [ ] ${ textFirstLine }`, done)
})
addTaskList(editor)
})
@ -732,7 +750,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- [ ] 2nd line3rd line')
expect(replacement)
.toEqual('- [ ] 2nd line3rd line')
done()
}
})
@ -745,7 +764,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- [ ] line3rd ')
expect(replacement)
.toEqual('- [ ] line3rd ')
done()
}
})
@ -764,7 +784,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[](https://)')
expect(replacement)
.toEqual('[](https://)')
done()
}
})
@ -776,7 +797,7 @@ describe('test addLink', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `[${textFirstLine}](https://)`, done)
replaceRange: expectFromToReplacement(firstLine, `[${ textFirstLine }](https://)`, done)
})
addLink(editor)
})
@ -787,7 +808,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[2nd line3rd line](https://)')
expect(replacement)
.toEqual('[2nd line3rd line](https://)')
done()
}
})
@ -800,7 +822,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[line3rd ](https://)')
expect(replacement)
.toEqual('[line3rd ](https://)')
done()
}
})
@ -819,7 +842,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![](https://)')
expect(replacement)
.toEqual('![](https://)')
done()
}
})
@ -831,7 +855,7 @@ describe('test addImage', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `![${textFirstLine}](https://)`, done)
replaceRange: expectFromToReplacement(firstLine, `![${ textFirstLine }](https://)`, done)
})
addImage(editor)
})
@ -842,7 +866,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![2nd line3rd line](https://)')
expect(replacement)
.toEqual('![2nd line3rd line](https://)')
done()
}
})
@ -855,7 +880,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![line3rd ](https://)')
expect(replacement)
.toEqual('![line3rd ](https://)')
done()
}
})
@ -874,7 +900,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n----`)
expect(replacement)
.toEqual(`${ textFirstLine }\n----`)
done()
}
})
@ -886,7 +913,7 @@ describe('test addLine', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n----`, done)
replaceRange: expectFromToReplacement(firstLine, `${ textFirstLine }\n----`, done)
})
addLine(editor)
})
@ -897,7 +924,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n----')
expect(replacement)
.toEqual('2nd line\n----')
done()
}
})
@ -910,7 +938,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n----')
expect(replacement)
.toEqual('2nd line\n----')
done()
}
})
@ -929,7 +958,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n:::spoiler Toggle label\n Toggled content\n:::`)
expect(replacement)
.toEqual(`${ textFirstLine }\n:::spoiler Toggle label\n Toggled content\n:::`)
done()
}
})
@ -941,7 +971,7 @@ describe('test collapsable block', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n:::spoiler Toggle label\n Toggled content\n:::`, done)
replaceRange: expectFromToReplacement(firstLine, `${ textFirstLine }\n:::spoiler Toggle label\n Toggled content\n:::`, done)
})
addCollapsableBlock(editor)
})
@ -952,7 +982,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
expect(replacement)
.toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done()
}
})
@ -965,7 +996,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
expect(replacement)
.toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done()
}
})
@ -984,7 +1016,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n> []`)
expect(replacement)
.toEqual(`${ textFirstLine }\n> []`)
done()
}
})
@ -996,7 +1029,7 @@ describe('test addComment', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n> []`, done)
replaceRange: expectFromToReplacement(firstLine, `${ textFirstLine }\n> []`, done)
})
addComment(editor)
})
@ -1007,7 +1040,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n> []')
expect(replacement)
.toEqual('2nd line\n> []')
done()
}
})
@ -1020,7 +1054,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n> []')
expect(replacement)
.toEqual('2nd line\n> []')
done()
}
})
@ -1039,7 +1074,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n${table}`)
expect(replacement)
.toEqual(`${ textFirstLine }\n${ table }`)
done()
}
})
@ -1051,7 +1087,7 @@ describe('test addTable', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n${table}`, done)
replaceRange: expectFromToReplacement(firstLine, `${ textFirstLine }\n${ table }`, done)
})
addTable(editor, 1, 3)
})
@ -1062,7 +1098,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`2nd line\n${table}`)
expect(replacement)
.toEqual(`2nd line\n${ table }`)
done()
}
})
@ -1075,7 +1112,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`2nd line\n${table}`)
expect(replacement)
.toEqual(`2nd line\n${ table }`)
done()
}
})
@ -1112,7 +1150,8 @@ describe('test addEmoji with native emoji', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(':1234:')
expect(replacement)
.toEqual(':1234:')
done()
}
})
@ -1173,7 +1212,8 @@ describe('test addEmoji with native emoji', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(forkAwesomeIcon)
expect(replacement)
.toEqual(forkAwesomeIcon)
done()
}
})

View file

@ -17,27 +17,31 @@ 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 => {
@ -72,7 +76,7 @@ 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 ?? ''}`
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 },
@ -89,7 +93,8 @@ 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)
}
@ -117,7 +122,8 @@ 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)
}
@ -131,9 +137,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')
}
}
}
@ -144,6 +150,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')
}
}