fix(cheatsheet): refactor cheatsheet to use app extensions as source

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-02-21 19:46:56 +01:00
parent 9d49401b4d
commit 24b0070909
53 changed files with 1164 additions and 275 deletions

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { Linter } from '../../components/editor-page/editor-pane/linter/linter'
import type { MarkdownRendererExtension } from '../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import type { EventEmitter2 } from 'eventemitter2'
@ -22,4 +23,8 @@ export abstract class AppExtension {
public buildEditorExtensionComponent(): React.FC {
return Fragment
}
public buildCheatsheetExtensions(): CheatsheetExtension[] {
return []
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { AbcjsMarkdownExtension } from './abcjs-markdown-extension'
@ -11,4 +12,8 @@ export class AbcjsAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new AbcjsMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'abcjs', categoryI18nKey: 'charts', readMoreUrl: new URL('https://www.abcjs.net/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { AlertMarkdownExtension } from './alert-markdown-extension'
@ -14,4 +15,8 @@ export class AlertAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new AlertMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'alert' }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { AsciinemaMarkdownExtension } from './asciinema-markdown-extension'
@ -16,4 +17,8 @@ export class AsciinemaAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new AsciinemaMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'asciinema', categoryI18nKey: 'embedding', readMoreUrl: new URL('https://asciinema.org/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { BlockquoteExtraTagMarkdownExtension } from './blockquote-extra-tag-markdown-extension'
@ -14,4 +15,8 @@ export class BlockquoteAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new BlockquoteExtraTagMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'blockquoteTags', entries: [{ i18nKey: 'name' }, { i18nKey: 'color' }, { i18nKey: 'time' }] }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { CsvTableMarkdownExtension } from './csv-table-markdown-extension'
@ -14,4 +15,8 @@ export class CsvTableAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new CsvTableMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'csv', entries: [{ i18nKey: 'table' }, { i18nKey: 'header' }] }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { FlowchartMarkdownExtension } from './flowchart-markdown-extension'
@ -14,4 +15,8 @@ export class FlowchartAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new FlowchartMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'flowchart', categoryI18nKey: 'charts', readMoreUrl: new URL('https://flowchart.js.org/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { GistMarkdownExtension } from './gist-markdown-extension'
@ -14,4 +15,8 @@ export class GistAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new GistMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'gist', categoryI18nKey: 'embedding', readMoreUrl: new URL('https://gist.github.com/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { GraphvizMarkdownExtension } from './graphviz-markdown-extension'
@ -14,4 +15,8 @@ export class GraphvizAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new GraphvizMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'graphviz', categoryI18nKey: 'charts', readMoreUrl: new URL('https://graphviz.org/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { HighlightedCodeMarkdownExtension } from './highlighted-code-markdown-extension'
@ -14,4 +15,13 @@ export class HighlightedCodeFenceAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new HighlightedCodeMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [
{
i18nKey: 'codeHighlighting',
entries: [{ i18nKey: 'language' }, { i18nKey: 'lineNumbers' }, { i18nKey: 'lineWrapping' }]
}
]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { KatexMarkdownExtension } from './katex-markdown-extension'
@ -16,4 +17,8 @@ export class KatexAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new KatexMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'katex', readMoreUrl: new URL('https://katex.org/') }]
}
}

View file

