mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-29 10:24:30 -05:00
added markdown export (#627)
This commit is contained in:
parent
4984008aff
commit
9f7a106834
5 changed files with 79 additions and 9 deletions
48
cypress/integration/export.spec.ts
Normal file
48
cypress/integration/export.spec.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
const testTitle = 'testContent'
|
||||||
|
const testContent = `---\ntitle: ${testTitle}\n---\nThis is some test content`
|
||||||
|
|
||||||
|
describe('Export', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/n/test')
|
||||||
|
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
|
||||||
|
.should('exist')
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type('{ctrl}a', { force: true })
|
||||||
|
.type('{backspace}')
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type(testContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Markdown', () => {
|
||||||
|
cy.get('#editor-menu-export')
|
||||||
|
.click()
|
||||||
|
cy.get('a.dropdown-item > i.fa-file-text')
|
||||||
|
.click()
|
||||||
|
cy.get('a[download]')
|
||||||
|
.then((anchor) => (
|
||||||
|
new Cypress.Promise((resolve: any, _: any) => {
|
||||||
|
// Use XHR to get the blob that corresponds to the object URL.
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', anchor.prop('href'), true);
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
|
||||||
|
// Once loaded, use FileReader to get the string back from the blob.
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const blob = xhr.response;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
// Once we have a string, resolve the promise to let
|
||||||
|
// the Cypress chain continue, e.g. to assert on the result.
|
||||||
|
resolve(reader.result);
|
||||||
|
};
|
||||||
|
reader.readAsText(blob);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
})
|
||||||
|
))
|
||||||
|
// Now the regular Cypress assertions should work.
|
||||||
|
.should('equal', testContent);
|
||||||
|
})
|
||||||
|
})
|
|
@ -5,5 +5,5 @@ export const download = (data: BlobPart, fileName: string, mimeType: string): vo
|
||||||
helperElement.download = fileName
|
helperElement.download = fileName
|
||||||
document.body.appendChild(helperElement)
|
document.body.appendChild(helperElement)
|
||||||
helperElement.click()
|
helperElement.click()
|
||||||
helperElement.remove()
|
setTimeout(() => helperElement.remove(), 2000)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const DocumentBar: React.FC<DocumentBarProps> = ({ title, noteContent })
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto navbar-nav">
|
<div className="ml-auto navbar-nav">
|
||||||
<ImportMenu/>
|
<ImportMenu/>
|
||||||
<ExportMenu/>
|
<ExportMenu title={title} noteContent={noteContent}/>
|
||||||
<EditorMenu noteTitle={title}/>
|
<EditorMenu noteTitle={title}/>
|
||||||
<ConnectionIndicator/>
|
<ConnectionIndicator/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,8 +3,14 @@ import { Dropdown } from 'react-bootstrap'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import links from '../../../../links.json'
|
import links from '../../../../links.json'
|
||||||
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
|
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
|
||||||
|
import { MarkdownExportDropdownItem } from './export/markdown'
|
||||||
|
|
||||||
const ExportMenu: React.FC = () => {
|
export interface ExportMenuProps {
|
||||||
|
title: string
|
||||||
|
noteContent: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ExportMenu: React.FC<ExportMenuProps> = ({ title, noteContent }) => {
|
||||||
useTranslation()
|
useTranslation()
|
||||||
return (
|
return (
|
||||||
<Dropdown className='small mx-1' alignRight={true}>
|
<Dropdown className='small mx-1' alignRight={true}>
|
||||||
|
@ -34,10 +40,10 @@ const ExportMenu: React.FC = () => {
|
||||||
<Dropdown.Header>
|
<Dropdown.Header>
|
||||||
<Trans i18nKey='editor.documentBar.download'/>
|
<Trans i18nKey='editor.documentBar.download'/>
|
||||||
</Dropdown.Header>
|
</Dropdown.Header>
|
||||||
<Dropdown.Item className='small'>
|
<MarkdownExportDropdownItem
|
||||||
<ForkAwesomeIcon icon='file-text' className={'mx-2'}/>
|
title={title}
|
||||||
Markdown
|
noteContent={noteContent}
|
||||||
</Dropdown.Item>
|
/>
|
||||||
<Dropdown.Item className='small'>
|
<Dropdown.Item className='small'>
|
||||||
<ForkAwesomeIcon icon='file-code-o' className={'mx-2'}/>
|
<ForkAwesomeIcon icon='file-code-o' className={'mx-2'}/>
|
||||||
HTML
|
HTML
|
||||||
|
@ -61,5 +67,3 @@ const ExportMenu: React.FC = () => {
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ExportMenu }
|
|
||||||
|
|
18
src/components/editor/document-bar/menus/export/markdown.tsx
Normal file
18
src/components/editor/document-bar/menus/export/markdown.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { Dropdown } from 'react-bootstrap'
|
||||||
|
import { download } from '../../../../common/download/download'
|
||||||
|
import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon'
|
||||||
|
|
||||||
|
export interface MarkdownExportDropdownItemProps {
|
||||||
|
title: string
|
||||||
|
noteContent: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MarkdownExportDropdownItem: React.FC<MarkdownExportDropdownItemProps> = ({ title, noteContent }) => {
|
||||||
|
return (
|
||||||
|
<Dropdown.Item className='small' onClick={() => download(noteContent, `${title}.md`, 'text/markdown')}>
|
||||||
|
<ForkAwesomeIcon icon='file-text' className={'mx-2'}/>
|
||||||
|
Markdown
|
||||||
|
</Dropdown.Item>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue