diff --git a/packages/tiptap-commands/src/commands/markPasteRule.js b/packages/tiptap-commands/src/commands/markPasteRule.js new file mode 100644 index 000000000..009ae013c --- /dev/null +++ b/packages/tiptap-commands/src/commands/markPasteRule.js @@ -0,0 +1,57 @@ +import { Plugin } from 'prosemirror-state' +import { Slice, Fragment } from 'prosemirror-model' + +export default function (regexp, type, getAttrs) { + + const handler = fragment => { + const nodes = [] + + fragment.forEach(child => { + if (child.isText) { + const { text } = child + let pos = 0 + let match + + // eslint-disable-next-line + while ((match = regexp.exec(text)) !== null) { + if (match[1]) { + const start = match.index + const end = start + match[0].length + const textStart = start + match[0].indexOf(match[1]) + const textEnd = textStart + match[1].length + const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs + + // adding text before markdown to nodes + if (start > 0) { + nodes.push(child.cut(pos, start)) + } + + // adding the markdown part to nodes + nodes.push(child + .cut(textStart, textEnd) + .mark(type.create(attrs) + .addToSet(child.marks))) + + pos = end + } + } + + // adding rest of text to nodes + if (pos < text.length) { + nodes.push(child.cut(pos)) + } + } else { + nodes.push(child.copy(handler(child.content))) + } + }) + + return Fragment.fromArray(nodes) + } + + return new Plugin({ + props: { + transformPasted: slice => new Slice(handler(slice.content), slice.openStart, slice.openEnd), + }, + }) + +} diff --git a/packages/tiptap-commands/src/index.js b/packages/tiptap-commands/src/index.js index c200c2d09..ded01c96c 100644 --- a/packages/tiptap-commands/src/index.js +++ b/packages/tiptap-commands/src/index.js @@ -42,6 +42,7 @@ import insertText from './commands/insertText' import markInputRule from './commands/markInputRule' import nodeInputRule from './commands/nodeInputRule' import pasteRule from './commands/pasteRule' +import markPasteRule from './commands/markPasteRule' import removeMark from './commands/removeMark' import replaceText from './commands/replaceText' import setInlineBlockType from './commands/setInlineBlockType' @@ -92,6 +93,7 @@ export { // custom insertText, markInputRule, + markPasteRule, nodeInputRule, pasteRule, removeMark, diff --git a/packages/tiptap-extensions/src/marks/Bold.js b/packages/tiptap-extensions/src/marks/Bold.js index 275426db2..937df5b89 100644 --- a/packages/tiptap-extensions/src/marks/Bold.js +++ b/packages/tiptap-extensions/src/marks/Bold.js @@ -1,5 +1,5 @@ import { Mark } from 'tiptap' -import { toggleMark, markInputRule } from 'tiptap-commands' +import { toggleMark, markInputRule, markPasteRule } from 'tiptap-commands' export default class Bold extends Mark { @@ -42,4 +42,10 @@ export default class Bold extends Mark { ] } + pasteRules({ type }) { + return [ + markPasteRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)/g, type), + ] + } + } diff --git a/packages/tiptap-extensions/src/marks/Code.js b/packages/tiptap-extensions/src/marks/Code.js index 7d7dfa982..29522c261 100644 --- a/packages/tiptap-extensions/src/marks/Code.js +++ b/packages/tiptap-extensions/src/marks/Code.js @@ -1,5 +1,5 @@ import { Mark } from 'tiptap' -import { toggleMark, markInputRule } from 'tiptap-commands' +import { toggleMark, markInputRule, markPasteRule } from 'tiptap-commands' export default class Code extends Mark { @@ -32,4 +32,10 @@ export default class Code extends Mark { ] } + pasteRules({ type }) { + return [ + markPasteRule(/(?:`)([^`]+)(?:`)/g, type), + ] + } + } diff --git a/packages/tiptap-extensions/src/marks/Italic.js b/packages/tiptap-extensions/src/marks/Italic.js index a69a731c1..e3d79e759 100644 --- a/packages/tiptap-extensions/src/marks/Italic.js +++ b/packages/tiptap-extensions/src/marks/Italic.js @@ -1,5 +1,5 @@ import { Mark } from 'tiptap' -import { toggleMark, markInputRule } from 'tiptap-commands' +import { toggleMark, markInputRule, markPasteRule } from 'tiptap-commands' export default class Italic extends Mark { @@ -34,4 +34,10 @@ export default class Italic extends Mark { ] } + pasteRules({ type }) { + return [ + markPasteRule(/(?:^|[^*_])(?:\*|_)([^*_]+)(?:\*|_)/g, type), + ] + } + } diff --git a/packages/tiptap-extensions/src/marks/Strike.js b/packages/tiptap-extensions/src/marks/Strike.js index 79fd0f46e..7734fa143 100644 --- a/packages/tiptap-extensions/src/marks/Strike.js +++ b/packages/tiptap-extensions/src/marks/Strike.js @@ -1,5 +1,5 @@ import { Mark } from 'tiptap' -import { toggleMark, markInputRule } from 'tiptap-commands' +import { toggleMark, markInputRule, markPasteRule } from 'tiptap-commands' export default class Strike extends Mark { @@ -44,4 +44,10 @@ export default class Strike extends Mark { ] } + pasteRules({ type }) { + return [ + markPasteRule(/~([^~]+)~/g, type), + ] + } + } diff --git a/packages/tiptap/src/Editor.js b/packages/tiptap/src/Editor.js index 95cc4586d..20f89d5e3 100644 --- a/packages/tiptap/src/Editor.js +++ b/packages/tiptap/src/Editor.js @@ -31,6 +31,7 @@ export default class Editor { onUpdate: () => {}, onFocus: () => {}, onBlur: () => {}, + onPaste: () => {}, } this.init(options) @@ -198,6 +199,8 @@ export default class Editor { createView() { const view = new EditorView(this.element, { state: this.state, + handlePaste: this.options.onPaste, + handleDrop: this.options.onPaste, dispatchTransaction: this.dispatchTransaction.bind(this), }) diff --git a/packages/tiptap/src/Utils/Extension.js b/packages/tiptap/src/Utils/Extension.js index e86851d26..92461dbe7 100644 --- a/packages/tiptap/src/Utils/Extension.js +++ b/packages/tiptap/src/Utils/Extension.js @@ -27,6 +27,10 @@ export default class Extension { return [] } + pasteRules() { + return [] + } + keys() { return {} }