feat: task checklist improvements (#797)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/797 Co-authored-by: konrad <k@knt.li> Co-committed-by: konrad <k@knt.li>
This commit is contained in:
91
src/helpers/checklistFromText.test.ts
Normal file
91
src/helpers/checklistFromText.test.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import {findCheckboxesInText, getChecklistStatistics} from './checklistFromText'
|
||||
|
||||
describe('Find checklists in text', () => {
|
||||
it('should find no checkbox', () => {
|
||||
const text: string = 'Lorem Ipsum'
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(0)
|
||||
})
|
||||
it('should find multiple checkboxes', () => {
|
||||
const text: string = `* [ ] Lorem Ipsum
|
||||
* [ ] Dolor sit amet
|
||||
|
||||
Here's some text in between
|
||||
|
||||
* [x] Dolor sit amet
|
||||
- [ ] Dolor sit amet`
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(4)
|
||||
expect(checkboxes[0]).toBe(0)
|
||||
expect(checkboxes[1]).toBe(18)
|
||||
expect(checkboxes[2]).toBe(69)
|
||||
})
|
||||
it('should find one checkbox with *', () => {
|
||||
const text: string = '* [ ] Lorem Ipsum'
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(1)
|
||||
expect(checkboxes[0]).toBe(0)
|
||||
})
|
||||
it('should find one checkbox with -', () => {
|
||||
const text: string = '- [ ] Lorem Ipsum'
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(1)
|
||||
expect(checkboxes[0]).toBe(0)
|
||||
})
|
||||
it('should find one checked checkbox with *', () => {
|
||||
const text: string = '* [x] Lorem Ipsum'
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(1)
|
||||
expect(checkboxes[0]).toBe(0)
|
||||
})
|
||||
it('should find one checked checkbox with -', () => {
|
||||
const text: string = '- [x] Lorem Ipsum'
|
||||
const checkboxes = findCheckboxesInText(text)
|
||||
|
||||
expect(checkboxes).toHaveLength(1)
|
||||
expect(checkboxes[0]).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Get Checklist Statistics in a Text', () => {
|
||||
it('should find no checkbox', () => {
|
||||
const text: string = 'Lorem Ipsum'
|
||||
const stats = getChecklistStatistics(text)
|
||||
|
||||
expect(stats.total).toBe(0)
|
||||
})
|
||||
it('should find one checkbox', () => {
|
||||
const text: string = '* [ ] Lorem Ipsum'
|
||||
const stats = getChecklistStatistics(text)
|
||||
|
||||
expect(stats.total).toBe(1)
|
||||
expect(stats.checked).toBe(0)
|
||||
})
|
||||
it('should find one checked checkbox', () => {
|
||||
const text: string = '* [x] Lorem Ipsum'
|
||||
const stats = getChecklistStatistics(text)
|
||||
|
||||
expect(stats.total).toBe(1)
|
||||
expect(stats.checked).toBe(1)
|
||||
})
|
||||
it('should find multiple mixed and matched', () => {
|
||||
const text: string = `* [ ] Lorem Ipsum
|
||||
* [ ] Dolor sit amet
|
||||
* [x] Dolor sit amet
|
||||
- [x] Dolor sit amet
|
||||
|
||||
Here's some text in between
|
||||
|
||||
* [x] Dolor sit amet
|
||||
- [ ] Dolor sit amet`
|
||||
const stats = getChecklistStatistics(text)
|
||||
|
||||
expect(stats.total).toBe(6)
|
||||
expect(stats.checked).toBe(3)
|
||||
})
|
||||
})
|
53
src/helpers/checklistFromText.ts
Normal file
53
src/helpers/checklistFromText.ts
Normal file
@ -0,0 +1,53 @@
|
||||
const checked = '[x]'
|
||||
|
||||
interface CheckboxStatistics {
|
||||
total: number
|
||||
checked: number
|
||||
}
|
||||
|
||||
interface MatchedCheckboxes {
|
||||
checked: number[]
|
||||
unchecked: number[]
|
||||
}
|
||||
|
||||
const getCheckboxesInText = (text: string): MatchedCheckboxes => {
|
||||
const regex = /[*-] \[[ x]]/g
|
||||
let match
|
||||
const checkboxes: MatchedCheckboxes = {
|
||||
checked: [],
|
||||
unchecked: [],
|
||||
}
|
||||
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
if (match[0].endsWith(checked)) {
|
||||
checkboxes.checked.push(match.index)
|
||||
} else {
|
||||
checkboxes.unchecked.push(match.index)
|
||||
}
|
||||
}
|
||||
|
||||
return checkboxes
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the indices where checkboxes start and end in the given text.
|
||||
*
|
||||
* @param text
|
||||
*/
|
||||
export const findCheckboxesInText = (text: string): number[] => {
|
||||
const checkboxes = getCheckboxesInText(text)
|
||||
|
||||
return [
|
||||
...checkboxes.checked,
|
||||
...checkboxes.unchecked,
|
||||
].sort()
|
||||
}
|
||||
|
||||
export const getChecklistStatistics = (text: string): CheckboxStatistics => {
|
||||
const checkboxes = getCheckboxesInText(text)
|
||||
|
||||
return {
|
||||
total: checkboxes.checked.length + checkboxes.unchecked.length,
|
||||
checked: checkboxes.checked.length,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user