fix: Move content into to frontend directory

Doing this BEFORE the merge prevents a lot of merge conflicts.

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2022-11-11 11:16:18 +01:00
parent 4e18ce38f3
commit 762a0a850e
No known key found for this signature in database
GPG key ID: B97799103358209B
1051 changed files with 0 additions and 35 deletions

View file

@ -0,0 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`YoutubeFrame renders a click shield 1`] = `
<div>
<span>
This is a click shield for
<span
class="embed-responsive embed-responsive-16by9"
>
<iframe
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
class="embed-responsive-item"
src="https://www.youtube-nocookie.com/embed/validYoutubeId?autoplay=1"
title="youtube video of validYoutubeId"
/>
</span>
</span>
</div>
`;

View file

@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`youtube markdown extension doesn't render invalid youtube ids in short code syntax 1`] = `
<div>
<p>
{%youtube a %}
</p>
</div>
`;
exports[`youtube markdown extension renders legacy youtube syntax 1`] = `
<div>
<p>
<span>
this is a mock for the youtube frame with id
XDnhKh5V5XQ
</span>
</p>
</div>
`;
exports[`youtube markdown extension renders plain youtube URLs 1`] = `
<div>
<p>
<span>
this is a mock for the youtube frame with id
XDnhKh5V5XQ
</span>
</p>
</div>
`;

View file

@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MarkdownIt from 'markdown-it'
import { replaceLegacyYoutubeShortCodeMarkdownItPlugin } from './replace-legacy-youtube-short-code'
describe('Replace legacy youtube short codes', () => {
let markdownIt: MarkdownIt
beforeEach(() => {
markdownIt = new MarkdownIt('default', {
html: false,
breaks: true,
langPrefix: '',
typographer: true
})
markdownIt.use(replaceLegacyYoutubeShortCodeMarkdownItPlugin)
})
it('detects a valid legacy youtube short code', () => {
expect(markdownIt.renderInline('{%youtube 12312312312 %}')).toBe('<app-youtube id="12312312312"></app-youtube>')
})
it("won't detect an empty string", () => {
const code = '{%youtube %}'
expect(markdownIt.renderInline(code)).toBe(code)
})
it("won't detect an invalid(too short) youtube id", () => {
const code = '{%youtube 1 %}'
expect(markdownIt.renderInline(code)).toBe(code)
})
it("won't detect an invalid(invalid characters) youtube id", () => {
const code = '{%youtube /!#/ %}'
expect(markdownIt.renderInline(code)).toBe(code)
})
it("won't detect an invalid(too long) youtube id", () => {
const code = '{%youtube 111111111111111111111111111111111 %}'
expect(markdownIt.renderInline(code)).toBe(code)
})
})

View file

@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { YoutubeMarkdownExtension } from './youtube-markdown-extension'
import markdownItRegex from 'markdown-it-regex'
import type MarkdownIt from 'markdown-it'
import type { RegexOptions } from '../../../external-types/markdown-it-regex/interface'
export const legacyYouTubeRegex = /^{%youtube\s+([\w-]{11})\s*%}$/
/**
* Configure the given {@link MarkdownIt} to render legacy hedgedoc 1 youtube short codes as embeddings.
*
* @param markdownIt The {@link MarkdownIt} to configure
*/
export const replaceLegacyYoutubeShortCodeMarkdownItPlugin: MarkdownIt.PluginSimple = (markdownIt: MarkdownIt): void =>
markdownItRegex(markdownIt, {
name: 'legacy-youtube-short-code',
regex: legacyYouTubeRegex,
replace: (match) => {
// ESLint wants to collapse this tag, but then the tag won't be valid html anymore.
// noinspection CheckTagEmptyBody
return `<${YoutubeMarkdownExtension.tagName} id="${match}"></${YoutubeMarkdownExtension.tagName}>`
}
} as RegexOptions)

