Skip to content

Commit

Permalink
Merge pull request #15393 from ckeditor/ck/2321-paste-from-markdown
Browse files Browse the repository at this point in the history
Feature (markdown-gfm): Added an experimental support for pasting from markdown. Closes #2321.
  • Loading branch information
niegowski authored Dec 5, 2023
2 parents 3e581ba + 663babb commit 767e681
Show file tree
Hide file tree
Showing 17 changed files with 799 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Feel free to open a [new feature request](https://github.com/ckeditor/ckeditor5/
## Related features

CKEditor 5 supports a wider range of paste features, including:
* {@link features/paste-markdown Paste Markdown} – Paste Markdown formatted content straight into the editor.
* {@link features/paste-from-office Paste from Office} – Paste content from Microsoft Word and maintain the original structure and formatting.
* {@link features/paste-from-google-docs Paste from Google Docs} – Paste content from Google Docs, maintaining the original formatting and structure.
* {@link features/import-word Import from Word} – Convert Word files directly into HTML content.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CodeBlock } from '@ckeditor/ckeditor5-code-block';
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
import { CKBox, CKBoxImageEdit } from '@ckeditor/ckeditor5-ckbox';
import { HorizontalLine } from '@ckeditor/ckeditor5-horizontal-line';
import { ImageUpload, ImageInsert, PictureEditing } from '@ckeditor/ckeditor5-image';
import { ImageUpload, ImageInsert, PictureEditing, AutoImage } from '@ckeditor/ckeditor5-image';
import { TodoList } from '@ckeditor/ckeditor5-list';
import { SourceEditing } from '@ckeditor/ckeditor5-source-editing';

