UNPKG

@wordpress/editor

Version:
266 lines (257 loc) 9.59 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.PageAttributesParent = PageAttributesParent; exports.ParentRow = ParentRow; exports.getItemPriority = exports.default = void 0; var _removeAccents = _interopRequireDefault(require("remove-accents")); var _i18n = require("@wordpress/i18n"); var _components = require("@wordpress/components"); var _compose = require("@wordpress/compose"); var _element = require("@wordpress/element"); var _data = require("@wordpress/data"); var _htmlEntities = require("@wordpress/html-entities"); var _coreData = require("@wordpress/core-data"); var _blockEditor = require("@wordpress/block-editor"); var _url = require("@wordpress/url"); var _postPanelRow = _interopRequireDefault(require("../post-panel-row")); var _terms = require("../../utils/terms"); var _store = require("../../store"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ function getTitle(post) { return post?.title?.rendered ? (0, _htmlEntities.decodeEntities)(post.title.rendered) : `#${post.id} (${(0, _i18n.__)('no title')})`; } const getItemPriority = (name, searchValue) => { const normalizedName = (0, _removeAccents.default)(name || '').toLowerCase(); const normalizedSearch = (0, _removeAccents.default)(searchValue || '').toLowerCase(); if (normalizedName === normalizedSearch) { return 0; } if (normalizedName.startsWith(normalizedSearch)) { return normalizedName.length; } return Infinity; }; /** * Renders the Page Attributes Parent component. A dropdown menu in an editor interface * for selecting the parent page of a given page. * * @return {Component|null} The component to be rendered. Return null if post type is not hierarchical. */ exports.getItemPriority = getItemPriority; function PageAttributesParent() { const { editPost } = (0, _data.useDispatch)(_store.store); const [fieldValue, setFieldValue] = (0, _element.useState)(false); const { isHierarchical, parentPostId, parentPostTitle, pageItems } = (0, _data.useSelect)(select => { var _pType$hierarchical; const { getPostType, getEntityRecords, getEntityRecord } = select(_coreData.store); const { getCurrentPostId, getEditedPostAttribute } = select(_store.store); const postTypeSlug = getEditedPostAttribute('type'); const pageId = getEditedPostAttribute('parent'); const pType = getPostType(postTypeSlug); const postId = getCurrentPostId(); const postIsHierarchical = (_pType$hierarchical = pType?.hierarchical) !== null && _pType$hierarchical !== void 0 ? _pType$hierarchical : false; const query = { per_page: 100, exclude: postId, parent_exclude: postId, orderby: 'menu_order', order: 'asc', _fields: 'id,title,parent' }; // Perform a search when the field is changed. if (!!fieldValue) { query.search = fieldValue; } const parentPost = pageId ? getEntityRecord('postType', postTypeSlug, pageId) : null; return { isHierarchical: postIsHierarchical, parentPostId: pageId, parentPostTitle: parentPost ? getTitle(parentPost) : '', pageItems: postIsHierarchical ? getEntityRecords('postType', postTypeSlug, query) : null }; }, [fieldValue]); const parentOptions = (0, _element.useMemo)(() => { const getOptionsFromTree = (tree, level = 0) => { const mappedNodes = tree.map(treeNode => [{ value: treeNode.id, label: '— '.repeat(level) + (0, _htmlEntities.decodeEntities)(treeNode.name), rawName: treeNode.name }, ...getOptionsFromTree(treeNode.children || [], level + 1)]); const sortedNodes = mappedNodes.sort(([a], [b]) => { const priorityA = getItemPriority(a.rawName, fieldValue); const priorityB = getItemPriority(b.rawName, fieldValue); return priorityA >= priorityB ? 1 : -1; }); return sortedNodes.flat(); }; if (!pageItems) { return []; } let tree = pageItems.map(item => ({ id: item.id, parent: item.parent, name: getTitle(item) })); // Only build a hierarchical tree when not searching. if (!fieldValue) { tree = (0, _terms.buildTermsTree)(tree); } const opts = getOptionsFromTree(tree); // Ensure the current parent is in the options list. const optsHasParent = opts.find(item => item.value === parentPostId); if (parentPostTitle && !optsHasParent) { opts.unshift({ value: parentPostId, label: parentPostTitle }); } return opts; }, [pageItems, fieldValue, parentPostTitle, parentPostId]); if (!isHierarchical) { return null; } /** * Handle user input. * * @param {string} inputValue The current value of the input field. */ const handleKeydown = inputValue => { setFieldValue(inputValue); }; /** * Handle author selection. * * @param {Object} selectedPostId The selected Author. */ const handleChange = selectedPostId => { editPost({ parent: selectedPostId }); }; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ComboboxControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, className: "editor-page-attributes__parent", label: (0, _i18n.__)('Parent'), help: (0, _i18n.__)('Choose a parent page.'), value: parentPostId, options: parentOptions, onFilterValueChange: (0, _compose.debounce)(handleKeydown, 300), onChange: handleChange, hideLabelFromVision: true }); } function PostParentToggle({ isOpen, onClick }) { const parentPost = (0, _data.useSelect)(select => { const { getEditedPostAttribute } = select(_store.store); const parentPostId = getEditedPostAttribute('parent'); if (!parentPostId) { return null; } const { getEntityRecord } = select(_coreData.store); const postTypeSlug = getEditedPostAttribute('type'); return getEntityRecord('postType', postTypeSlug, parentPostId); }, []); const parentTitle = (0, _element.useMemo)(() => !parentPost ? (0, _i18n.__)('None') : getTitle(parentPost), [parentPost]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { size: "compact", className: "editor-post-parent__panel-toggle", variant: "tertiary", "aria-expanded": isOpen // translators: %s: Current post parent. , "aria-label": (0, _i18n.sprintf)((0, _i18n.__)('Change parent: %s'), parentTitle), onClick: onClick, children: parentTitle }); } function ParentRow() { const homeUrl = (0, _data.useSelect)(select => { // Site index. return select(_coreData.store).getEntityRecord('root', '__unstableBase')?.home; }, []); // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. const [popoverAnchor, setPopoverAnchor] = (0, _element.useState)(null); // Memoize popoverProps to avoid returning a new object every time. const popoverProps = (0, _element.useMemo)(() => ({ // Anchor the popover to the middle of the entire row so that it doesn't // move around when the label changes. anchor: popoverAnchor, placement: 'left-start', offset: 36, shift: true }), [popoverAnchor]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_postPanelRow.default, { label: (0, _i18n.__)('Parent'), ref: setPopoverAnchor, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Dropdown, { popoverProps: popoverProps, className: "editor-post-parent__panel-dropdown", contentClassName: "editor-post-parent__panel-dialog", focusOnMount: true, renderToggle: ({ isOpen, onToggle }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(PostParentToggle, { isOpen: isOpen, onClick: onToggle }), renderContent: ({ onClose }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: "editor-post-parent", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalInspectorPopoverHeader, { title: (0, _i18n.__)('Parent'), onClose: onClose }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { children: [(0, _element.createInterpolateElement)((0, _i18n.sprintf)( /* translators: %1$s The home URL of the WordPress installation without the scheme. */ (0, _i18n.__)('Child pages inherit characteristics from their parent, such as URL structure. For instance, if "Pricing" is a child of "Services", its URL would be %1$s<wbr />/services<wbr />/pricing.'), (0, _url.filterURLForDisplay)(homeUrl).replace(/([/.])/g, '<wbr />$1')), { wbr: /*#__PURE__*/(0, _jsxRuntime.jsx)("wbr", {}) }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", { children: (0, _element.createInterpolateElement)((0, _i18n.__)('They also show up as sub-items in the default navigation menu. <a>Learn more.</a>'), { a: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, { href: (0, _i18n.__)('https://wordpress.org/documentation/article/page-post-settings-sidebar/#page-attributes') }) }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(PageAttributesParent, {})] }) }) }); } var _default = exports.default = PageAttributesParent; //# sourceMappingURL=parent.js.map