View file

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { replaceYouTubeLinkMarkdownItPlugin } from './replace-youtube-link'
import MarkdownIt from 'markdown-it'
describe('Replace youtube link', () => {
let markdownIt: MarkdownIt
beforeEach(() => {
markdownIt = new MarkdownIt('default', {
html: false,
breaks: true,
langPrefix: '',
typographer: true
})
markdownIt.use(replaceYouTubeLinkMarkdownItPlugin)
})
;['http://', 'https://', ''].forEach((protocol) => {
;['www.', ''].forEach((subdomain) => {
;['youtube.com', 'youtube-nocookie.com'].forEach((domain) => {
const origin = `${protocol}${subdomain}${domain}/`
describe(origin, () => {
const validUrl = `${origin}?v=12312312312`
it(`can detect a correct youtube video url`, () => {
expect(markdownIt.renderInline(validUrl)).toBe('<app-youtube id="12312312312"></app-youtube>')
})
it("won't detect an URL without video id", () => {
expect(markdownIt.renderInline(origin)).toBe(origin)
})
it("won't detect an invalid(too short) youtube id", () => {
const invalidUrl = `${origin}?v=1`
expect(markdownIt.renderInline(invalidUrl)).toBe(invalidUrl)
})
it("won't detect an invalid(invalid characters) youtube id", () => {
const invalidUrl = `${origin}?v= /!#/`
expect(markdownIt.renderInline(invalidUrl)).toBe(invalidUrl)
})
it("won't detect an invalid(too long) youtube id", () => {
const invalidUrl = `${origin}?v=111111111111111111111111111111111`
expect(markdownIt.renderInline(invalidUrl)).toBe(invalidUrl)
})
})
})
})
})
})