@ -3,9 +3,8 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { HtmlToReact } from '../../../components/common/html-to-react/html-to-react'
import { testId } from '../../../utils/test-id'
import convertHtmlToReact from '@hedgedoc/html-to-react'
import { sanitize } from 'dompurify'
import KaTeX from 'katex'
import 'katex/dist/katex.min.css'
import React, { useMemo } from 'react'
@ -26,10 +25,12 @@ export const KatexFrame: React.FC<KatexFrameProps> = ({ expression, block = fals
const dom = useMemo(() => {
try {
const katexHtml = KaTeX.renderToString(expression, {
displayMode: block === true,
displayMode: block,
throwOnError: true
})
return convertHtmlToReact(sanitize(katexHtml, { ADD_TAGS: ['semantics', 'annotation'] }))
return (
<HtmlToReact htmlCode={katexHtml} domPurifyConfig={{ ADD_TAGS: ['semantics', 'annotation'] }}></HtmlToReact>
)
} catch (error) {
return (
<Alert className={block ? '' : 'd-inline-block'} variant={'danger'}>

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { MermaidMarkdownExtension } from './mermaid-markdown-extension'
@ -14,4 +15,8 @@ export class MermaidAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new MermaidMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'mermaid', categoryI18nKey: 'charts', readMoreUrl: new URL('https://mermaid.js.org/') }]
}
}

View file

@ -3,6 +3,12 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { BasicMarkdownSyntaxAppExtension } from '../../components/markdown-renderer/extensions/basic-markdown-syntax/basic-markdown-syntax-app-extension'
import { BootstrapIconAppExtension } from '../../components/markdown-renderer/extensions/bootstrap-icons/bootstrap-icon-app-extension'
import { EmojiAppExtension } from '../../components/markdown-renderer/extensions/emoji/emoji-app-extension'
import { IframeCapsuleAppExtension } from '../../components/markdown-renderer/extensions/iframe-capsule/iframe-capsule-app-extension'
import { ImagePlaceholderAppExtension } from '../../components/markdown-renderer/extensions/image-placeholder/image-placeholder-app-extension'
import { TableOfContentsAppExtension } from '../../components/markdown-renderer/extensions/table-of-contents/table-of-contents-app-extension'
import type { AppExtension } from '../base/app-extension'
import { AbcjsAppExtension } from './abcjs/abcjs-app-extension'
import { AlertAppExtension } from './alert/alert-app-extension'
@ -48,5 +54,11 @@ export const optionalAppExtensions: AppExtension[] = [
new YoutubeAppExtension(),
new TaskListCheckboxAppExtension(),
new HighlightedCodeFenceAppExtension(),
new ForkAwesomeHtmlTagAppExtension()
new ForkAwesomeHtmlTagAppExtension(),
new BootstrapIconAppExtension(),
new EmojiAppExtension(),
new TableOfContentsAppExtension(),
new ImagePlaceholderAppExtension(),
new IframeCapsuleAppExtension(),
new BasicMarkdownSyntaxAppExtension()
]

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { PlantumlMarkdownExtension } from './plantuml-markdown-extension'
@ -16,4 +17,8 @@ export class PlantumlAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new PlantumlMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'plantuml', categoryI18nKey: 'charts', readMoreUrl: new URL('https://plantuml.com/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { SpoilerMarkdownExtension } from './spoiler-markdown-extension'
@ -16,4 +17,8 @@ export class SpoilerAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new SpoilerMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'spoiler' }]
}
}

View file

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
/**
* Returns the markdown line prefix for a task list checkbox.
*
* @param state The check state of the checkbox.
*/
export const createCheckboxContent = (state: boolean) => {
return `[${state ? 'x' : ' '}]`
}

View file

@ -13,7 +13,7 @@ type EventEmittingTaskListCheckboxProps = Omit<TaskListProps, 'onTaskCheckedChan
export interface TaskCheckedEventPayload {
lineInMarkdown: number
checked: boolean
newCheckedState: boolean
}
/**
@ -25,7 +25,10 @@ export const EventEmittingTaskListCheckbox: React.FC<EventEmittingTaskListCheckb
const emitter = useExtensionEventEmitter()
const sendEvent: TaskCheckedChangeHandler = useCallback(
(lineInMarkdown: number, checked: boolean) => {
emitter?.emit(TaskListCheckboxAppExtension.EVENT_NAME, { lineInMarkdown, checked } as TaskCheckedEventPayload)
emitter?.emit(TaskListCheckboxAppExtension.EVENT_NAME, {
lineInMarkdown,
newCheckedState: checked
} as TaskCheckedEventPayload)
},
[emitter]
)

View file

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Optional } from '@mrdrogdrog/optional'
const TASK_REGEX = /^(\s*(?:[-*+]|\d+[.)]) )(\[[ xX]?])/
/**
* Checks if the given markdown content contains a task list checkbox at the given line index.
*
* @param markdownContent The content that should be checked
* @param lineIndex The index of the line that should be checked for a task list checkbox
* @return An {@link Optional} that contains the start and end index of the found checkbox
*/
export const findCheckBox = (
markdownContent: string,
lineIndex: number
): Optional<[startIndex: number, endIndex: number]> => {
const lines = markdownContent.split('\n')
const lineStartIndex = findStartIndexOfLine(lines, lineIndex)
return Optional.ofNullable(TASK_REGEX.exec(lines[lineIndex])).map(([, beforeCheckbox, oldCheckbox]) => [
lineStartIndex + beforeCheckbox.length,
lineStartIndex + beforeCheckbox.length + oldCheckbox.length
])
}
const findStartIndexOfLine = (lines: string[], wantedLineIndex: number): number => {
return lines
.map((value) => value.length)
.filter((value, index) => index < wantedLineIndex)
.reduce((state, lineLength) => state + lineLength + 1, 0)
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtensionComponentProps } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import { useExtensionEventEmitterHandler } from '../../../components/markdown-renderer/hooks/use-extension-event-emitter'
import { createCheckboxContent } from './create-checkbox-content'
import type { TaskCheckedEventPayload } from './event-emitting-task-list-checkbox'
import { findCheckBox } from './find-check-box'
import { TaskListCheckboxAppExtension } from './task-list-checkbox-app-extension'
import type React from 'react'
/**
* Receives task-checkbox-change events and modify the current editor content.
*/
export const SetCheckboxInCheatsheet: React.FC<CheatsheetExtensionComponentProps> = ({ setContent }) => {
useExtensionEventEmitterHandler(TaskListCheckboxAppExtension.EVENT_NAME, (event: TaskCheckedEventPayload) => {
setContent((previousContent) => {
return findCheckBox(previousContent, event.lineInMarkdown)
.map(
([startIndex, endIndex]) =>
previousContent.slice(0, startIndex) +
createCheckboxContent(event.newCheckedState) +
previousContent.slice(endIndex)
)
.orElse(previousContent)
})
})
return null
}

