mirror of
https://github.com/outline/outline.git
synced 2026-05-08 02:50:30 -05:00
chore: Replace custom toPlainText serialization with leafText (#10039)
This commit is contained in:
@@ -143,7 +143,7 @@ export function exportTable({
|
||||
.map((row) =>
|
||||
row
|
||||
.map((cell) => {
|
||||
let value = ProsemirrorHelper.toPlainText(cell, state.schema);
|
||||
let value = ProsemirrorHelper.toPlainText(cell);
|
||||
|
||||
// Escape double quotes by doubling them
|
||||
if (value.includes('"')) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Node as ProseMirrorNode } from "prosemirror-model";
|
||||
import { PlainTextSerializer } from "../types";
|
||||
|
||||
/**
|
||||
* Returns the text content between two positions.
|
||||
@@ -7,25 +6,22 @@ import { PlainTextSerializer } from "../types";
|
||||
* @param doc The Prosemirror document to use
|
||||
* @param from A start point
|
||||
* @param to An end point
|
||||
* @param plainTextSerializers A map of node names to PlainTextSerializers which convert a node to plain text
|
||||
* @returns A string of plain text
|
||||
*/
|
||||
export default function textBetween(
|
||||
doc: ProseMirrorNode,
|
||||
from: number,
|
||||
to: number,
|
||||
plainTextSerializers: Record<string, PlainTextSerializer | undefined>
|
||||
to: number
|
||||
): string {
|
||||
let text = "";
|
||||
let first = true;
|
||||
const blockSeparator = "\n";
|
||||
|
||||
doc.nodesBetween(from, to, (node, pos) => {
|
||||
const toPlainText = plainTextSerializers[node.type.name];
|
||||
let nodeText = "";
|
||||
|
||||
if (toPlainText) {
|
||||
nodeText += toPlainText(node);
|
||||
if (node.type.spec.leafText) {
|
||||
nodeText += node.type.spec.leafText(node);
|
||||
} else if (node.isText) {
|
||||
nodeText += node.textBetween(
|
||||
Math.max(from, pos) - pos,
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Schema } from "prosemirror-model";
|
||||
|
||||
/**
|
||||
* Generate a map of text serializers for a given schema
|
||||
* @param schema
|
||||
* @returns Text serializers
|
||||
*/
|
||||
export function getTextSerializers(schema: Schema) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(schema.nodes)
|
||||
.filter(([, node]) => node.spec.toPlainText)
|
||||
.map(([name, node]) => [name, node.spec.toPlainText])
|
||||
);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ export default class Attachment extends Node {
|
||||
},
|
||||
String(node.attrs.title),
|
||||
],
|
||||
toPlainText: (node) => node.attrs.title,
|
||||
leafText: (node) => node.attrs.title,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ export default class Embed extends Node {
|
||||
];
|
||||
}
|
||||
},
|
||||
toPlainText: (node) => node.attrs.href,
|
||||
leafText: (node) => node.attrs.href,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export default class Emoji extends Extension {
|
||||
getEmojiFromName(name),
|
||||
];
|
||||
},
|
||||
toPlainText: (node) => getEmojiFromName(node.attrs["data-name"]),
|
||||
leafText: (node) => getEmojiFromName(node.attrs["data-name"]),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class HardBreak extends Node {
|
||||
selectable: false,
|
||||
parseDOM: [{ tag: "br" }],
|
||||
toDOM: () => ["br"],
|
||||
toPlainText: () => "\n",
|
||||
leafText: () => "\n",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ export default class Image extends SimpleImage {
|
||||
...children,
|
||||
];
|
||||
},
|
||||
toPlainText: (node) =>
|
||||
leafText: (node) =>
|
||||
node.attrs.alt ? `(image: ${node.attrs.alt})` : "(image)",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,7 +119,6 @@ export default class Mention extends Node {
|
||||
},
|
||||
toPlainText(node),
|
||||
],
|
||||
toPlainText,
|
||||
leafText: toPlainText,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export default class Video extends Node {
|
||||
String(node.attrs.title),
|
||||
],
|
||||
],
|
||||
toPlainText: (node) => node.attrs.title,
|
||||
leafText: (node) => node.attrs.title,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
-7
@@ -8,11 +8,4 @@ declare module "prosemirror-model" {
|
||||
// https://github.com/ProseMirror/prosemirror-model/blob/bd13a2329fda39f1c4d09abd8f0db2032bdc8014/src/replace.js#L51
|
||||
removeBetween(from: number, to: number): Slice;
|
||||
}
|
||||
|
||||
interface NodeSpec {
|
||||
/**
|
||||
* Defines the text representation of the node when copying to clipboard.
|
||||
*/
|
||||
toPlainText?: PlainTextSerializer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Node, Schema } from "prosemirror-model";
|
||||
import headingToSlug from "../editor/lib/headingToSlug";
|
||||
import textBetween from "../editor/lib/textBetween";
|
||||
import { getTextSerializers } from "../editor/lib/textSerializers";
|
||||
import { ProsemirrorData } from "../types";
|
||||
import { TextHelper } from "./TextHelper";
|
||||
import env from "../env";
|
||||
@@ -91,9 +90,8 @@ export class ProsemirrorHelper {
|
||||
* @param schema The schema to use.
|
||||
* @returns The document content as plain text without formatting.
|
||||
*/
|
||||
static toPlainText(root: Node, schema: Schema) {
|
||||
const textSerializers = getTextSerializers(schema);
|
||||
return textBetween(root, 0, root.content.size, textSerializers);
|
||||
static toPlainText(root: Node) {
|
||||
return textBetween(root, 0, root.content.size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +100,6 @@ export class ProsemirrorHelper {
|
||||
* @returns True if the editor is empty
|
||||
*/
|
||||
static trim(doc: Node) {
|
||||
const { schema } = doc.type;
|
||||
let index = 0,
|
||||
start = 0,
|
||||
end = doc.nodeSize - 2,
|
||||
@@ -118,7 +115,7 @@ export class ProsemirrorHelper {
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node, schema).trim() === "";
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node).trim() === "";
|
||||
if (isEmpty) {
|
||||
start += node.nodeSize;
|
||||
}
|
||||
@@ -131,7 +128,7 @@ export class ProsemirrorHelper {
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node, schema).trim() === "";
|
||||
isEmpty = ProsemirrorHelper.toPlainText(node).trim() === "";
|
||||
if (isEmpty) {
|
||||
end -= node.nodeSize;
|
||||
}
|
||||
@@ -150,8 +147,6 @@ export class ProsemirrorHelper {
|
||||
return !doc || doc.textContent.trim() === "";
|
||||
}
|
||||
|
||||
const textSerializers = getTextSerializers(schema);
|
||||
|
||||
let empty = true;
|
||||
doc.descendants((child: Node) => {
|
||||
// If we've already found non-empty data, we can stop descending further
|
||||
@@ -159,9 +154,8 @@ export class ProsemirrorHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
const toPlainText = textSerializers[child.type.name];
|
||||
if (toPlainText) {
|
||||
empty = !toPlainText(child).trim();
|
||||
if (child.type.spec.leafText) {
|
||||
empty = !child.type.spec.leafText(child).trim();
|
||||
} else if (child.isText) {
|
||||
empty = !child.text?.trim();
|
||||
}
|
||||
@@ -331,10 +325,9 @@ export class ProsemirrorHelper {
|
||||
* Iterates through the document to find all of the headings and their level.
|
||||
*
|
||||
* @param doc Prosemirror document node
|
||||
* @param schema Prosemirror schema
|
||||
* @returns Array<Heading>
|
||||
*/
|
||||
static getHeadings(doc: Node, schema: Schema) {
|
||||
static getHeadings(doc: Node) {
|
||||
const headings: Heading[] = [];
|
||||
const previouslySeen: Record<string, number> = {};
|
||||
|
||||
@@ -356,7 +349,7 @@ export class ProsemirrorHelper {
|
||||
previouslySeen[id] !== undefined ? previouslySeen[id] + 1 : 1;
|
||||
|
||||
headings.push({
|
||||
title: ProsemirrorHelper.toPlainText(node, schema),
|
||||
title: ProsemirrorHelper.toPlainText(node),
|
||||
level: node.attrs.level,
|
||||
id: name,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user