View file

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { YoutubeMarkdownExtension } from './youtube-markdown-extension'
import markdownItRegex from 'markdown-it-regex'
import type MarkdownIt from 'markdown-it'
import type { RegexOptions } from '../../../external-types/markdown-it-regex/interface'
const linkRegex =
/^(?:https?:\/\/)?(?:www.)?(?:youtube(?:-nocookie)?\.com\/(?:[^\\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([\w-]{11})(?:[?&#].*)?$/i
/**
* Replacer for youtube links.
*/
export const replaceYouTubeLinkMarkdownItPlugin: MarkdownIt.PluginSimple = (markdownIt: MarkdownIt) =>
markdownItRegex(markdownIt, {
name: 'youtube-link',
regex: linkRegex,
replace: (match) => {
// ESLint wants to collapse this tag, but then the tag won't be valid html anymore.
// noinspection CheckTagEmptyBody
return `<${YoutubeMarkdownExtension.tagName} id="${match}"></${YoutubeMarkdownExtension.tagName}>`
}
} as RegexOptions)

View file

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { AppExtension } from '../../base/app-extension'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { YoutubeMarkdownExtension } from './youtube-markdown-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 { legacyYouTubeRegex } from './replace-legacy-youtube-short-code'
import { t } from 'i18next'
/**
* Adds YouTube video embeddings to the markdown renderer.
*/
export class YoutubeAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new YoutubeMarkdownExtension()]
}
public buildCodeMirrorLinter(): Linter[] {
return [
new SingleLineRegexLinter(
legacyYouTubeRegex,
t('editor.linter.shortcode', { shortcode: 'YouTube' }),
(match: string) => `https://www.youtube.com/watch?v=${match}`
)
]
}
}

View file

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { render } from '@testing-library/react'
import { YouTubeFrame } from './youtube-frame'
import React from 'react'
import * as ClickShieldModule from '../../../components/markdown-renderer/replace-components/click-shield/click-shield'
import type { ClickShieldProps } from '../../../components/markdown-renderer/replace-components/click-shield/click-shield'
jest.mock('../../../components/markdown-renderer/replace-components/click-shield/click-shield')
describe('YoutubeFrame', () => {
beforeEach(() => {
jest.spyOn(ClickShieldModule, 'ClickShield').mockImplementation((({ children }) => {
return <span>This is a click shield for {children}</span>
}) as React.FC<ClickShieldProps>)
})
it('renders a click shield', () => {
const view = render(<YouTubeFrame id={'validYoutubeId'} />)
expect(view.container).toMatchSnapshot()
})
})

View file

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React from 'react'
import { ClickShield } from '../../../components/markdown-renderer/replace-components/click-shield/click-shield'
import type { IdProps } from '../../../components/markdown-renderer/replace-components/custom-tag-with-id-component-replacer'
/**
* Renders a video player embedding for https://youtube.com
*
* @param id The id from the youtube video url
*/
export const YouTubeFrame: React.FC<IdProps> = ({ id }) => {
return (
<ClickShield
hoverIcon={'youtube-play'}
targetDescription={'YouTube'}
fallbackPreviewImageUrl={`https://i.ytimg.com/vi/${id}/maxresdefault.jpg`}
fallbackBackgroundColor={'#ff0000'}
data-cypress-id={'click-shield-youtube'}>
<span className={'embed-responsive embed-responsive-16by9'}>
<iframe
className='embed-responsive-item'
title={`youtube video of ${id}`}
src={`https://www.youtube-nocookie.com/embed/${id}?autoplay=1`}
allow='accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'
/>
</span>
</ClickShield>
)
}

View file

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { YoutubeMarkdownExtension } from './youtube-markdown-extension'
import { render } from '@testing-library/react'
import * as YouTubeFrameModule from './youtube-frame'
import React from 'react'
import { mockI18n } from '../../../components/markdown-renderer/test-utils/mock-i18n'
import { TestMarkdownRenderer } from '../../../components/markdown-renderer/test-utils/test-markdown-renderer'
import type { IdProps } from '../../../components/markdown-renderer/replace-components/custom-tag-with-id-component-replacer'
jest.mock('./youtube-frame')
describe('youtube markdown extension', () => {
beforeAll(async () => {
jest
.spyOn(YouTubeFrameModule, 'YouTubeFrame')
.mockImplementation((({ id }) => (
<span>this is a mock for the youtube frame with id {id}</span>
)) as React.FC<IdProps>)
await mockI18n()
})
afterAll(() => {
jest.resetAllMocks()
jest.resetModules()
})
it('renders plain youtube URLs', () => {
const view = render(
<TestMarkdownRenderer
extensions={[new YoutubeMarkdownExtension()]}
content={'https://www.youtube.com/watch?v=XDnhKh5V5XQ'}
/>
)
expect(view.container).toMatchSnapshot()
})
it('renders legacy youtube syntax', () => {
const view = render(
<TestMarkdownRenderer extensions={[new YoutubeMarkdownExtension()]} content={'{%youtube XDnhKh5V5XQ %}'} />
)
expect(view.container).toMatchSnapshot()
})
it("doesn't render invalid youtube ids in short code syntax", () => {
const view = render(
<TestMarkdownRenderer extensions={[new YoutubeMarkdownExtension()]} content={'{%youtube a %}'} />
)
expect(view.container).toMatchSnapshot()
})
})

View file

@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { replaceYouTubeLinkMarkdownItPlugin } from './replace-youtube-link'
import { replaceLegacyYoutubeShortCodeMarkdownItPlugin } from './replace-legacy-youtube-short-code'
import type MarkdownIt from 'markdown-it'
import { YouTubeFrame } from './youtube-frame'
import { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import { CustomTagWithIdComponentReplacer } from '../../../components/markdown-renderer/replace-components/custom-tag-with-id-component-replacer'
import type { ComponentReplacer } from '../../../components/markdown-renderer/replace-components/component-replacer'
/**
* Adds YouTube video embeddings using link detection and the legacy YouTube short code syntax.
*/
export class YoutubeMarkdownExtension extends MarkdownRendererExtension {
public static readonly tagName = 'app-youtube'
public configureMarkdownIt(markdownIt: MarkdownIt): void {
replaceYouTubeLinkMarkdownItPlugin(markdownIt)
replaceLegacyYoutubeShortCodeMarkdownItPlugin(markdownIt)
}
public buildReplacers(): ComponentReplacer[] {
return [new CustomTagWithIdComponentReplacer(YouTubeFrame, YoutubeMarkdownExtension.tagName)]
}
public buildTagNameAllowList(): string[] {
return [YoutubeMarkdownExtension.tagName]
}
}