View file

@ -3,10 +3,16 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useChangeEditorContentCallback } from '../../../components/editor-page/change-content-context/use-change-editor-content-callback'
import type { ContentEdits } from '../../../components/editor-page/editor-pane/tool-bar/formatters/types/changes'
import { useExtensionEventEmitterHandler } from '../../../components/markdown-renderer/hooks/use-extension-event-emitter'
import { store } from '../../../redux'
import { createCheckboxContent } from './create-checkbox-content'
import type { TaskCheckedEventPayload } from './event-emitting-task-list-checkbox'
import { findCheckBox } from './find-check-box'
import { TaskListCheckboxAppExtension } from './task-list-checkbox-app-extension'
import { useSetCheckboxInEditor } from './use-set-checkbox-in-editor'
import type React from 'react'
import { useCallback } from 'react'
/**
* Receives task-checkbox-change events and modify the current editor content.
@ -16,3 +22,45 @@ export const SetCheckboxInEditor: React.FC = () => {
useExtensionEventEmitterHandler(TaskListCheckboxAppExtension.EVENT_NAME, changeCallback)
return null
}
/**
* Provides a callback that changes the state of a checkbox in a given line in the current codemirror instance.
*/
export const useSetCheckboxInEditor = () => {
const changeEditorContent = useChangeEditorContentCallback()
return useCallback(
({ lineInMarkdown, newCheckedState }: TaskCheckedEventPayload): void => {
changeEditorContent?.(({ markdownContent }) => {
const correctedLineIndex = lineInMarkdown + store.getState().noteDetails.frontmatterRendererInfo.lineOffset
const edits = findCheckBox(markdownContent, correctedLineIndex)
.map(([startIndex, endIndex]) => createCheckboxContentEdit(startIndex, endIndex, newCheckedState))
.orElse([])
return [edits, undefined]
})
},
[changeEditorContent]
)
}
/**
* Creates a {@link ContentEdits content edit} for the change of a checkbox at a given position.
*
* @param checkboxStartIndex The start index of the old checkbox code
* @param checkboxEndIndex The end index of the old checkbox code
* @param newCheckboxState The new status of the checkbox
* @return the created {@link ContentEdits edit}
*/
const createCheckboxContentEdit = (
checkboxStartIndex: number,
checkboxEndIndex: number,
newCheckboxState: boolean
): ContentEdits => {
return [
{
from: checkboxStartIndex,
to: checkboxEndIndex,
insert: createCheckboxContent(newCheckboxState)
}
]
}

View file

