fix: Draft comment on text gets into a strange state when unfocused (#5153)
This commit is contained in:
184
server/utils/ProsemirrorHelper.test.ts
Normal file
184
server/utils/ProsemirrorHelper.test.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { Node } from "prosemirror-model";
|
||||
import ProsemirrorHelper from "@shared/utils/ProsemirrorHelper";
|
||||
import { schema } from "@server/editor";
|
||||
|
||||
// Note: The test is here rather than shared to access the schema
|
||||
describe("#ProsemirrorHelper", () => {
|
||||
describe("#trim", () => {
|
||||
it("Does not remove single paragraph", () => {
|
||||
const doc = Node.fromJSON(schema, {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(ProsemirrorHelper.trim(doc).toJSON()).toEqual({
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("Removes empty first paragraph", () => {
|
||||
const doc = Node.fromJSON(schema, {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "one",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(ProsemirrorHelper.trim(doc).toJSON()).toEqual({
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "one",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("Removes empty last paragraph", () => {
|
||||
const doc = Node.fromJSON(schema, {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "nice",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(ProsemirrorHelper.trim(doc).toJSON()).toEqual({
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "nice",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("Removes multiple empty paragraphs", () => {
|
||||
const doc = Node.fromJSON(schema, {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "nice",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: " ",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(ProsemirrorHelper.trim(doc).toJSON()).toEqual({
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "nice",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -49,20 +49,42 @@ export default class ProsemirrorHelper {
|
||||
* @returns True if the editor is empty
|
||||
*/
|
||||
static trim(doc: Node) {
|
||||
const first = doc.firstChild;
|
||||
const last = doc.lastChild;
|
||||
const firstIsEmpty =
|
||||
first &&
|
||||
ProsemirrorHelper.toPlainText(first, doc.type.schema).trim() === "";
|
||||
const lastIsEmpty =
|
||||
last &&
|
||||
ProsemirrorHelper.toPlainText(last, doc.type.schema).trim() === "";
|
||||
const firstIsLast = first === last;
|
||||
const { schema } = doc.type;
|
||||
let index = 0,
|
||||
start = 0,
|
||||
end = doc.nodeSize - 2,
|
||||
isEmpty;
|
||||
|
||||
return doc.cut(
|
||||
firstIsEmpty ? first.nodeSize : 0,
|
||||
lastIsEmpty && !firstIsLast ? doc.nodeSize - last.nodeSize : undefined
|
||||
);
|
||||
if (doc.childCount <= 1) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
isEmpty = true;
|
||||
while (isEmpty) {
|
||||
const node = doc.maybeChild(index++);
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node, schema).trim() === "";
|
||||
if (isEmpty) {
|
||||
start += node.nodeSize;
|
||||
}
|
||||
}
|
||||
|
||||
index = doc.childCount - 1;
|
||||
isEmpty = true;
|
||||
while (isEmpty) {
|
||||
const node = doc.maybeChild(index--);
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node, schema).trim() === "";
|
||||
if (isEmpty) {
|
||||
end -= node.nodeSize;
|
||||
}
|
||||
}
|
||||
|
||||
return doc.cut(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user