UNPKG

@wordpress/block-library

Version:
621 lines (615 loc) 24.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = LatestPostsEdit; var _clsx = _interopRequireDefault(require("clsx")); var _components = require("@wordpress/components"); var _i18n = require("@wordpress/i18n"); var _date = require("@wordpress/date"); var _blockEditor = require("@wordpress/block-editor"); var _data = require("@wordpress/data"); var _icons = require("@wordpress/icons"); var _coreData = require("@wordpress/core-data"); var _notices = require("@wordpress/notices"); var _compose = require("@wordpress/compose"); var _element = require("@wordpress/element"); var _constants = require("./constants"); var _hooks = require("../utils/hooks"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ /** * Module Constants */const CATEGORIES_LIST_QUERY = { per_page: -1, _fields: 'id,name', context: 'view' }; const USERS_LIST_QUERY = { per_page: -1, has_published_posts: ['post'], context: 'view' }; const imageAlignmentOptions = [{ value: 'none', icon: _icons.alignNone, label: (0, _i18n.__)('None') }, { value: 'left', icon: _icons.positionLeft, label: (0, _i18n.__)('Left') }, { value: 'center', icon: _icons.positionCenter, label: (0, _i18n.__)('Center') }, { value: 'right', icon: _icons.positionRight, label: (0, _i18n.__)('Right') }]; function getFeaturedImageDetails(post, size) { var _image$media_details$; const image = post._embedded?.['wp:featuredmedia']?.['0']; return { url: (_image$media_details$ = image?.media_details?.sizes?.[size]?.source_url) !== null && _image$media_details$ !== void 0 ? _image$media_details$ : image?.source_url, alt: image?.alt_text }; } function getCurrentAuthor(post) { return post._embedded?.author?.[0]; } function Controls({ attributes, setAttributes, postCount }) { var _categoriesList$reduc; const { postsToShow, order, orderBy, categories, selectedAuthor, displayFeaturedImage, displayPostContentRadio, displayPostContent, displayPostDate, displayAuthor, postLayout, columns, excerptLength, featuredImageAlign, featuredImageSizeSlug, featuredImageSizeWidth, featuredImageSizeHeight, addLinkToFeaturedImage } = attributes; const { imageSizes, defaultImageWidth, defaultImageHeight, categoriesList, authorList } = (0, _data.useSelect)(select => { var _settings$imageDimens, _settings$imageDimens2; const { getEntityRecords, getUsers } = select(_coreData.store); const settings = select(_blockEditor.store).getSettings(); return { defaultImageWidth: (_settings$imageDimens = settings.imageDimensions?.[featuredImageSizeSlug]?.width) !== null && _settings$imageDimens !== void 0 ? _settings$imageDimens : 0, defaultImageHeight: (_settings$imageDimens2 = settings.imageDimensions?.[featuredImageSizeSlug]?.height) !== null && _settings$imageDimens2 !== void 0 ? _settings$imageDimens2 : 0, imageSizes: settings.imageSizes, categoriesList: getEntityRecords('taxonomy', 'category', CATEGORIES_LIST_QUERY), authorList: getUsers(USERS_LIST_QUERY) }; }, [featuredImageSizeSlug]); const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)(); const imageSizeOptions = imageSizes.filter(({ slug }) => slug !== 'full').map(({ name, slug }) => ({ value: slug, label: name })); const categorySuggestions = (_categoriesList$reduc = categoriesList?.reduce((accumulator, category) => ({ ...accumulator, [category.name]: category }), {})) !== null && _categoriesList$reduc !== void 0 ? _categoriesList$reduc : {}; const selectCategories = tokens => { const hasNoSuggestion = tokens.some(token => typeof token === 'string' && !categorySuggestions[token]); if (hasNoSuggestion) { return; } // Categories that are already will be objects, while new additions will be strings (the name). // allCategories nomalizes the array so that they are all objects. const allCategories = tokens.map(token => { return typeof token === 'string' ? categorySuggestions[token] : token; }); // We do nothing if the category is not selected // from suggestions. if (allCategories.includes(null)) { return false; } setAttributes({ categories: allCategories }); }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Post content'), resetAll: () => setAttributes({ displayPostContent: false, displayPostContentRadio: 'excerpt', excerptLength: _constants.DEFAULT_EXCERPT_LENGTH }), dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!displayPostContent, label: (0, _i18n.__)('Display post content'), onDeselect: () => setAttributes({ displayPostContent: false }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Display post content'), checked: displayPostContent, onChange: value => setAttributes({ displayPostContent: value }) }) }), displayPostContent && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => displayPostContentRadio !== 'excerpt', label: (0, _i18n.__)('Content length'), onDeselect: () => setAttributes({ displayPostContentRadio: 'excerpt' }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RadioControl, { label: (0, _i18n.__)('Content length'), selected: displayPostContentRadio, options: [{ label: (0, _i18n.__)('Excerpt'), value: 'excerpt' }, { label: (0, _i18n.__)('Full post'), value: 'full_post' }], onChange: value => setAttributes({ displayPostContentRadio: value }) }) }), displayPostContent && displayPostContentRadio === 'excerpt' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => excerptLength !== _constants.DEFAULT_EXCERPT_LENGTH, label: (0, _i18n.__)('Max number of words'), onDeselect: () => setAttributes({ excerptLength: _constants.DEFAULT_EXCERPT_LENGTH }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, label: (0, _i18n.__)('Max number of words'), value: excerptLength, onChange: value => setAttributes({ excerptLength: value }), min: _constants.MIN_EXCERPT_LENGTH, max: _constants.MAX_EXCERPT_LENGTH }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Post meta'), resetAll: () => setAttributes({ displayAuthor: false, displayPostDate: false }), dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!displayAuthor, label: (0, _i18n.__)('Display author name'), onDeselect: () => setAttributes({ displayAuthor: false }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Display author name'), checked: displayAuthor, onChange: value => setAttributes({ displayAuthor: value }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!displayPostDate, label: (0, _i18n.__)('Display post date'), onDeselect: () => setAttributes({ displayPostDate: false }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Display post date'), checked: displayPostDate, onChange: value => setAttributes({ displayPostDate: value }) }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Featured image'), resetAll: () => setAttributes({ displayFeaturedImage: false, featuredImageAlign: undefined, featuredImageSizeSlug: 'thumbnail', featuredImageSizeWidth: null, featuredImageSizeHeight: null, addLinkToFeaturedImage: false }), dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!displayFeaturedImage, label: (0, _i18n.__)('Display featured image'), onDeselect: () => setAttributes({ displayFeaturedImage: false }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Display featured image'), checked: displayFeaturedImage, onChange: value => setAttributes({ displayFeaturedImage: value }) }) }), displayFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => featuredImageSizeSlug !== 'thumbnail' || featuredImageSizeWidth !== null || featuredImageSizeHeight !== null, label: (0, _i18n.__)('Image size'), onDeselect: () => setAttributes({ featuredImageSizeSlug: 'thumbnail', featuredImageSizeWidth: null, featuredImageSizeHeight: null }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalImageSizeControl, { onChange: value => { const newAttrs = {}; if (value.hasOwnProperty('width')) { newAttrs.featuredImageSizeWidth = value.width; } if (value.hasOwnProperty('height')) { newAttrs.featuredImageSizeHeight = value.height; } setAttributes(newAttrs); }, slug: featuredImageSizeSlug, width: featuredImageSizeWidth, height: featuredImageSizeHeight, imageWidth: defaultImageWidth, imageHeight: defaultImageHeight, imageSizeOptions: imageSizeOptions, imageSizeHelp: (0, _i18n.__)('Select the size of the source image.'), onChangeImage: value => setAttributes({ featuredImageSizeSlug: value, featuredImageSizeWidth: undefined, featuredImageSizeHeight: undefined }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!featuredImageAlign, label: (0, _i18n.__)('Image alignment'), onDeselect: () => setAttributes({ featuredImageAlign: undefined }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControl, { className: "editor-latest-posts-image-alignment-control", __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, label: (0, _i18n.__)('Image alignment'), value: featuredImageAlign || 'none', onChange: value => setAttributes({ featuredImageAlign: value !== 'none' ? value : undefined }), children: imageAlignmentOptions.map(({ value, icon, label }) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControlOptionIcon, { value: value, icon: icon, label: label }, value); }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!addLinkToFeaturedImage, label: (0, _i18n.__)('Add link to featured image'), onDeselect: () => setAttributes({ addLinkToFeaturedImage: false }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Add link to featured image'), checked: addLinkToFeaturedImage, onChange: value => setAttributes({ addLinkToFeaturedImage: value }) }) })] })] }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Sorting and filtering'), resetAll: () => setAttributes({ order: 'desc', orderBy: 'date', postsToShow: 5, categories: undefined, selectedAuthor: undefined, columns: 3 }), dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => order !== 'desc' || orderBy !== 'date' || postsToShow !== 5 || categories?.length > 0 || !!selectedAuthor, label: (0, _i18n.__)('Sort and filter'), onDeselect: () => setAttributes({ order: 'desc', orderBy: 'date', postsToShow: 5, categories: undefined, selectedAuthor: undefined }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.QueryControls, { order, orderBy, numberOfItems: postsToShow, onOrderChange: value => setAttributes({ order: value }), onOrderByChange: value => setAttributes({ orderBy: value }), onNumberOfItemsChange: value => setAttributes({ postsToShow: value }), categorySuggestions: categorySuggestions, onCategoryChange: selectCategories, selectedCategories: categories, onAuthorChange: value => setAttributes({ selectedAuthor: '' !== value ? Number(value) : undefined }), authorList: authorList !== null && authorList !== void 0 ? authorList : [], selectedAuthorId: selectedAuthor }) }), postLayout === 'grid' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => columns !== 3, label: (0, _i18n.__)('Columns'), onDeselect: () => setAttributes({ columns: 3 }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, label: (0, _i18n.__)('Columns'), value: columns, onChange: value => setAttributes({ columns: value }), min: 2, max: !postCount ? _constants.MAX_POSTS_COLUMNS : Math.min(_constants.MAX_POSTS_COLUMNS, postCount), required: true }) })] })] }); } function LatestPostsEdit({ attributes, setAttributes }) { var _latestPosts$length; const instanceId = (0, _compose.useInstanceId)(LatestPostsEdit); const { postsToShow, order, orderBy, categories, selectedAuthor, displayFeaturedImage, displayPostContentRadio, displayPostContent, displayPostDate, displayAuthor, postLayout, columns, excerptLength, featuredImageAlign, featuredImageSizeSlug, featuredImageSizeWidth, featuredImageSizeHeight, addLinkToFeaturedImage } = attributes; const { latestPosts } = (0, _data.useSelect)(select => { const { getEntityRecords } = select(_coreData.store); const catIds = categories && categories.length > 0 ? categories.map(cat => cat.id) : []; const latestPostsQuery = Object.fromEntries(Object.entries({ categories: catIds, author: selectedAuthor, order, orderby: orderBy, per_page: postsToShow, _embed: 'author,wp:featuredmedia', ignore_sticky: true }).filter(([, value]) => typeof value !== 'undefined')); return { latestPosts: getEntityRecords('postType', 'post', latestPostsQuery) }; }, [postsToShow, order, orderBy, categories, selectedAuthor]); // If a user clicks to a link prevent redirection and show a warning. const { createWarningNotice } = (0, _data.useDispatch)(_notices.store); const showRedirectionPreventedNotice = event => { event.preventDefault(); createWarningNotice((0, _i18n.__)('Links are disabled in the editor.'), { id: `block-library/core/latest-posts/redirection-prevented/${instanceId}`, type: 'snackbar' }); }; const hasPosts = !!latestPosts?.length; const inspectorControls = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Controls, { attributes: attributes, setAttributes: setAttributes, postCount: (_latestPosts$length = latestPosts?.length) !== null && _latestPosts$length !== void 0 ? _latestPosts$length : 0 }) }); const blockProps = (0, _blockEditor.useBlockProps)({ className: (0, _clsx.default)({ 'wp-block-latest-posts__list': true, 'is-grid': postLayout === 'grid', 'has-dates': displayPostDate, 'has-author': displayAuthor, [`columns-${columns}`]: postLayout === 'grid' }) }); if (!hasPosts) { return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { ...blockProps, children: [inspectorControls, /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Placeholder, { icon: _icons.pin, label: (0, _i18n.__)('Latest Posts'), children: !Array.isArray(latestPosts) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {}) : (0, _i18n.__)('No posts found.') })] }); } // Removing posts from display should be instant. const displayPosts = latestPosts.length > postsToShow ? latestPosts.slice(0, postsToShow) : latestPosts; const layoutControls = [{ icon: _icons.list, title: (0, _i18n._x)('List view', 'Latest posts block display setting'), onClick: () => setAttributes({ postLayout: 'list' }), isActive: postLayout === 'list' }, { icon: _icons.grid, title: (0, _i18n._x)('Grid view', 'Latest posts block display setting'), onClick: () => setAttributes({ postLayout: 'grid' }), isActive: postLayout === 'grid' }]; const dateFormat = (0, _date.getSettings)().formats.date; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [inspectorControls, /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarGroup, { controls: layoutControls }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", { ...blockProps, children: displayPosts.map(post => { const titleTrimmed = post.title.rendered.trim(); let excerpt = post.excerpt.rendered; const currentAuthor = getCurrentAuthor(post); const excerptElement = document.createElement('div'); excerptElement.innerHTML = excerpt; excerpt = excerptElement.textContent || excerptElement.innerText || ''; const { url: imageSourceUrl, alt: featuredImageAlt } = getFeaturedImageDetails(post, featuredImageSizeSlug); const imageClasses = (0, _clsx.default)({ 'wp-block-latest-posts__featured-image': true, [`align${featuredImageAlign}`]: !!featuredImageAlign }); const renderFeaturedImage = displayFeaturedImage && imageSourceUrl; const featuredImage = renderFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)("img", { src: imageSourceUrl, alt: featuredImageAlt, style: { maxWidth: featuredImageSizeWidth, maxHeight: featuredImageSizeHeight } }); const needsReadMore = excerptLength < excerpt.trim().split(' ').length && post.excerpt.raw === ''; const postExcerpt = needsReadMore ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [excerpt.trim().split(' ', excerptLength).join(' '), (0, _element.createInterpolateElement)((0, _i18n.sprintf)(/* translators: 1: Hidden accessibility text: Post title */ (0, _i18n.__)('… <a>Read more<span>: %1$s</span></a>'), titleTrimmed || (0, _i18n.__)('(no title)')), { a: /*#__PURE__*/ // eslint-disable-next-line jsx-a11y/anchor-has-content (0, _jsxRuntime.jsx)("a", { className: "wp-block-latest-posts__read-more", href: post.link, rel: "noopener noreferrer", onClick: showRedirectionPreventedNotice }), span: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "screen-reader-text" }) })] }) : excerpt; return /*#__PURE__*/(0, _jsxRuntime.jsxs)("li", { children: [renderFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: imageClasses, children: addLinkToFeaturedImage ? /*#__PURE__*/(0, _jsxRuntime.jsx)("a", { href: post.link, rel: "noreferrer noopener", onClick: showRedirectionPreventedNotice, children: featuredImage }) : featuredImage }), /*#__PURE__*/(0, _jsxRuntime.jsx)("a", { className: "wp-block-latest-posts__post-title", href: post.link, rel: "noreferrer noopener", dangerouslySetInnerHTML: !!titleTrimmed ? { __html: titleTrimmed } : undefined, onClick: showRedirectionPreventedNotice, children: !titleTrimmed ? (0, _i18n.__)('(no title)') : null }), displayAuthor && currentAuthor && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "wp-block-latest-posts__post-author", children: (0, _i18n.sprintf)(/* translators: byline. %s: author. */ (0, _i18n.__)('by %s'), currentAuthor.name) }), displayPostDate && post.date_gmt && /*#__PURE__*/(0, _jsxRuntime.jsx)("time", { dateTime: (0, _date.format)('c', post.date_gmt), className: "wp-block-latest-posts__post-date", children: (0, _date.dateI18n)(dateFormat, post.date_gmt) }), displayPostContent && displayPostContentRadio === 'excerpt' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "wp-block-latest-posts__post-excerpt", children: postExcerpt }), displayPostContent && displayPostContentRadio === 'full_post' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "wp-block-latest-posts__post-full-content", dangerouslySetInnerHTML: { __html: post.content.raw.trim() } })] }, post.id); }) })] }); } //# sourceMappingURL=edit.js.map