Skip to content

Commit

Permalink
Merge pull request #19 from aguingand/parse-clipboard
Browse files Browse the repository at this point in the history
Handle pasting / copying markdown
  • Loading branch information
aguingand authored Jun 23, 2023
2 parents 2dad5e7 + b9e3984 commit d9d65b8
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 9 deletions.
85 changes: 85 additions & 0 deletions __tests__/clipboard.spec.js
Original file line number Diff line number Diff line change
@@ -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('<h1>My title</h1>')
});

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('<h1>My title</h1>')
});
});

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');
});
});
})
14 changes: 14 additions & 0 deletions __tests__/utils/dom.js
Original file line number Diff line number Diff line change
@@ -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;
}
7 changes: 7 additions & 0 deletions __tests__/utils/setup-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

document.createRange = () => {
return Object.assign(new Range(), {
getClientRects: () => [],
getBoundingClientRect: () => ({}),
});
};
4 changes: 3 additions & 1 deletion example/src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -60,6 +60,8 @@
this.editor = new Editor({
extensions: [
Markdown.configure({
transformPastedText: true,
transformCopiedText: true,
}),
StarterKit.configure({
codeBlock: false,
Expand Down
11 changes: 7 additions & 4 deletions example/src/content.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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**
Expand Down
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path');

/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
Expand Down Expand Up @@ -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: [],
Expand Down
12 changes: 9 additions & 3 deletions src/Markdown.js
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -15,6 +15,8 @@ export const Markdown = Extension.create({
bulletListMarker: '-',
linkify: false,
breaks: false,
transformPastedText: false,
transformCopiedText: false,
}
},
addCommands() {
Expand Down Expand Up @@ -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,
}),
]
}
},
});
40 changes: 40 additions & 0 deletions src/extensions/tiptap/clipboard.js
Original file line number Diff line number Diff line change
@@ -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);
},
},
})
]
}
})

0 comments on commit d9d65b8

Please sign in to comment.