Expand All @@ -23,8 +23,8 @@ import { Markdown } from '@ckeditor/ckeditor5-markdown-gfm';
ClassicEditor
.create( document.querySelector( '#snippet-markdown' ), {
plugins: [
ArticlePluginSet, SourceEditing, CKBox, CKBoxImageEdit, ImageInsert, ImageUpload, PictureEditing, CloudServices, Markdown,
Code, CodeBlock, TodoList, Strikethrough, HorizontalLine
ArticlePluginSet, SourceEditing, CKBox, CKBoxImageEdit, ImageInsert, ImageUpload, PictureEditing, AutoImage,
CloudServices, Markdown, Code, CodeBlock, TodoList, Strikethrough, HorizontalLine
],
toolbar: {
items: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script src="https://cdn.ckbox.io/ckbox/latest/ckbox.js"></script>
<textarea id="snippet-paste-from-markdown">

&lt;h2&gt;Markdown output 🛫&lt;/h2&gt;

</textarea>

<p>Output:</p>

<pre><code id="snippet-paste-from-markdown-output"></code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/* globals console, window, document, setTimeout */

import { Code, Strikethrough, Underline } from '@ckeditor/ckeditor5-basic-styles';
import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
import { CodeBlock } from '@ckeditor/ckeditor5-code-block';
import { HorizontalLine } from '@ckeditor/ckeditor5-horizontal-line';
import { SourceEditing } from '@ckeditor/ckeditor5-source-editing';
import { DocumentList, TodoDocumentList, AdjacentListsSupport } from '@ckeditor/ckeditor5-list';
import { Markdown, PasteFromMarkdownExperimental } from '@ckeditor/ckeditor5-markdown-gfm';
import { CKBox, CKBoxImageEdit } from '@ckeditor/ckeditor5-ckbox';
import { PictureEditing, ImageInsert, ImageResize, AutoImage } from '@ckeditor/ckeditor5-image';
import { LinkImage } from '@ckeditor/ckeditor5-link';
import { Font } from '@ckeditor/ckeditor5-font';

// Umberto combines all `packages/*/docs` into the `docs/` directory. The import path must be valid after merging all directories.
import ClassicEditor from '../build-classic';

const plugins = ClassicEditor.builtinPlugins
// Remove the `List` plugin as in a single demo we want to use the Document list feature.
.filter( pluginConstructor => {
if ( pluginConstructor.pluginName === 'List' ) {
return false;
}

return true;
} )
// Then, add Markdown-specific features.
.concat( [
SourceEditing, Code, Strikethrough, Underline, Markdown, CodeBlock, HorizontalLine, DocumentList, TodoDocumentList,
AdjacentListsSupport, PasteFromMarkdownExperimental, CKBox, CKBoxImageEdit,
PictureEditing, ImageInsert, ImageResize, AutoImage, LinkImage, Font
] );

ClassicEditor
.create( document.querySelector( '#snippet-paste-from-markdown' ), {
plugins,
toolbar: {
items: [
'undo', 'redo', '|', 'sourceEditing', '|', 'heading',
'|', 'bold', 'italic', 'underline', 'strikethrough', 'code',
'-', 'link', 'insertImage', 'insertTable', 'mediaEmbed', 'blockQuote', 'codeBlock', 'horizontalLine',
'|', 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent'
],
shouldNotGroupWhenFull: true
},
cloudServices: CS_CONFIG,
image: {
toolbar: [
'imageStyle:inline',
'imageStyle:block',
'imageStyle:side',
'|',
'toggleImageCaption',
'imageTextAlternative',
'|',
'ckboxImageEdit'
]
},
codeBlock: {
languages: [
{ language: 'css', label: 'CSS' },
{ language: 'html', label: 'HTML' },
{ language: 'javascript', label: 'JavaScript' },
{ language: 'php', label: 'PHP' }
]
},
ui: {
viewportOffset: {
top: window.getViewportTopOffsetConfig()
}
}
} )
.then( editor => {
window.editor = editor;

const outputElement = document.querySelector( '#snippet-paste-from-markdown-output' );

editor.model.document.on( 'change', () => {
outputElement.innerText = editor.getData();
} );

// Set the initial data with delay so hightlight.js doesn't catch it.
setTimeout( () => {
outputElement.innerText = editor.getData();
}, 500 );
} )
.catch( err => {
console.error( err.stack );
} );
72 changes: 72 additions & 0 deletions packages/ckeditor5-markdown-gfm/docs/assets/markdown.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Headings of various kinds
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading


## Various ways to create horizontal rules

___

---

***

## Basic formatting

**This is bold text**

__This is bold text__

*This is italic text*

_This is italic text_

~~Strikethrough~~


## Block quotes

> Basic block quotes


## Lists

Unordered lists

+ A list is created by starting a line with `+`, `-`, or `*`.
+ Indenting an item by two spaces will turn it into a sub-list.
+ That can be nested further:
+ Like this!

Ordered lists

1. You can create ordered lists...
2. ...with sequential numbers...
3. ...incrementing by 1.


1. Or you can just use 1...
1. ...for all the items.

## Code formatting

This covers either inline `code`...

```
Or a code block.
```

## Tables

| Header | Header |
| ------ | ----------- |
| Tables are tricky | And need some special care |

## Links
[CKEditor 5 main site](https://ckeditor.com/)

## Images

![CKEditor 5](https://user-images.githubusercontent.com/1099479/179190754-f4aaf2b3-21cc-49c4-a454-8de4a00cc70e.jpg)
4 changes: 3 additions & 1 deletion packages/ckeditor5-markdown-gfm/docs/features/markdown.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Markdown output
meta-title: Markdown output | CKEditor 5 Documentation
meta-description: The Markdown plugin lets you switch the default CKEditor 5 output from HTML to Markdown.
category: features
---

Expand Down Expand Up @@ -41,7 +42,7 @@ editor.setData( 'This is **bold**.' );

The data processor outputs the GFM Markdown syntax. "GFM" stands for "GitHub Flavored Markdown" &ndash; a Markdown dialect used by [GitHub](https://github.com). Markdown lacks any formal specification (although the [CommonMark](https://commonmark.org/) initiative aims to close this gap) and has many dialects, often incompatible with one another.

When converting the output produced by this data processor, make sure to use a compatible Markdown-to-HTML converter (for example the [marked](https://www.npmjs.com/package/marked) library).
When converting the output produced by this data processor, make sure to use a compatible Markdown-to-HTML converter (for example, the [marked](https://www.npmjs.com/package/marked) library).

<info-box info>
While the CKEditor&nbsp;5 architecture supports changing the data format, in most scenarios we do recommend sticking to the default format which is HTML (supported by the {@link module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor}). HTML remains [the best standard for rich-text data](https://medium.com/content-uneditable/a-standard-for-rich-text-data-4b3a507af552).
Expand Down Expand Up @@ -116,6 +117,7 @@ Some other ways to output the edited content include:
* {@link features/export-word Export to Word} &ndash; Generate editable `.docx` files out of your editor-created content.
* {@link features/export-pdf Export to PDF} &ndash; Generate portable PDF files out of your editor-created content.
* {@link features/autoformat Autoformatting} &ndash; Use Markdown syntax shortcodes to automatically format your content as you type!
* {@link features/paste-markdown Paste Markdown} &ndash; Paste Markdown formatted content straight into the editor.

## Contribute

Expand Down
88 changes: 88 additions & 0 deletions packages/ckeditor5-markdown-gfm/docs/features/paste-markdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
menu-title: Paste Markdown
meta-title: Paste Markdown | CKEditor 5 Documentation
meta-description: The paste Markdown feature lets users paste Markdown-formatted content straight into CKEditor 5.
category: features-pasting
order: 40
modified_at: 2023-11-24
---

# Paste Markdown

The paste Markdown feature lets users paste Markdown-formatted content straight into the editor. It will be then converted into rich text on the fly.

<info-box warning>
This feature is still in the experimental phase. See the [known issues](#known-issues) section to learn more.
</info-box>

## Demo

Simply paste some Markdown-formatted content into the demo editor below and see it turn into rich text on the fly. You can copy [this document](%BASE_PATH%/assets/markdown.txt) for convenience.

{@snippet features/paste-from-markdown}

<info-box info>
This demo only presents a limited set of features. Visit the {@link examples/builds/full-featured-editor feature-rich editor example} to see more in action.
</info-box>

## Installation

<info-box info>
This feature is not available in any of the {@link installation/getting-started/predefined-builds predefined builds}.
</info-box>

To enable this data processor in your editor, install the [`@ckeditor/ckeditor5-markdown-gfm`](https://www.npmjs.com/package/@ckeditor/ckeditor5-markdown-gfm) package:

```
npm install --save @ckeditor/ckeditor5-markdown-gfm
```

Then add the {@link module:markdown-gfm/pastefrommarkdownexperimental~PasteFromMarkdownExperimental} plugin to the editor configuration:

```js
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';

import { Bold, Italic } from '@ckeditor/ckeditor5-basic-styles';
import { Essentials } from '@ckeditor/ckeditor5-essentials';
// More imports.
// ...

import { PasteFromMarkdownExperimental } from '@ckeditor/ckeditor5-markdown-gfm';

ClassicEditor
.create( document.querySelector( '#snippet-markdown' ), {
plugins: [
PasteFromMarkdownExperimental,
Essentials,
Bold,
Italic,
// More plugins.
// ...
],
// More of editor's config.
// ...
} )
.then( /* ... */ )
.catch( /* ... */ );

```

<info-box info>
Read more about {@link installation/plugins/installing-plugins installing plugins}.
</info-box>

## Known issues

While the Paste Markdown feature is already stable enough to use it, please remember it still needs some more testing. We are now mostly concentrating on testing it in connection with other tools and plugins. If you have any observations, suggestions or other piece of information you want to share with us, feel free to put them in [this GitHub issue](https://github.com/ckeditor/ckeditor5/issues/2321).

## Related features

CKEditor&nbsp;5 supports a wider range of paste features, including:
* {@link features/paste-from-office Paste from Office} &ndash; Paste content from Microsoft Word and maintain the original structure and formatting.
* {@link features/paste-from-google-docs Paste from Google Docs} &ndash; Paste content from Google Docs, maintaining the original formatting and structure.
* {@link features/paste-plain-text Paste plain text} &ndash; Paste text without formatting that will inherit the style of the content it was pasted into.
* {@link features/autoformat Autoformatting} &ndash; Format your content on the go with Markdown-like shortcodes.

## Contribute

The source code of the feature is available on GitHub at [https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-markdown-gfm](https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-markdown-gfm)
14 changes: 14 additions & 0 deletions packages/ckeditor5-markdown-gfm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,29 @@
"turndown-plugin-gfm": "1.0.2"
},
"devDependencies": {
"@ckeditor/ckeditor5-autoformat":"40.1.0",
"@ckeditor/ckeditor5-basic-styles": "40.1.0",
"@ckeditor/ckeditor5-block-quote": "40.1.0",
"@ckeditor/ckeditor5-clipboard": "40.1.0",
"@ckeditor/ckeditor5-code-block": "40.1.0",
"@ckeditor/ckeditor5-core": "40.1.0",
"@ckeditor/ckeditor5-dev-utils": "^39.0.0",
"@ckeditor/ckeditor5-editor-classic": "40.1.0",
"@ckeditor/ckeditor5-engine": "40.1.0",
"@ckeditor/ckeditor5-essentials": "40.1.0",
"@ckeditor/ckeditor5-font": "40.1.0",
"@ckeditor/ckeditor5-heading":"40.1.0",
"@ckeditor/ckeditor5-horizontal-line": "40.1.0",
"@ckeditor/ckeditor5-image": "40.1.0",
"@ckeditor/ckeditor5-indent":"40.1.0",
"@ckeditor/ckeditor5-link": "40.1.0",
"@ckeditor/ckeditor5-list": "40.1.0",
"@ckeditor/ckeditor5-media-embed":"40.1.0",
"@ckeditor/ckeditor5-paragraph": "40.1.0",
"@ckeditor/ckeditor5-table": "40.1.0",
"@ckeditor/ckeditor5-theme-lark": "40.1.0",
"@ckeditor/ckeditor5-undo": "40.1.0",
"@ckeditor/ckeditor5-utils": "40.1.0",
"@types/marked": "^4.0.8",
"typescript": "^4.8.4",
"webpack": "^5.58.1",
Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-markdown-gfm/src/augmentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

import type { Markdown } from './index';
import type { Markdown, PasteFromMarkdownExperimental } from './index';

declare module '@ckeditor/ckeditor5-core' {
interface PluginsMap {
[ Markdown.pluginName ]: Markdown;
[ PasteFromMarkdownExperimental.pluginName ]: PasteFromMarkdownExperimental;
}
}
1 change: 1 addition & 0 deletions packages/ckeditor5-markdown-gfm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
*/

export { default as Markdown } from './markdown';
export { default as PasteFromMarkdownExperimental } from './pastefrommarkdownexperimental';

import './augmentation';
Loading

0 comments on commit 767e681

Please sign in to comment.