added a spoiler container (#947)

changed toolbar to insert the new spoiler container
changed tests accordingly

References:
https://github.com/markdown-it/markdown-it-container
Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2021-01-13 11:45:33 +01:00 committed by GitHub
parent 9330adf564
commit 7be64bc582
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 60 additions and 18 deletions

View file

@ -63,7 +63,7 @@ describe('Autocompletion', () => {
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span')
.should('have.text', ':::success')
cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line > span span')
.should('have.text', ':::')
.should('have.text', '::: ')
cy.get('.markdown-body > div.alert')
.should('exist')
})
@ -78,7 +78,7 @@ describe('Autocompletion', () => {
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span')
.should('have.text', ':::success')
cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line > span span')
.should('have.text', ':::')
.should('have.text', '::: ')
cy.get('.markdown-body > div.alert')
.should('exist')
})

View file

@ -322,7 +322,7 @@ describe('Toolbar', () => {
cy.get('.fa-caret-square-o-down')
.click()
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span')
.should('have.text', '<details>')
.should('have.text', ':::spoiler Toggle label')
})
it('comment', () => {

View file

@ -5,12 +5,20 @@
*/
import { Editor, Hint, Hints, Pos } from 'codemirror'
import { validAlertLevels } from '../../../markdown-renderer/markdown-it-plugins/alert-container'
import { findWordAtCursor, Hinter } from './index'
const wordRegExp = /^:::((\w|-|_|\+)*)$/
const allSupportedConatiner = ['success', 'info', 'warning', 'danger']
const spoilerSuggestion: Hint = {
text: ':::spoiler Toggle label\nToggled content\n::: \n',
displayText: 'spoiler'
}
const suggestions = validAlertLevels.map((suggestion: string): Hint => ({
text: ':::' + suggestion + '\n\n::: \n',
displayText: suggestion
})).concat(spoilerSuggestion)
const containerHint = (editor: Editor): Promise< Hints| null > => {
const containerHint = (editor: Editor): Promise<Hints | null> => {
return new Promise((resolve) => {
const searchTerm = findWordAtCursor(editor)
const searchResult = wordRegExp.exec(searchTerm.text)
@ -18,16 +26,12 @@ const containerHint = (editor: Editor): Promise< Hints| null > => {
resolve(null)
return
}
const suggestions = allSupportedConatiner
const cursor = editor.getCursor()
if (!suggestions) {
resolve(null)
} else {
resolve({
list: suggestions.map((suggestion: string): Hint => ({
text: ':::' + suggestion + '\n\n:::\n',
displayText: suggestion
})),
list: suggestions.filter((suggestion) => suggestion.displayText?.startsWith(searchResult[1])),
from: Pos(cursor.line, searchTerm.start),
to: Pos(cursor.line, searchTerm.end)
})

View file

@ -64,5 +64,5 @@ export const allHinters: Hinter[] = [
ImageHinter,
LinkAndExtraTagHinter,
PDFHinter,
CollapsableBlockHinter
CollapsableBlockHinter,
]

View file

@ -929,7 +929,7 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n<details>\n <summary>Toggle label</summary>\n Toggled content\n</details>`)
expect(replacement).toEqual(`${textFirstLine}\n:::spoiler Toggle label\n Toggled content\n:::`)
done()
}
})
@ -941,7 +941,7 @@ describe('test collapsable block', () => {
getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false),
getLine: (): string => (textFirstLine),
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n<details>\n <summary>Toggle label</summary>\n Toggled content\n</details>`, done)
replaceRange: expectFromToReplacement(firstLine, `${textFirstLine}\n:::spoiler Toggle label\n Toggled content\n:::`, done)
})
addCollapsableBlock(editor)
})
@ -952,7 +952,7 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n<details>\n <summary>Toggle label</summary>\n Toggled content\n</details>')
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done()
}
})
@ -965,7 +965,7 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n<details>\n <summary>Toggle label</summary>\n Toggled content\n</details>')
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done()
}
})

View file

@ -28,7 +28,7 @@ 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<details>\n <summary>Toggle label</summary>\n Toggled content\n</details>`)
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)

View file

@ -16,6 +16,7 @@ import superscript from 'markdown-it-sup'
import { alertContainer } from '../markdown-it-plugins/alert-container'
import { linkifyExtra } from '../markdown-it-plugins/linkify-extra'
import { MarkdownItParserDebugger } from '../markdown-it-plugins/parser-debugger'
import { spoilerContainer } from '../markdown-it-plugins/spoiler-container'
import { tasksLists } from '../markdown-it-plugins/tasks-lists'
import { twitterEmojis } from '../markdown-it-plugins/twitter-emojis'
import { MarkdownItConfigurator } from './MarkdownItConfigurator'
@ -33,7 +34,8 @@ export class BasicMarkdownItConfigurator extends MarkdownItConfigurator {
footnote,
imsize,
tasksLists,
alertContainer
alertContainer,
spoilerContainer
)
this.postConfigurations.push(
linkifyExtra,

View file

@ -10,7 +10,7 @@ import Renderer from 'markdown-it/lib/renderer'
import Token from 'markdown-it/lib/token'
import { MarkdownItPlugin } from '../replace-components/ComponentReplacer'
type RenderContainerReturn = (tokens: Token[], index: number, options: MarkdownIt.Options, env: unknown, self: Renderer) => void;
export type RenderContainerReturn = (tokens: Token[], index: number, options: MarkdownIt.Options, env: unknown, self: Renderer) => string;
type ValidAlertLevels = ('warning' | 'danger' | 'success' | 'info')
export const validAlertLevels: ValidAlertLevels[] = ['success', 'danger', 'info', 'warning']

View file

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MarkdownIt from 'markdown-it'
import { escapeHtml } from 'markdown-it/lib/common/utils'
import markdownItContainer from 'markdown-it-container'
import Token from 'markdown-it/lib/token'
import { MarkdownItPlugin } from '../replace-components/ComponentReplacer'
import { RenderContainerReturn } from './alert-container'
export const spoilerRegEx = /^spoiler\s+(.*)$/;
const createSpoilerContainer = (): RenderContainerReturn => {
return (tokens: Token[], index: number) => {
const matches = spoilerRegEx.exec(tokens[index].info.trim())
if (tokens[index].nesting === 1 && matches && matches[1]) {
// opening tag
return `<details><summary>${escapeHtml(matches[1])}</summary>`
} else {
// closing tag
return '</details>\n'
}
}
}
export const spoilerContainer: MarkdownItPlugin = (markdownIt: MarkdownIt) => {
markdownItContainer(markdownIt, 'spoiler', {
validate: (params: string) => spoilerRegEx.test(params),
render: createSpoilerContainer()
})
}