@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
149 lines (125 loc) • 4.72 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.DocumentOutline = void 0;
var _element = require("@wordpress/element");
var _lodash = require("lodash");
var _i18n = require("@wordpress/i18n");
var _compose = require("@wordpress/compose");
var _data = require("@wordpress/data");
var _richText = require("@wordpress/rich-text");
var _blockEditor = require("@wordpress/block-editor");
var _item = _interopRequireDefault(require("./item"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Module constants
*/
const emptyHeadingContent = (0, _element.createElement)("em", null, (0, _i18n.__)('(Empty heading)'));
const incorrectLevelContent = [(0, _element.createElement)("br", {
key: "incorrect-break"
}), (0, _element.createElement)("em", {
key: "incorrect-message"
}, (0, _i18n.__)('(Incorrect heading level)'))];
const singleH1Headings = [(0, _element.createElement)("br", {
key: "incorrect-break-h1"
}), (0, _element.createElement)("em", {
key: "incorrect-message-h1"
}, (0, _i18n.__)('(Your theme may already use a H1 for the post title)'))];
const multipleH1Headings = [(0, _element.createElement)("br", {
key: "incorrect-break-multiple-h1"
}), (0, _element.createElement)("em", {
key: "incorrect-message-multiple-h1"
}, (0, _i18n.__)('(Multiple H1 headings are not recommended)'))];
/**
* Returns an array of heading blocks enhanced with the following properties:
* level - An integer with the heading level.
* isEmpty - Flag indicating if the heading has no content.
*
* @param {?Array} blocks An array of blocks.
*
* @return {Array} An array of heading blocks enhanced with the properties described above.
*/
const computeOutlineHeadings = (blocks = []) => {
return (0, _lodash.flatMap)(blocks, (block = {}) => {
if (block.name === 'core/heading') {
return { ...block,
level: block.attributes.level,
isEmpty: isEmptyHeading(block)
};
}
return computeOutlineHeadings(block.innerBlocks);
});
};
const isEmptyHeading = heading => !heading.attributes.content || heading.attributes.content.length === 0;
const DocumentOutline = ({
blocks = [],
title,
onSelect,
isTitleSupported,
hasOutlineItemsDisabled
}) => {
const headings = computeOutlineHeadings(blocks);
if (headings.length < 1) {
return null;
}
let prevHeadingLevel = 1; // Not great but it's the simplest way to locate the title right now.
const titleNode = document.querySelector('.editor-post-title__input');
const hasTitle = isTitleSupported && title && titleNode;
const countByLevel = (0, _lodash.countBy)(headings, 'level');
const hasMultipleH1 = countByLevel[1] > 1;
return (0, _element.createElement)("div", {
className: "document-outline"
}, (0, _element.createElement)("ul", null, hasTitle && (0, _element.createElement)(_item.default, {
level: (0, _i18n.__)('Title'),
isValid: true,
onSelect: onSelect,
href: `#${titleNode.id}`,
isDisabled: hasOutlineItemsDisabled
}, title), headings.map((item, index) => {
// Headings remain the same, go up by one, or down by any amount.
// Otherwise there are missing levels.
const isIncorrectLevel = item.level > prevHeadingLevel + 1;
const isValid = !item.isEmpty && !isIncorrectLevel && !!item.level && (item.level !== 1 || !hasMultipleH1 && !hasTitle);
prevHeadingLevel = item.level;
return (0, _element.createElement)(_item.default, {
key: index,
level: `H${item.level}`,
isValid: isValid,
isDisabled: hasOutlineItemsDisabled,
href: `#block-${item.clientId}`,
onSelect: onSelect
}, item.isEmpty ? emptyHeadingContent : (0, _richText.getTextContent)((0, _richText.create)({
html: item.attributes.content
})), isIncorrectLevel && incorrectLevelContent, item.level === 1 && hasMultipleH1 && multipleH1Headings, hasTitle && item.level === 1 && !hasMultipleH1 && singleH1Headings);
})));
};
exports.DocumentOutline = DocumentOutline;
var _default = (0, _compose.compose)((0, _data.withSelect)(select => {
const {
getBlocks
} = select(_blockEditor.store);
const {
getEditedPostAttribute
} = select('core/editor');
const {
getPostType
} = select('core');
const postType = getPostType(getEditedPostAttribute('type'));
return {
title: getEditedPostAttribute('title'),
blocks: getBlocks(),
isTitleSupported: (0, _lodash.get)(postType, ['supports', 'title'], false)
};
}))(DocumentOutline);
exports.default = _default;
//# sourceMappingURL=index.js.map