fix: Improved pasting behavior from Dropbox Paper
This commit is contained in:
@@ -40,8 +40,8 @@ export default class Code extends Mark {
|
|||||||
get schema(): MarkSpec {
|
get schema(): MarkSpec {
|
||||||
return {
|
return {
|
||||||
excludes: "_",
|
excludes: "_",
|
||||||
parseDOM: [{ tag: "code", preserveWhitespace: true }],
|
parseDOM: [{ tag: "code.inline", preserveWhitespace: true }],
|
||||||
toDOM: () => ["code", { spellCheck: "false" }],
|
toDOM: () => ["code", { class: "inline", spellCheck: "false" }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ export default class Blockquote extends Node {
|
|||||||
content: "block+",
|
content: "block+",
|
||||||
group: "block",
|
group: "block",
|
||||||
defining: true,
|
defining: true,
|
||||||
parseDOM: [{ tag: "blockquote" }],
|
parseDOM: [
|
||||||
|
{ tag: "blockquote" },
|
||||||
|
// Dropbox Paper parsing, yes their quotes are actually lists
|
||||||
|
{ tag: "ul.listtype-quote", contentElement: "li" },
|
||||||
|
],
|
||||||
toDOM: () => ["blockquote", 0],
|
toDOM: () => ["blockquote", 0],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export default class CodeFence extends Node {
|
|||||||
defining: true,
|
defining: true,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
parseDOM: [
|
parseDOM: [
|
||||||
|
{ tag: "code" },
|
||||||
{ tag: "pre", preserveWhitespace: "full" },
|
{ tag: "pre", preserveWhitespace: "full" },
|
||||||
{
|
{
|
||||||
tag: ".code-block",
|
tag: ".code-block",
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import isUrl from "../lib/isUrl";
|
|||||||
import selectionIsInCode from "../queries/isInCode";
|
import selectionIsInCode from "../queries/isInCode";
|
||||||
import { LANGUAGES } from "./Prism";
|
import { LANGUAGES } from "./Prism";
|
||||||
|
|
||||||
|
function isDropboxPaper(html: string): boolean {
|
||||||
|
// The best we have to detect if a paste is likely coming from Paper
|
||||||
|
// In this case it's actually better to use the text version
|
||||||
|
return html?.includes("usually-unique-id");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add support for additional syntax that users paste even though it isn't
|
* Add support for additional syntax that users paste even though it isn't
|
||||||
* supported by the markdown parser directly by massaging the text content.
|
* supported by the markdown parser directly by massaging the text content.
|
||||||
@@ -14,13 +20,16 @@ import { LANGUAGES } from "./Prism";
|
|||||||
* @param text The incoming pasted plain text
|
* @param text The incoming pasted plain text
|
||||||
*/
|
*/
|
||||||
function normalizePastedMarkdown(text: string): string {
|
function normalizePastedMarkdown(text: string): string {
|
||||||
// find checkboxes not contained in a list and wrap them in list items
|
|
||||||
const CHECKBOX_REGEX = /^\s?(\[(X|\s|_|-)\]\s(.*)?)/gim;
|
const CHECKBOX_REGEX = /^\s?(\[(X|\s|_|-)\]\s(.*)?)/gim;
|
||||||
|
|
||||||
|
// find checkboxes not contained in a list and wrap them in list items
|
||||||
while (text.match(CHECKBOX_REGEX)) {
|
while (text.match(CHECKBOX_REGEX)) {
|
||||||
text = text.replace(CHECKBOX_REGEX, (match) => `- ${match.trim()}`);
|
text = text.replace(CHECKBOX_REGEX, (match) => `- ${match.trim()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find multiple newlines and insert a hard break to ensure they are respected
|
||||||
|
text = text.replace(/\n{2,}/g, "\n\n\\\n");
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +42,13 @@ export default class PasteHandler extends Extension {
|
|||||||
return [
|
return [
|
||||||
new Plugin({
|
new Plugin({
|
||||||
props: {
|
props: {
|
||||||
|
transformPastedHTML(html: string) {
|
||||||
|
if (isDropboxPaper(html)) {
|
||||||
|
// Fixes double paragraphs when pasting from Dropbox Paper
|
||||||
|
html = html.replace(/<div><br><\/div>/gi, "<p></p>");
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
},
|
||||||
handlePaste: (view, event: ClipboardEvent) => {
|
handlePaste: (view, event: ClipboardEvent) => {
|
||||||
if (view.props.editable && !view.props.editable(view.state)) {
|
if (view.props.editable && !view.props.editable(view.state)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -125,7 +141,7 @@ export default class PasteHandler extends Extension {
|
|||||||
// If the text on the clipboard looks like Markdown OR there is no
|
// If the text on the clipboard looks like Markdown OR there is no
|
||||||
// html on the clipboard then try to parse content as Markdown
|
// html on the clipboard then try to parse content as Markdown
|
||||||
if (
|
if (
|
||||||
isMarkdown(text) ||
|
(isMarkdown(text) && !isDropboxPaper(html)) ||
|
||||||
html.length === 0 ||
|
html.length === 0 ||
|
||||||
pasteCodeLanguage === "markdown"
|
pasteCodeLanguage === "markdown"
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user