perf: Remove markdown serialize from editor render path (#3567)
* perf: Remove markdown serialize from editor render path * fix: Simplify heading equality check * perf: Add cache for slugified headings * tsc
This commit is contained in:
@@ -1,11 +1,23 @@
|
||||
import { EditorView } from "prosemirror-view";
|
||||
import { Node } from "prosemirror-model";
|
||||
import headingToSlug from "./headingToSlug";
|
||||
|
||||
export default function getHeadings(view: EditorView) {
|
||||
const headings: { title: string; level: number; id: string }[] = [];
|
||||
export type Heading = {
|
||||
title: string;
|
||||
level: number;
|
||||
id: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates through the document to find all of the headings and their level.
|
||||
*
|
||||
* @param doc Prosemirror document node
|
||||
* @returns Array<Heading>
|
||||
*/
|
||||
export default function getHeadings(doc: Node) {
|
||||
const headings: Heading[] = [];
|
||||
const previouslySeen = {};
|
||||
|
||||
view.state.doc.forEach((node) => {
|
||||
doc.forEach((node) => {
|
||||
if (node.type.name === "heading") {
|
||||
// calculate the optimal id
|
||||
const id = headingToSlug(node);
|
||||
|
||||
44
shared/editor/lib/getTasks.ts
Normal file
44
shared/editor/lib/getTasks.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Node } from "prosemirror-model";
|
||||
|
||||
export type Task = {
|
||||
text: string;
|
||||
completed: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates through the document to find all of the tasks and their completion
|
||||
* state.
|
||||
*
|
||||
* @param doc Prosemirror document node
|
||||
* @returns Array<Task>
|
||||
*/
|
||||
export default function getTasks(doc: Node): Task[] {
|
||||
const tasks: Task[] = [];
|
||||
|
||||
doc.descendants((node) => {
|
||||
if (!node.isBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.type.name === "checkbox_list") {
|
||||
node.content.forEach((listItem) => {
|
||||
let text = "";
|
||||
|
||||
listItem.forEach((contentNode) => {
|
||||
if (contentNode.type.name === "paragraph") {
|
||||
text += contentNode.textContent;
|
||||
}
|
||||
});
|
||||
|
||||
tasks.push({
|
||||
text,
|
||||
completed: listItem.attrs.checked,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return tasks;
|
||||
}
|
||||
@@ -2,16 +2,25 @@ import { escape } from "lodash";
|
||||
import { Node } from "prosemirror-model";
|
||||
import slugify from "slugify";
|
||||
|
||||
const cache = new Map<string, string>();
|
||||
|
||||
// Slugify, escape, and remove periods from headings so that they are
|
||||
// compatible with both url hashes AND dom ID's (querySelector does not like
|
||||
// ID's that begin with a number or a period, for example).
|
||||
function safeSlugify(text: string) {
|
||||
return `h-${escape(
|
||||
if (cache.has(text)) {
|
||||
return cache.get(text) as string;
|
||||
}
|
||||
|
||||
const slug = `h-${escape(
|
||||
slugify(text, {
|
||||
remove: /[!"#$%&'\.()*+,\/:;<=>?@\[\]\\^_`{|}~]/g,
|
||||
lower: true,
|
||||
})
|
||||
)}`;
|
||||
|
||||
cache.set(text, slug);
|
||||
return slug;
|
||||
}
|
||||
|
||||
// calculates a unique slug for this heading based on it's text and position
|
||||
|
||||
Reference in New Issue
Block a user