@ -3,7 +3,9 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import { AppExtension } from '../../base/app-extension'
import { SetCheckboxInCheatsheet } from './set-checkbox-in-cheatsheet'
import { SetCheckboxInEditor } from './set-checkbox-in-editor'
import { TaskListMarkdownExtension } from './task-list-markdown-extension'
import type { EventEmitter2 } from 'eventemitter2'
@ -22,4 +24,8 @@ export class TaskListCheckboxAppExtension extends AppExtension {
buildEditorExtensionComponent(): React.FC {
return SetCheckboxInEditor
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'taskList', cheatsheetExtensionComponent: SetCheckboxInCheatsheet }]
}
}

View file

@ -1,74 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useChangeEditorContentCallback } from '../../../components/editor-page/change-content-context/use-change-editor-content-callback'
import type { ContentEdits } from '../../../components/editor-page/editor-pane/tool-bar/formatters/types/changes'
import { store } from '../../../redux'
import type { TaskCheckedEventPayload } from './event-emitting-task-list-checkbox'
import { Optional } from '@mrdrogdrog/optional'
import { useCallback } from 'react'
const TASK_REGEX = /(\s*(?:[-*+]|\d+[.)]) )(\[[ xX]?])/
/**
* Provides a callback that changes the state of a checkbox in a given line in the current codemirror instance.
*/
export const useSetCheckboxInEditor = () => {
const changeEditorContent = useChangeEditorContentCallback()
return useCallback(
({ lineInMarkdown, checked }: TaskCheckedEventPayload): void => {
changeEditorContent?.(({ markdownContent }) => {
const lines = markdownContent.split('\n')
const correctedLineIndex = lineInMarkdown + store.getState().noteDetails.frontmatterRendererInfo.lineOffset
const lineStartIndex = findStartIndexOfLine(lines, correctedLineIndex)
const edits = Optional.ofNullable(TASK_REGEX.exec(lines[correctedLineIndex]))
.map(([, beforeCheckbox, oldCheckbox]) => {
const checkboxStartIndex = lineStartIndex + beforeCheckbox.length
return createCheckboxContentEdit(checkboxStartIndex, oldCheckbox, checked)
})
.orElse([])
return [edits, undefined]
})
},
[changeEditorContent]
)
}
/**
* Finds the start position of the wanted line index if the given lines would be concat with new-line-characters.
*
* @param lines The lines to search through
* @param wantedLineIndex The index of the line whose start position should be found
* @return the found start position
*/
const findStartIndexOfLine = (lines: string[], wantedLineIndex: number): number => {
return lines
.map((value) => value.length)
.filter((value, index) => index < wantedLineIndex)
.reduce((state, lineLength) => state + lineLength + 1, 0)
}
/**
* Creates a {@link ContentEdits content edit} for the change of a checkbox at a given position.
*
* @param checkboxStartIndex The start index of the checkbox
* @param oldCheckbox The old checkbox that should be replaced
* @param newCheckboxState The new status of the checkbox
* @return the created {@link ContentEdits edit}
*/
const createCheckboxContentEdit = (
checkboxStartIndex: number,
oldCheckbox: string,
newCheckboxState: boolean
): ContentEdits => {
return [
{
from: checkboxStartIndex,
to: checkboxStartIndex + oldCheckbox.length,
insert: `[${newCheckboxState ? 'x' : ' '}]`
}
]
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { AppExtension } from '../../base/app-extension'
import { VegaLiteMarkdownExtension } from './vega-lite-markdown-extension'
@ -14,4 +15,10 @@ export class VegaLiteAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new VegaLiteMarkdownExtension()]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [
{ i18nKey: 'vegaLite', categoryI18nKey: 'charts', readMoreUrl: new URL('https://vega.github.io/vega-lite/') }
]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { Linter } from '../../../components/editor-page/editor-pane/linter/linter'
import { SingleLineRegexLinter } from '../../../components/editor-page/editor-pane/linter/single-line-regex-linter'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
@ -28,4 +29,8 @@ export class VimeoAppExtension extends AppExtension {
)
]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'vimeo', categoryI18nKey: 'embedding', readMoreUrl: new URL('https://vimeo.com/') }]
}
}

View file

@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { Linter } from '../../../components/editor-page/editor-pane/linter/linter'
import { SingleLineRegexLinter } from '../../../components/editor-page/editor-pane/linter/single-line-regex-linter'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
@ -28,4 +29,8 @@ export class YoutubeAppExtension extends AppExtension {
)
]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {
return [{ i18nKey: 'youtube', categoryI18nKey: 'embedding', readMoreUrl: new URL('https://youtube.com/') }]
}
}