diff --git a/packages/editor/package-lock.json b/packages/editor/package-lock.json
index a679acf86..85f66a2f7 100644
--- a/packages/editor/package-lock.json
+++ b/packages/editor/package-lock.json
@@ -38,7 +38,6 @@
"@tiptap/extension-underline": "2.0.3",
"@tiptap/pm": "2.0.3",
"@tiptap/starter-kit": "2.0.3",
- "clipboard-polyfill": "4.0.0",
"detect-indent": "^7.0.0",
"entities": "^4.5.0",
"katex": "0.16.4",
@@ -1910,11 +1909,6 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
- "node_modules/clipboard-polyfill": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/clipboard-polyfill/-/clipboard-polyfill-4.0.0.tgz",
- "integrity": "sha512-U4KPNJqAYuyOtixCZZUyWTcj+wlI66j07g5ggMRE2DR1VFu/3ZWXkjLAslmme8i065gBSCUblHET7DKQ2Xg3RA=="
- },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -5098,11 +5092,6 @@
}
}
},
- "clipboard-polyfill": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/clipboard-polyfill/-/clipboard-polyfill-4.0.0.tgz",
- "integrity": "sha512-U4KPNJqAYuyOtixCZZUyWTcj+wlI66j07g5ggMRE2DR1VFu/3ZWXkjLAslmme8i065gBSCUblHET7DKQ2Xg3RA=="
- },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
diff --git a/packages/editor/package.json b/packages/editor/package.json
index f0f1fa42b..991cd259f 100644
--- a/packages/editor/package.json
+++ b/packages/editor/package.json
@@ -33,7 +33,6 @@
"@tiptap/extension-underline": "2.0.3",
"@tiptap/pm": "2.0.3",
"@tiptap/starter-kit": "2.0.3",
- "clipboard-polyfill": "4.0.0",
"detect-indent": "^7.0.0",
"entities": "^4.5.0",
"katex": "0.16.4",
diff --git a/packages/editor/src/extensions/clipboard-text-serializer/index.ts b/packages/editor/src/extensions/clipboard-text-serializer/index.ts
deleted file mode 100644
index 01daa05b9..000000000
--- a/packages/editor/src/extensions/clipboard-text-serializer/index.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-This file is part of the Notesnook project (https://notesnook.com/)
-
-Copyright (C) 2023 Streetwriters (Private) Limited
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-import { Extension, TextSerializer } from "@tiptap/core";
-import { Plugin, PluginKey } from "prosemirror-state";
-import { Fragment, Schema, Slice } from "prosemirror-model";
-import { ListItem } from "../list-item";
-import { LIST_NODE_TYPES } from "../../utils/node-types";
-import {
- DOMSerializer,
- DOMParser as ProsemirrorDOMParser
-} from "@tiptap/pm/model";
-import { convertTextToHTML } from "../../utils/html";
-
-export class ClipboardDOMSerializer extends DOMSerializer {
- static fromSchema(schema: Schema): ClipboardDOMSerializer {
- return (
- schema.cached.domSerializer2 ||
- (schema.cached.domSerializer2 = new ClipboardDOMSerializer(
- this.nodesFromSchema(schema),
- this.marksFromSchema(schema)
- ))
- );
- }
-
- serializeFragment(
- fragment: Fragment,
- options?: { document?: Document | undefined } | undefined,
- target?: HTMLElement | DocumentFragment | undefined
- ): HTMLElement | DocumentFragment {
- const dom = super.serializeFragment(fragment, options, target);
- for (const p of dom.querySelectorAll("li > p")) {
- if (p.parentElement && p.parentElement.childElementCount > 1) continue;
- p.parentElement?.append(...p.childNodes);
- p.remove();
- }
-
- for (const p of dom.querySelectorAll('p[data-spacing="single"]')) {
- if (!p.previousElementSibling || p.previousElementSibling.tagName !== "P")
- continue;
- if (p.previousElementSibling.childNodes.length > 0)
- p.previousElementSibling.appendChild(document.createElement("br"));
- p.previousElementSibling.append(...p.childNodes);
- p.remove();
- }
-
- return dom;
- }
-}
-
-export const ClipboardTextSerializer = Extension.create({
- name: "clipboardTextSerializer",
-
- addProseMirrorPlugins() {
- return [
- new Plugin({
- key: new PluginKey("clipboardTextSerializer"),
- props: {
- transformCopied,
- clipboardSerializer: ClipboardDOMSerializer.fromSchema(
- this.editor.view.state.schema
- ),
- clipboardTextParser: (text) => {
- const doc = new DOMParser().parseFromString(
- convertTextToHTML(text),
- "text/html"
- );
- return ProsemirrorDOMParser.fromSchema(
- this.editor.view.state.schema
- ).parseSlice(doc, { preserveWhitespace: "full" });
- },
- clipboardTextSerializer: (content, view) => {
- return getTextBetween(content, view.state.schema);
- }
- }
- })
- ];
- }
-});
-
-export function transformCopied(slice: Slice) {
- // when copying a single list item, we shouldn't retain the
- // list formatting but copy it as a paragraph.
- const maybeList = slice.content.firstChild;
- if (
- maybeList &&
- LIST_NODE_TYPES.includes(maybeList.type.name) &&
- maybeList.childCount === 1 &&
- maybeList.firstChild
- ) {
- return transformCopied(new Slice(maybeList.firstChild.content, 0, 0));
- }
- return slice;
-}
-
-export function getTextBetween(slice: Slice, schema: Schema): string {
- const range = { from: 0, to: slice.size };
- const separator = "\n";
- let text = "";
- let separated = true;
-
- slice.content.nodesBetween(0, slice.size, (node, pos, parent, index) => {
- const textSerializer = schema.nodes[node.type.name]?.spec
- .toText as TextSerializer;
-
- if (textSerializer) {
- if (node.isBlock && !separated) {
- text += separator;
- separated = true;
- }
-
- if (parent) {
- text += textSerializer({
- node,
- pos,
- parent,
- index,
- range
- });
- }
- } else if (node.isText) {
- text += node?.text;
- separated = false;
- } else if (node.isBlock && !!text) {
- // we don't want double spaced list items when pasting
- if (index === 0 && parent?.type.name === ListItem.name) return;
-
- text += separator;
- if (node.attrs.spacing === "double" && node.childCount > 0)
- text += separator;
- separated = true;
- }
- });
-
- return text;
-}
diff --git a/packages/editor/src/utils/html.ts b/packages/editor/src/extensions/clipboard/clipboard-dom-parser.ts
similarity index 69%
rename from packages/editor/src/utils/html.ts
rename to packages/editor/src/extensions/clipboard/clipboard-dom-parser.ts
index dd7dbaa11..be03868db 100644
--- a/packages/editor/src/utils/html.ts
+++ b/packages/editor/src/extensions/clipboard/clipboard-dom-parser.ts
@@ -17,11 +17,32 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { encodeNonAsciiHTML } from "entities";
+import {
+ DOMParser as ProsemirrorDOMParser,
+ ParseOptions
+} from "@tiptap/pm/model";
+import { Schema, Slice } from "prosemirror-model";
-export function convertBrToParagraph(html: string) {
- const doc = new DOMParser().parseFromString(html, "text/html");
- for (const br of doc.querySelectorAll("br")) {
+export class ClipboardDOMParser extends ProsemirrorDOMParser {
+ static fromSchema(schema: Schema): ClipboardDOMParser {
+ return (
+ (schema.cached.clipboardDomParser as ClipboardDOMParser) ||
+ (schema.cached.clipboardDomParser = new ClipboardDOMParser(
+ schema,
+ (ProsemirrorDOMParser as any).schemaRules(schema)
+ ))
+ );
+ }
+
+ parseSlice(dom: Node, options?: ParseOptions | undefined): Slice {
+ convertBrToSingleSpacedParagraphs(dom);
+ return super.parseSlice(dom, options);
+ }
+}
+
+export function convertBrToSingleSpacedParagraphs(dom: Node) {
+ if (!(dom instanceof HTMLElement)) return;
+ for (const br of dom.querySelectorAll("br")) {
let paragraph = br.closest("p");
// if no paragraph is found over the br, we add one.
@@ -37,14 +58,13 @@ export function convertBrToParagraph(html: string) {
if (paragraph) {
splitOn(paragraph, br);
const children = Array.from(paragraph.childNodes.values());
- const newParagraph = doc.createElement("p");
+ const newParagraph = document.createElement("p");
newParagraph.dataset.spacing = "single";
newParagraph.append(...children.slice(children.indexOf(br) + 1));
paragraph.insertAdjacentElement("afterend", newParagraph);
br.remove();
}
}
- return doc;
}
function splitOn(bound: Element, cutElement: Element) {
@@ -63,25 +83,3 @@ function splitOn(bound: Element, cutElement: Element) {
}
}
}
-
-export function convertTextToHTML(src: string) {
- return src
- .split(/[\r\n]/)
- .map((line) =>
- line
- ? `
${encodeLine(line)}
`
- : ``
- )
- .join("");
-}
-
-function encodeLine(line: string) {
- line = encodeNonAsciiHTML(line);
- line = line.replace(/(^ +)|( {2,})/g, (sub, ...args) => {
- const [starting, inline] = args;
- if (starting) return " ".repeat(starting.length);
- if (inline) return " ".repeat(inline.length);
- return sub;
- });
- return line;
-}
diff --git a/packages/editor/src/extensions/clipboard/clipboard-dom-serializer.ts b/packages/editor/src/extensions/clipboard/clipboard-dom-serializer.ts
new file mode 100644
index 000000000..45e1438f0
--- /dev/null
+++ b/packages/editor/src/extensions/clipboard/clipboard-dom-serializer.ts
@@ -0,0 +1,57 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+import { Fragment, Schema } from "prosemirror-model";
+import { DOMSerializer } from "@tiptap/pm/model";
+
+export class ClipboardDOMSerializer extends DOMSerializer {
+ static fromSchema(schema: Schema): ClipboardDOMSerializer {
+ return (
+ schema.cached.clipboardDomSerializer ||
+ (schema.cached.clipboardDomSerializer = new ClipboardDOMSerializer(
+ this.nodesFromSchema(schema),
+ this.marksFromSchema(schema)
+ ))
+ );
+ }
+
+ serializeFragment(
+ fragment: Fragment,
+ options?: { document?: Document | undefined } | undefined,
+ target?: HTMLElement | DocumentFragment | undefined
+ ): HTMLElement | DocumentFragment {
+ const dom = super.serializeFragment(fragment, options, target);
+ for (const p of dom.querySelectorAll("li > p")) {
+ if (p.parentElement && p.parentElement.childElementCount > 1) continue;
+ p.parentElement?.append(...p.childNodes);
+ p.remove();
+ }
+
+ for (const p of dom.querySelectorAll('p[data-spacing="single"]')) {
+ if (!p.previousElementSibling || p.previousElementSibling.tagName !== "P")
+ continue;
+ if (p.previousElementSibling.childNodes.length > 0)
+ p.previousElementSibling.appendChild(document.createElement("br"));
+ p.previousElementSibling.append(...p.childNodes);
+ p.remove();
+ }
+
+ return dom;
+ }
+}
diff --git a/packages/editor/src/extensions/clipboard/clipboard-text-parser.ts b/packages/editor/src/extensions/clipboard/clipboard-text-parser.ts
new file mode 100644
index 000000000..44b76de4a
--- /dev/null
+++ b/packages/editor/src/extensions/clipboard/clipboard-text-parser.ts
@@ -0,0 +1,60 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+import { ResolvedPos, Slice } from "@tiptap/pm/model";
+import { encodeNonAsciiHTML } from "entities";
+import { ClipboardDOMParser } from "./clipboard-dom-parser";
+import { EditorView } from "@tiptap/pm/view";
+
+export function clipboardTextParser(
+ text: string,
+ _$context: ResolvedPos,
+ _plain: boolean,
+ view: EditorView
+): Slice {
+ const doc = new DOMParser().parseFromString(
+ convertTextToHTML(text),
+ "text/html"
+ );
+ return ClipboardDOMParser.fromSchema(view.state.schema).parseSlice(doc, {
+ preserveWhitespace: "full"
+ });
+}
+
+export function convertTextToHTML(src: string) {
+ return src
+ .split(/[\r\n]/)
+ .map((line) =>
+ line
+ ? `${encodeLine(line)}
`
+ : ``
+ )
+ .join("");
+}
+
+function encodeLine(line: string) {
+ line = encodeNonAsciiHTML(line);
+ line = line.replace(/(^ +)|( {2,})/g, (sub, ...args) => {
+ const [starting, inline] = args;
+ if (starting) return " ".repeat(starting.length);
+ if (inline) return " ".repeat(inline.length);
+ return sub;
+ });
+ return line;
+}
diff --git a/packages/editor/src/extensions/clipboard/clipboard-text-serializer.ts b/packages/editor/src/extensions/clipboard/clipboard-text-serializer.ts
new file mode 100644
index 000000000..058fc1157
--- /dev/null
+++ b/packages/editor/src/extensions/clipboard/clipboard-text-serializer.ts
@@ -0,0 +1,69 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+import { TextSerializer } from "@tiptap/core";
+import { Schema, Slice } from "prosemirror-model";
+import { ListItem } from "../list-item";
+import { EditorView } from "@tiptap/pm/view";
+
+export function clipboardTextSerializer(content: Slice, view: EditorView) {
+ return getTextBetween(content, view.state.schema);
+}
+
+export function getTextBetween(slice: Slice, schema: Schema): string {
+ const range = { from: 0, to: slice.size };
+ const separator = "\n";
+ let text = "";
+ let separated = true;
+
+ slice.content.nodesBetween(0, slice.size, (node, pos, parent, index) => {
+ const textSerializer = schema.nodes[node.type.name]?.spec
+ .toText as TextSerializer;
+
+ if (textSerializer) {
+ if (node.isBlock && !separated) {
+ text += separator;
+ separated = true;
+ }
+
+ if (parent) {
+ text += textSerializer({
+ node,
+ pos,
+ parent,
+ index,
+ range
+ });
+ }
+ } else if (node.isText) {
+ text += node?.text;
+ separated = false;
+ } else if (node.isBlock && !!text) {
+ // we don't want double spaced list items when pasting
+ if (index === 0 && parent?.type.name === ListItem.name) return;
+
+ text += separator;
+ if (node.attrs.spacing === "double" && node.childCount > 0)
+ text += separator;
+ separated = true;
+ }
+ });
+
+ return text;
+}
diff --git a/packages/editor/src/extensions/clipboard/clipboard.ts b/packages/editor/src/extensions/clipboard/clipboard.ts
index 9530d1be4..ddc5a5243 100644
--- a/packages/editor/src/extensions/clipboard/clipboard.ts
+++ b/packages/editor/src/extensions/clipboard/clipboard.ts
@@ -16,8 +16,15 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+
import { Extension } from "@tiptap/core";
-import { writeText } from "clipboard-polyfill";
+import { Plugin, PluginKey } from "prosemirror-state";
+import { Slice } from "prosemirror-model";
+import { LIST_NODE_TYPES } from "../../utils/node-types";
+import { ClipboardDOMParser } from "./clipboard-dom-parser";
+import { ClipboardDOMSerializer } from "./clipboard-dom-serializer";
+import { clipboardTextParser } from "./clipboard-text-parser";
+import { clipboardTextSerializer } from "./clipboard-text-serializer";
declare module "@tiptap/core" {
interface Commands {
@@ -31,14 +38,15 @@ export type ClipboardOptions = {
copyToClipboard: (text: string) => void;
};
-export const Clipboard = Extension.create({
+export const Clipboard = Extension.create({
+ name: "clipboard",
+
addOptions() {
return {
- copyToClipboard: (text) => {
- writeText(text);
- }
+ copyToClipboard: () => {}
};
},
+
addCommands() {
return {
copyToClipboard: (text: string) => (props) => {
@@ -46,5 +54,39 @@ export const Clipboard = Extension.create({
return true;
}
};
+ },
+
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ key: new PluginKey("clipboard"),
+ props: {
+ clipboardParser: ClipboardDOMParser.fromSchema(
+ this.editor.view.state.schema
+ ),
+ clipboardSerializer: ClipboardDOMSerializer.fromSchema(
+ this.editor.view.state.schema
+ ),
+ transformCopied,
+ clipboardTextParser,
+ clipboardTextSerializer
+ }
+ })
+ ];
}
});
+
+export function transformCopied(slice: Slice) {
+ // when copying a single list item, we shouldn't retain the
+ // list formatting but copy it as a paragraph.
+ const maybeList = slice.content.firstChild;
+ if (
+ maybeList &&
+ LIST_NODE_TYPES.includes(maybeList.type.name) &&
+ maybeList.childCount === 1 &&
+ maybeList.firstChild
+ ) {
+ return transformCopied(new Slice(maybeList.firstChild.content, 0, 0));
+ }
+ return slice;
+}
diff --git a/packages/editor/src/extensions/clipboard/index.ts b/packages/editor/src/extensions/clipboard/index.ts
index 88adc7417..72e41804c 100644
--- a/packages/editor/src/extensions/clipboard/index.ts
+++ b/packages/editor/src/extensions/clipboard/index.ts
@@ -16,8 +16,6 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { Clipboard } from "./clipboard";
export * from "./clipboard";
-
-export default Clipboard;
+export { Clipboard as default } from "./clipboard";
diff --git a/packages/editor/src/extensions/clipboard/tests/__snapshots__/clipboard-dom-parser.test.ts.snap b/packages/editor/src/extensions/clipboard/tests/__snapshots__/clipboard-dom-parser.test.ts.snap
new file mode 100644
index 000000000..d7f1ebb76
--- /dev/null
+++ b/packages/editor/src/extensions/clipboard/tests/__snapshots__/clipboard-dom-parser.test.ts.snap
@@ -0,0 +1,69 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`convert br tags to paragraphs (
+
+A troll, they call me, but I have no wish
+to be associated with those dolls
+
+We lack religion, purpose, politics,
+and yet, we somehow manage to get by.
+
+) 1`] = `
+"A troll, they call me, but I have no wish
+to be associated with those dolls
+
+We lack religion, purpose, politics,
+and yet, we somehow manage to get by.
"
+`;
+
+exports[`convert br tags to paragraphs (
+ When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.
+ Also when I share the selection to Notesnook via the share functionality from Android, I have the same issue.
+
+ Device information:
+ App version: 2.3.0
+ Platform: android
+ Model: OnePlus-CPH2409-31
+ Pro: true
+ Logged in: yes
+
+ ) 1`] = `
+"When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.
+ Also when I share the selection to Notesnook via the share functionality from Android, I have the same issue.
+
+ Device information:
+ App version: 2.3.0
+ Platform: android
+ Model: OnePlus-CPH2409-31
+ Pro: true
+ Logged in: yes
"
+`;
+
+exports[`convert br tags to paragraphs (
+ Why switch from Gmail?
+
+ Not sacrificing features for more privacy, prefer using one app, in many public groups and channels (Telegram)
+
+ LibreOffice Slow & buggy
+
+ Switched to Brave for the better Android app, more private out of the box & unsure if uBlock Origin closes gap
+
+ ) 1`] = `
+"Why switch from Gmail?
+
+ Not sacrificing features for more privacy, prefer using one app, in many public groups and channels (Telegram)
+
+ LibreOffice Slow & buggy
+
+ Switched to Brave for the better Android app, more private out of the box & unsure if uBlock Origin closes gap"
+`;
+
+exports[`convert br tags to paragraphs (
) 1`] = `"
"`;
+
+exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
+
+exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
+
+exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
+
+exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
diff --git a/packages/editor/src/extensions/clipboard-text-serializer/tests/__snapshots__/clipboard-text-serializer.test.ts.snap b/packages/editor/src/extensions/clipboard/tests/__snapshots__/clipboard-text-serializer.test.ts.snap
similarity index 100%
rename from packages/editor/src/extensions/clipboard-text-serializer/tests/__snapshots__/clipboard-text-serializer.test.ts.snap
rename to packages/editor/src/extensions/clipboard/tests/__snapshots__/clipboard-text-serializer.test.ts.snap
diff --git a/packages/editor/src/utils/tests/html.test.ts b/packages/editor/src/extensions/clipboard/tests/clipboard-dom-parser.test.ts
similarity index 90%
rename from packages/editor/src/utils/tests/html.test.ts
rename to packages/editor/src/extensions/clipboard/tests/clipboard-dom-parser.test.ts
index 2fb22f45c..de7dc774a 100644
--- a/packages/editor/src/utils/tests/html.test.ts
+++ b/packages/editor/src/extensions/clipboard/tests/clipboard-dom-parser.test.ts
@@ -18,7 +18,7 @@ along with this program. If not, see .
*/
import { test } from "vitest";
-import { convertBrToParagraph } from "../html";
+import { convertBrToSingleSpacedParagraphs } from "../clipboard-dom-parser";
const cases = [
[`line 1
line 2
`],
@@ -68,8 +68,8 @@ and yet, we somehow manage to get by.
for (const testCase of cases) {
const [html, expected] = testCase;
test(`convert br tags to paragraphs (${testCase})`, (t) => {
- t.expect(
- convertBrToParagraph(html).body.innerHTML.trim()
- ).toMatchSnapshot();
+ const element = new DOMParser().parseFromString(html, "text/html");
+ convertBrToSingleSpacedParagraphs(element);
+ t.expect(element.body.innerHTML.trim()).toMatchSnapshot();
});
}
diff --git a/packages/editor/src/extensions/clipboard-text-serializer/tests/clipboard-text-serializer.test.ts b/packages/editor/src/extensions/clipboard/tests/clipboard-text-serializer.test.ts
similarity index 96%
rename from packages/editor/src/extensions/clipboard-text-serializer/tests/clipboard-text-serializer.test.ts
rename to packages/editor/src/extensions/clipboard/tests/clipboard-text-serializer.test.ts
index 674700eaa..03629b8d3 100644
--- a/packages/editor/src/extensions/clipboard-text-serializer/tests/clipboard-text-serializer.test.ts
+++ b/packages/editor/src/extensions/clipboard/tests/clipboard-text-serializer.test.ts
@@ -21,12 +21,10 @@ import { test } from "vitest";
import { createEditor, h } from "../../../../test-utils";
import OrderedList from "../../ordered-list";
import { ListItem } from "../../list-item";
-import {
- getTextBetween,
- transformCopied,
- ClipboardDOMSerializer
-} from "../index";
+import { transformCopied } from "../index";
import { Paragraph } from "../../paragraph";
+import { ClipboardDOMSerializer } from "../clipboard-dom-serializer";
+import { clipboardTextSerializer } from "../clipboard-text-serializer";
test("copied list items shouldn't contain extra newlines", (t) => {
const { editor } = createEditor({
@@ -59,9 +57,9 @@ test("copied list items shouldn't contain extra newlines", (t) => {
);
t.expect(
- getTextBetween(
+ clipboardTextSerializer(
editor.state.doc.slice(0, editor.state.doc.nodeSize - 2),
- editor.schema
+ editor.view
)
).toBe(`This is line: number 1.
And this is line number 2.
@@ -194,9 +192,9 @@ for (const testCase of paragraphTestCases) {
).toBe(testCase.expectedHtml);
t.expect(
- getTextBetween(
+ clipboardTextSerializer(
editor.state.doc.slice(0, editor.state.doc.nodeSize - 2),
- editor.schema
+ editor.view
)
).toBe(testCase.expectedText);
});
diff --git a/packages/editor/src/extensions/code-block/tests/__snapshots__/code-block.test.ts.snap b/packages/editor/src/extensions/code-block/tests/__snapshots__/code-block.test.ts.snap
index d4461a057..db97a3165 100644
--- a/packages/editor/src/extensions/code-block/tests/__snapshots__/code-block.test.ts.snap
+++ b/packages/editor/src/extensions/code-block/tests/__snapshots__/code-block.test.ts.snap
@@ -10,4 +10,9 @@ exports[`codeblocks should not be updated if other content is changed 1`] = `"function hello() { }const hello0 = 0;const hello1 = 1;const hello2 = 2;const hello3 = 3;const hello4 = 4;const hello5 = 5;const hello6 = 6;const hello7 = 7;const hello8 = 8;const hello9 = 9;const hello10 = 10;const hello11 = 11;const hello12 = 12;const hello13 = 13;const hello14 = 14;const hello15 = 15;const hello16 = 16;const hello17 = 17;const hello18 = 18;const hello19 = 19;const hello20 = 20;const hello21 = 21;const hello22 = 22;const hello23 = 23;const hello24 = 24;const hello25 = 25;const hello26 = 26;const hello27 = 27;const hello28 = 28;const hello29 = 29;const hello30 = 30;const hello31 = 31;const hello32 = 32;const hello33 = 33;const hello34 = 34;const hello35 = 35;const hello36 = 36;const hello37 = 37;const hello38 = 38;const hello39 = 39;const hello40 = 40;const hello41 = 41;const hello42 = 42;const hello43 = 43;const hello44 = 44;const hello45 = 45;const hello46 = 46;const hello47 = 47;const hello48 = 48;const hello49 = 49;const hello50 = 50;const hello51 = 51;const hello52 = 52;const hello53 = 53;const hello54 = 54;const hello55 = 55;const hello56 = 56;const hello57 = 57;const hello58 = 58;const hello59 = 59;const hello60 = 60;const hello61 = 61;const hello62 = 62;const hello63 = 63;const hello64 = 64;const hello65 = 65;const hello66 = 66;const hello67 = 67;const hello68 = 68;const hello69 = 69;const hello70 = 70;const hello71 = 71;const hello72 = 72;const hello73 = 73;const hello74 = 74;const hello75 = 75;const hello76 = 76;const hello77 = 77;const hello78 = 78;const hello79 = 79;const hello80 = 80;const hello81 = 81;const hello82 = 82;const hello83 = 83;const hello84 = 84;const hello85 = 85;const hello86 = 86;const hello87 = 87;const hello88 = 88;const hello89 = 89;const hello90 = 90;const hello91 = 91;const hello92 = 92;const hello93 = 93;const hello94 = 94;const hello95 = 95;const hello96 = 96;const hello97 = 97;const hello98 = 98;const hello99 = 99; "`;
-exports[`pasting code from vscode should automatically create a syntax highlighted codeblock 1`] = `""`;
+exports[`pasting code from vscode should automatically create a syntax highlighted codeblock 1`] = `
+"function hello()
+{
+ const world = \\"hello\\";
+} "
+`;
diff --git a/packages/editor/src/extensions/code-block/tests/code-block.test.ts b/packages/editor/src/extensions/code-block/tests/code-block.test.ts
index 7138b1fd9..42f3eec05 100644
--- a/packages/editor/src/extensions/code-block/tests/code-block.test.ts
+++ b/packages/editor/src/extensions/code-block/tests/code-block.test.ts
@@ -122,7 +122,10 @@ test("pasting code from vscode should automatically create a syntax highlighted
(clipboardEvent as unknown as any)["clipboardData"] = {
getData: (type: string) =>
type === "text/plain"
- ? "function hello() { }"
+ ? `function hello()
+{
+ const world = "hello";
+}`
: type === "vscode-editor-data"
? JSON.stringify({ mode: "javascript" })
: undefined
diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts
index 1672cc183..0e21a59d2 100644
--- a/packages/editor/src/index.ts
+++ b/packages/editor/src/index.ts
@@ -40,7 +40,6 @@ import { useEffect, useMemo } from "react";
import "./extensions";
import { AttachmentNode, AttachmentOptions } from "./extensions/attachment";
import BulletList from "./extensions/bullet-list";
-import { ClipboardTextSerializer } from "./extensions/clipboard-text-serializer";
import { CodeBlock } from "./extensions/code-block";
import { Codemark } from "./extensions/code-mark";
import { DateTime, DateTimeOptions } from "./extensions/date-time";
@@ -76,7 +75,6 @@ import { useToolbarStore } from "./toolbar/stores/toolbar-store";
import { DownloadOptions } from "./utils/downloader";
import { Heading } from "./extensions/heading";
import Clipboard, { ClipboardOptions } from "./extensions/clipboard";
-import { convertBrToParagraph } from "./utils/html";
import Blockquote from "./extensions/blockquote";
declare global {
@@ -147,14 +145,10 @@ const useTiptap = (
() => ({
enableCoreExtensions: false,
editorProps: {
- ...editorProps,
- transformPastedHTML(html) {
- return convertBrToParagraph(html).documentElement.outerHTML;
- }
+ ...editorProps
},
extensions: [
...CoreExtensions,
- ClipboardTextSerializer,
NodeViewSelectionNotifier,
SearchReplace,
TextStyle.extend({
diff --git a/packages/editor/src/utils/tests/__snapshots__/html.test.ts.snap b/packages/editor/src/utils/tests/__snapshots__/html.test.ts.snap
deleted file mode 100644
index 73d3cbdbd..000000000
--- a/packages/editor/src/utils/tests/__snapshots__/html.test.ts.snap
+++ /dev/null
@@ -1,45 +0,0 @@
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`convert br tags to paragraphs (
-
-A troll, they call me, but I have no wish
-to be associated with those dolls
-
-We lack religion, purpose, politics,
-and yet, we somehow manage to get by.
-
-) 1`] = `"A troll, they call me, but I have no wish
to be associated with those dolls
We lack religion, purpose, politics,
and yet, we somehow manage to get by.
"`;
-
-exports[`convert br tags to paragraphs (
- When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.
- Also when I share the selection to Notesnook via the share functionality from Android, I have the same issue.
-
- Device information:
- App version: 2.3.0
- Platform: android
- Model: OnePlus-CPH2409-31
- Pro: true
- Logged in: yes
-
- ) 1`] = `"When I try to paste something (e.g. email content) to a note, the styling is kept, which is good, but the newlines are removed.
Also when I share the selection to Notesnook via the share functionality from Android, I have the same issue.
Device information:
App version: 2.3.0
Platform: android
Model: OnePlus-CPH2409-31
Pro: true
Logged in: yes
"`;
-
-exports[`convert br tags to paragraphs (
- Why switch from Gmail?
-
- Not sacrificing features for more privacy, prefer using one app, in many public groups and channels (Telegram)
-
- LibreOffice Slow & buggy
-
- Switched to Brave for the better Android app, more private out of the box & unsure if uBlock Origin closes gap
-
- ) 1`] = `"Why switch from Gmail?
Not sacrificing features for more privacy, prefer using one app, in many public groups and channels (Telegram)
LibreOffice Slow & buggy
Switched to Brave for the better Android app, more private out of the box & unsure if uBlock Origin closes gap
"`;
-
-exports[`convert br tags to paragraphs (
) 1`] = `"
"`;
-
-exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
-
-exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
-
-exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;
-
-exports[`convert br tags to paragraphs (line 1
line 2
) 1`] = `"line 1
line 2
"`;