@wordpress/block-library
Version:
Block library for the WordPress editor.
104 lines (103 loc) • 3.73 kB
JavaScript
// packages/block-library/src/table-of-contents/hooks.js
import fastDeepEqual from "fast-deep-equal/es6";
import { useRegistry } from "@wordpress/data";
import { __unstableStripHTML as stripHTML } from "@wordpress/dom";
import { useEffect } from "@wordpress/element";
import { addQueryArgs, removeQueryArgs } from "@wordpress/url";
import { store as blockEditorStore } from "@wordpress/block-editor";
function getLatestHeadings(select, clientId) {
const {
getBlockAttributes,
getBlockName,
getBlocksByName,
getClientIdsOfDescendants
} = select(blockEditorStore);
const permalink = select("core/editor").getPermalink() ?? null;
const isPaginated = getBlocksByName("core/nextpage").length !== 0;
const { onlyIncludeCurrentPage, maxLevel } = getBlockAttributes(clientId) ?? {};
const [postContentClientId = ""] = getBlocksByName("core/post-content");
const allBlockClientIds = getClientIdsOfDescendants(postContentClientId);
let tocPage = 1;
if (isPaginated && onlyIncludeCurrentPage) {
const tocIndex = allBlockClientIds.indexOf(clientId);
for (const [
blockIndex,
blockClientId
] of allBlockClientIds.entries()) {
if (blockIndex >= tocIndex) {
break;
}
if (getBlockName(blockClientId) === "core/nextpage") {
tocPage++;
}
}
}
const latestHeadings = [];
let headingPage = 1;
let headingPageLink = null;
if (typeof permalink === "string") {
headingPageLink = isPaginated ? addQueryArgs(permalink, { page: headingPage }) : permalink;
}
for (const blockClientId of allBlockClientIds) {
const blockName = getBlockName(blockClientId);
if (blockName === "core/nextpage") {
headingPage++;
if (onlyIncludeCurrentPage && headingPage > tocPage) {
break;
}
if (typeof permalink === "string") {
headingPageLink = addQueryArgs(
removeQueryArgs(permalink, ["page"]),
{ page: headingPage }
);
}
} else if (!onlyIncludeCurrentPage || headingPage === tocPage) {
if (blockName === "core/heading") {
const headingAttributes = getBlockAttributes(blockClientId);
if (maxLevel && headingAttributes.level > maxLevel) {
continue;
}
const canBeLinked = typeof headingPageLink === "string" && typeof headingAttributes.anchor === "string" && headingAttributes.anchor !== "";
latestHeadings.push({
// Convert line breaks to spaces, and get rid of HTML tags in the headings.
content: stripHTML(
headingAttributes.content.replace(
/(<br *\/?>)+/g,
" "
)
),
level: headingAttributes.level,
link: canBeLinked ? `${headingPageLink}#${headingAttributes.anchor}` : null
});
}
}
}
return latestHeadings;
}
function observeCallback(select, dispatch, clientId) {
const { getBlockAttributes } = select(blockEditorStore);
const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } = dispatch(blockEditorStore);
const attributes = getBlockAttributes(clientId);
if (attributes === null) {
return;
}
const headings = getLatestHeadings(select, clientId);
if (!fastDeepEqual(headings, attributes.headings)) {
window.queueMicrotask(() => {
__unstableMarkNextChangeAsNotPersistent();
updateBlockAttributes(clientId, { headings });
});
}
}
function useObserveHeadings(clientId) {
const registry = useRegistry();
useEffect(() => {
return registry.subscribe(
() => observeCallback(registry.select, registry.dispatch, clientId)
);
}, [registry, clientId]);
}
export {
useObserveHeadings
};
//# sourceMappingURL=hooks.js.map