diff --git a/__tests__/clipboard.spec.js b/__tests__/clipboard.spec.js
new file mode 100644
index 0000000..496d3c2
--- /dev/null
+++ b/__tests__/clipboard.spec.js
@@ -0,0 +1,85 @@
+import { Editor } from "@tiptap/core";
+import StarterKit from "@tiptap/starter-kit";
+import { Markdown } from "../src";
+import { clipboardEvent } from "./utils/dom";
+
+
+describe('clipboard', () => {
+ describe('paste', () => {
+ test('transform', () => {
+ const editor = new Editor({
+ extensions: [
+ StarterKit,
+ Markdown.configure({
+ transformPastedText: true,
+ }),
+ ],
+ });
+
+ const event = clipboardEvent('paste');
+ event.clipboardData.setData('text/plain', `# My title`);
+
+ editor.view.dom.dispatchEvent(event);
+
+ expect(editor.getHTML()).toContain('
My title
')
+ });
+
+ test('does not transform', () => {
+ const editor = new Editor({
+ extensions: [
+ StarterKit,
+ Markdown.configure({
+ transformPastedText: false,
+ }),
+ ],
+ });
+
+ const event = clipboardEvent('paste');
+ event.clipboardData.setData('text/plain', `# My title`);
+
+ editor.view.dom.dispatchEvent(event);
+
+ expect(editor.getHTML()).not.toContain('My title
')
+ });
+ });
+
+ describe('copy', () => {
+ test('transform', () => {
+ const editor = new Editor({
+ content: '# My title',
+ extensions: [
+ StarterKit,
+ Markdown.configure({
+ transformCopiedText: true,
+ }),
+ ],
+ });
+
+ const event = clipboardEvent('copy');
+
+ editor.commands.selectAll();
+ editor.view.dom.dispatchEvent(event);
+
+ expect(event.clipboardData.getData('text/plain')).toBe('# My title');
+ });
+
+ test('does not transform', () => {
+ const editor = new Editor({
+ content: '# My title',
+ extensions: [
+ StarterKit,
+ Markdown.configure({
+ transformCopiedText: false,
+ }),
+ ],
+ });
+
+ const event = clipboardEvent('copy');
+
+ editor.commands.selectAll();
+ editor.view.dom.dispatchEvent(event);
+
+ expect(event.clipboardData.getData('text/plain')).toBe('My title');
+ });
+ });
+})
diff --git a/__tests__/utils/dom.js b/__tests__/utils/dom.js
new file mode 100644
index 0000000..a93f94d
--- /dev/null
+++ b/__tests__/utils/dom.js
@@ -0,0 +1,14 @@
+
+
+export function clipboardEvent(name) {
+ const clipboardData = {
+ data: {},
+ getData(format) { return this.data[format] },
+ setData(format, content) { return this.data[format] = content },
+ clearData(format) { delete this.data[format] },
+ };
+ const event = new Event(name);
+ event.clipboardData = clipboardData;
+
+ return event;
+}
diff --git a/__tests__/utils/setup-dom.js b/__tests__/utils/setup-dom.js
new file mode 100644
index 0000000..7128b3f
--- /dev/null
+++ b/__tests__/utils/setup-dom.js
@@ -0,0 +1,7 @@
+
+document.createRange = () => {
+ return Object.assign(new Range(), {
+ getClientRects: () => [],
+ getBoundingClientRect: () => ({}),
+ });
+};
diff --git a/example/src/components/Editor.vue b/example/src/components/Editor.vue
index c19c169..ee4f639 100644
--- a/example/src/components/Editor.vue
+++ b/example/src/components/Editor.vue
@@ -49,7 +49,7 @@
},
methods: {
updateMarkdownOutput() {
- console.log(this.editor.storage.markdown);
+ // console.log(this.editor.storage.markdown);
this.markdown = this.editor.storage.markdown.getMarkdown();
},
handleInput() {
@@ -60,6 +60,8 @@
this.editor = new Editor({
extensions: [
Markdown.configure({
+ transformPastedText: true,
+ transformCopiedText: true,
}),
StarterKit.configure({
codeBlock: false,
diff --git a/example/src/content.md b/example/src/content.md
index 32ddef7..c0eb4a3 100644
--- a/example/src/content.md
+++ b/example/src/content.md
@@ -1,9 +1,14 @@
----
+## Paragraph
+
+Proin pretium, leo ac pellentesque mollis, felis nunc ultrices eros, sed gravida augue augue mollis justo. Duis leo. Fusce neque. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris.
+
+Nulla consequat massa quis enim. Phasellus blandit leo ut odio. Phasellus dolor. Proin pretium, leo ac pellentesque mollis, felis nunc ultrices eros, sed gravida augue augue mollis justo.
+
+## Task lists
- [ ] fzfzefz
- [x] fzfezfezf
----
# h1 Heading 8-)
## h2 Heading
@@ -21,8 +26,6 @@ ___
***
-Aenean ut eros et nisl sagittis vestibulum. Donec vitae orci sed dolor rutrum auctor. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.
-
## Emphasis
**This is bold text**
diff --git a/jest.config.js b/jest.config.js
index 2356dfc..b3fdbac 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,3 +1,5 @@
+const path = require('path');
+
/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
@@ -125,7 +127,7 @@ module.exports = {
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
- // setupFiles: [],
+ setupFiles: [path.resolve(__dirname, '__tests__/utils/setup-dom.js')],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
diff --git a/src/Markdown.js b/src/Markdown.js
index fb79598..057873b 100644
--- a/src/Markdown.js
+++ b/src/Markdown.js
@@ -1,8 +1,8 @@
-import { Extension } from '@tiptap/core';
+import { Extension, extensions } from '@tiptap/core';
import { MarkdownTightLists } from "./extensions/tiptap/tight-lists";
import { MarkdownSerializer } from "./serialize/MarkdownSerializer";
import { MarkdownParser } from "./parse/MarkdownParser";
-import { extensions } from '@tiptap/core';
+import { MarkdownClipboard } from "./extensions/tiptap/clipboard";
export const Markdown = Extension.create({
name: 'markdown',
@@ -15,6 +15,8 @@ export const Markdown = Extension.create({
bulletListMarker: '-',
linkify: false,
breaks: false,
+ transformPastedText: false,
+ transformCopiedText: false,
}
},
addCommands() {
@@ -63,6 +65,10 @@ export const Markdown = Extension.create({
tight: this.options.tightLists,
tightClass: this.options.tightListClass,
}),
+ MarkdownClipboard.configure({
+ transformPastedText: this.options.transformPastedText,
+ transformCopiedText: this.options.transformCopiedText,
+ }),
]
- }
+ },
});
diff --git a/src/extensions/tiptap/clipboard.js b/src/extensions/tiptap/clipboard.js
new file mode 100644
index 0000000..22f9cbc
--- /dev/null
+++ b/src/extensions/tiptap/clipboard.js
@@ -0,0 +1,40 @@
+import { Extension } from "@tiptap/core";
+import { Plugin, PluginKey } from '@tiptap/pm/state';
+import { DOMParser } from '@tiptap/pm/model';
+import { elementFromString } from "../../util/dom";
+
+export const MarkdownClipboard = Extension.create({
+ name: 'markdownClipboard',
+ addOptions() {
+ return {
+ transformPastedText: false,
+ transformCopiedText: false,
+ }
+ },
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ key: new PluginKey('markdownClipboard'),
+ props: {
+ clipboardTextParser: (text, context, plainText) => {
+ if(plainText || !this.options.transformPastedText) {
+ return null; // pasting with shift key prevents formatting
+ }
+ const parsed = this.editor.storage.markdown.parser.parse(text, { inline: true });
+ return DOMParser.fromSchema(this.editor.schema)
+ .parseSlice(elementFromString(parsed), { preserveWhitespace: true });
+ },
+ /**
+ * @param {import('prosemirror-model').Slice} slice
+ */
+ clipboardTextSerializer: (slice) => {
+ if(!this.options.transformCopiedText) {
+ return null;
+ }
+ return this.editor.storage.markdown.serializer.serialize(slice.content);
+ },
+ },
+ })
+ ]
+ }
+})