feat: set url hash when clicking a link

Implements #6474

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares
2026-07-31 23:17:56 +02:00
committed by Philip Molares
parent 41cd58e72e
commit ab3c6ffd01
4 changed files with 26 additions and 11 deletions
@@ -7,12 +7,24 @@ import { mockI18n } from '../../../test-utils/mock-i18n'
import { TableOfContents } from './table-of-contents' import { TableOfContents } from './table-of-contents'
import type { TocAst } from '@hedgedoc/markdown-it-plugins' import type { TocAst } from '@hedgedoc/markdown-it-plugins'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import { RendererToEditorCommunicatorContextProvider } from '../render-context/renderer-to-editor-communicator-context-provider'
import { BaseUrlContextProvider } from '../../common/base-url/base-url-context-provider'
import * as UseSingleStringUrlParameterMock from '../../../hooks/common/use-single-string-url-parameter'
jest.mock('../../../hooks/common/use-single-string-url-parameter')
describe('Table of contents', () => { describe('Table of contents', () => {
beforeAll(async () => { beforeAll(async () => {
await mockI18n() await mockI18n()
jest.spyOn(UseSingleStringUrlParameterMock, 'useSingleStringUrlParameter').mockReturnValue('test-uuid')
}) })
const baseUrls = {
editor: 'http://example.com',
renderer: 'http://example.com',
internalApiUrl: 'http://example.com'
}
const level4Ast: TocAst = { const level4Ast: TocAst = {
name: 'Level 4', name: 'Level 4',
level: 4, level: 4,
@@ -41,14 +53,22 @@ describe('Table of contents', () => {
it('renders correctly', () => { it('renders correctly', () => {
const view = render( const view = render(
<TableOfContents ast={level0Ast} className={'customClassName'} baseUrl={'https://example.org'} /> <BaseUrlContextProvider baseUrls={baseUrls}>
<RendererToEditorCommunicatorContextProvider>
<TableOfContents ast={level0Ast} className={'customClassName'} baseUrl={'https://example.org'} />
</RendererToEditorCommunicatorContextProvider>
</BaseUrlContextProvider>
) )
expect(view.container).toMatchSnapshot() expect(view.container).toMatchSnapshot()
}) })
it('renders only in requested max depth', () => { it('renders only in requested max depth', () => {
const view = render( const view = render(
<TableOfContents ast={level0Ast} maxDepth={2} className={'customClassName'} baseUrl={'https://example.org'} /> <BaseUrlContextProvider baseUrls={baseUrls}>
<RendererToEditorCommunicatorContextProvider>
<TableOfContents ast={level0Ast} maxDepth={2} className={'customClassName'} baseUrl={'https://example.org'} />
</RendererToEditorCommunicatorContextProvider>
</BaseUrlContextProvider>
) )
expect(view.container).toMatchSnapshot() expect(view.container).toMatchSnapshot()
}) })
@@ -11,12 +11,8 @@ import { DocumentMarkdownRenderer } from './renderers/document/document-markdown
import { SimpleMarkdownRenderer } from './renderers/simple/simple-markdown-renderer' import { SimpleMarkdownRenderer } from './renderers/simple/simple-markdown-renderer'
import { SlideshowMarkdownRenderer } from './renderers/slideshow/slideshow-markdown-renderer' import { SlideshowMarkdownRenderer } from './renderers/slideshow/slideshow-markdown-renderer'
import { useRendererReceiveHandler } from './window-post-message-communicator/hooks/use-renderer-receive-handler' import { useRendererReceiveHandler } from './window-post-message-communicator/hooks/use-renderer-receive-handler'
import type { import type { BaseConfiguration } from './window-post-message-communicator/rendering-message'
BaseConfiguration} from './window-post-message-communicator/rendering-message'; import { CommunicationMessageType, RendererType } from './window-post-message-communicator/rendering-message'
import {
CommunicationMessageType,
RendererType
} from './window-post-message-communicator/rendering-message'
import { countWords } from './word-counter' import { countWords } from './word-counter'
import type { RevealOptions } from 'reveal.js' import type { RevealOptions } from 'reveal.js'
import { EventEmitter2 } from 'eventemitter2' import { EventEmitter2 } from 'eventemitter2'
@@ -13,7 +13,6 @@ type EditorMessageHandler<MESSAGE_TYPE extends RendererToEditorMessageType> = Ha
MESSAGE_TYPE MESSAGE_TYPE
> | null > | null
/** /**
* Sets the handler for the given message type in the current editor to renderer communicator. * Sets the handler for the given message type in the current editor to renderer communicator.
* *
@@ -22,7 +21,7 @@ type EditorMessageHandler<MESSAGE_TYPE extends RendererToEditorMessageType> = Ha
*/ */
export const useEditorReceiveHandler = <MESSAGE_TYPE extends RendererToEditorMessageType>( export const useEditorReceiveHandler = <MESSAGE_TYPE extends RendererToEditorMessageType>(
messageType: MESSAGE_TYPE, messageType: MESSAGE_TYPE,
handler: EditorMessageHandler<MESSAGE_TYPE>, handler: EditorMessageHandler<MESSAGE_TYPE>
): void => { ): void => {
const editorToRendererCommunicator = useEditorToRendererCommunicator() const editorToRendererCommunicator = useEditorToRendererCommunicator()
useEffect(() => { useEffect(() => {
@@ -21,7 +21,7 @@ type RendererMessageHandler<MESSAGE_TYPE extends EditorToRendererMessageType> =
*/ */
export const useRendererReceiveHandler = <MESSAGE_TYPE extends EditorToRendererMessageType>( export const useRendererReceiveHandler = <MESSAGE_TYPE extends EditorToRendererMessageType>(
messageType: MESSAGE_TYPE, messageType: MESSAGE_TYPE,
handler: RendererMessageHandler<MESSAGE_TYPE>, handler: RendererMessageHandler<MESSAGE_TYPE>
): void => { ): void => {
const rendererToEditorCommunicator = useRendererToEditorCommunicator() const rendererToEditorCommunicator = useRendererToEditorCommunicator()
useEffect(() => { useEffect(() => {