summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/extensions/blocks/related-posts/edit.js')
-rw-r--r--plugins/jetpack/extensions/blocks/related-posts/edit.js252
1 files changed, 252 insertions, 0 deletions
diff --git a/plugins/jetpack/extensions/blocks/related-posts/edit.js b/plugins/jetpack/extensions/blocks/related-posts/edit.js
new file mode 100644
index 00000000..7de102f4
--- /dev/null
+++ b/plugins/jetpack/extensions/blocks/related-posts/edit.js
@@ -0,0 +1,252 @@
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { BlockControls, InspectorControls } from '@wordpress/editor';
+import { PanelBody, RangeControl, ToggleControl, Toolbar, Path, SVG } from '@wordpress/components';
+import { Component, Fragment } from '@wordpress/element';
+import { get } from 'lodash';
+import { withSelect } from '@wordpress/data';
+import { compose, withInstanceId } from '@wordpress/compose';
+
+export const MAX_POSTS_TO_SHOW = 6;
+
+function PlaceholderPostEdit( props ) {
+ return (
+ <div
+ className="jp-related-posts-i2__post"
+ id={ props.id }
+ aria-labelledby={ props.id + '-heading' }
+ >
+ <strong id={ props.id + '-heading' } className="jp-related-posts-i2__post-link">
+ { __(
+ "Preview unavailable: you haven't published enough posts with similar content.",
+ 'jetpack'
+ ) }
+ </strong>
+ { props.displayThumbnails && (
+ <figure
+ className="jp-related-posts-i2__post-image-placeholder"
+ aria-label={ __( 'Placeholder image', 'jetpack' ) }
+ >
+ <SVG
+ className="jp-related-posts-i2__post-image-placeholder-square"
+ xmlns="http://www.w3.org/2000/svg"
+ width="100%"
+ height="100%"
+ viewBox="0 0 350 200"
+ >
+ <title>{ __( 'Grey square', 'jetpack' ) }</title>
+ <Path d="M0 0h350v200H0z" fill="#8B8B96" fill-opacity=".1" />
+ </SVG>
+ <SVG
+ className="jp-related-posts-i2__post-image-placeholder-icon"
+ xmlns="http://www.w3.org/2000/svg"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ >
+ <title>{ __( 'Icon for image', 'jetpack' ) }</title>
+ <Path fill="none" d="M0 0h24v24H0V0z" />
+ <Path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86l-3 3.87L9 13.14 6 17h12l-3.86-5.14z" />
+ </SVG>
+ </figure>
+ ) }
+
+ { props.displayDate && (
+ <div className="jp-related-posts-i2__post-date has-small-font-size">
+ { __( 'August 3, 2018', 'jetpack' ) }
+ </div>
+ ) }
+ { props.displayContext && (
+ <div className="jp-related-posts-i2__post-context has-small-font-size">
+ { __( 'In “Uncategorized”', 'jetpack' ) }
+ </div>
+ ) }
+ </div>
+ );
+}
+
+function RelatedPostsEditItem( props ) {
+ return (
+ <div
+ className="jp-related-posts-i2__post"
+ id={ props.id }
+ aria-labelledby={ props.id + '-heading' }
+ >
+ <a
+ className="jp-related-posts-i2__post-link"
+ id={ props.id + '-heading' }
+ href={ props.post.url }
+ rel="nofollow noopener noreferrer"
+ target="_blank"
+ >
+ { props.post.title }
+ </a>
+ { props.displayThumbnails && props.post.img && props.post.img.src && (
+ <a className="jp-related-posts-i2__post-img-link" href={ props.post.url }>
+ <img
+ className="jp-related-posts-i2__post-img"
+ src={ props.post.img.src }
+ alt={ props.post.title }
+ rel="nofollow noopener noreferrer"
+ target="_blank"
+ />
+ </a>
+ ) }
+ { props.displayDate && (
+ <div className="jp-related-posts-i2__post-date has-small-font-size">
+ { props.post.date }
+ </div>
+ ) }
+ { props.displayContext && (
+ <div className="jp-related-posts-i2__post-context has-small-font-size">
+ { props.post.context }
+ </div>
+ ) }
+ </div>
+ );
+}
+
+function RelatedPostsPreviewRows( props ) {
+ const className = 'jp-related-posts-i2__row';
+
+ let topRowEnd = 0;
+ const displayLowerRow = props.posts.length > 3;
+
+ switch ( props.posts.length ) {
+ case 2:
+ case 4:
+ case 5:
+ topRowEnd = 2;
+ break;
+ default:
+ topRowEnd = 3;
+ break;
+ }
+
+ return (
+ <div>
+ <div className={ className } data-post-count={ props.posts.slice( 0, topRowEnd ).length }>
+ { props.posts.slice( 0, topRowEnd ) }
+ </div>
+ { displayLowerRow && (
+ <div className={ className } data-post-count={ props.posts.slice( topRowEnd ).length }>
+ { props.posts.slice( topRowEnd ) }
+ </div>
+ ) }
+ </div>
+ );
+}
+
+class RelatedPostsEdit extends Component {
+ render() {
+ const { attributes, className, posts, setAttributes, instanceId } = this.props;
+ const { displayContext, displayDate, displayThumbnails, postLayout, postsToShow } = attributes;
+
+ const layoutControls = [
+ {
+ icon: 'grid-view',
+ title: __( 'Grid View', 'jetpack' ),
+ onClick: () => setAttributes( { postLayout: 'grid' } ),
+ isActive: postLayout === 'grid',
+ },
+ {
+ icon: 'list-view',
+ title: __( 'List View', 'jetpack' ),
+ onClick: () => setAttributes( { postLayout: 'list' } ),
+ isActive: postLayout === 'list',
+ },
+ ];
+
+ // To prevent the block from crashing, we need to limit ourselves to the
+ // posts returned by the backend - so if we want 6 posts, but only 3 are
+ // returned, we need to limit ourselves to those 3 and fill in the rest
+ // with placeholders.
+ //
+ // Also, if the site does not have sufficient posts to display related ones
+ // (minimum 10 posts), we also use this code block to fill in the
+ // placeholders.
+ const previewClassName = 'jp-relatedposts-i2';
+ const displayPosts = [];
+ for ( let i = 0; i < postsToShow; i++ ) {
+ if ( posts[ i ] ) {
+ displayPosts.push(
+ <RelatedPostsEditItem
+ id={ `related-posts-${ instanceId }-post-${ i }` }
+ key={ previewClassName + '-' + i }
+ post={ posts[ i ] }
+ displayThumbnails={ displayThumbnails }
+ displayDate={ displayDate }
+ displayContext={ displayContext }
+ />
+ );
+ } else {
+ displayPosts.push(
+ <PlaceholderPostEdit
+ id={ `related-posts-${ instanceId }-post-${ i }` }
+ key={ 'related-post-placeholder-' + i }
+ displayThumbnails={ displayThumbnails }
+ displayDate={ displayDate }
+ displayContext={ displayContext }
+ />
+ );
+ }
+ }
+
+ return (
+ <Fragment>
+ <InspectorControls>
+ <PanelBody title={ __( 'Related Posts Settings', 'jetpack' ) }>
+ <ToggleControl
+ label={ __( 'Display thumbnails', 'jetpack' ) }
+ checked={ displayThumbnails }
+ onChange={ value => setAttributes( { displayThumbnails: value } ) }
+ />
+ <ToggleControl
+ label={ __( 'Display date', 'jetpack' ) }
+ checked={ displayDate }
+ onChange={ value => setAttributes( { displayDate: value } ) }
+ />
+ <ToggleControl
+ label={ __( 'Display context (category or tag)', 'jetpack' ) }
+ checked={ displayContext }
+ onChange={ value => setAttributes( { displayContext: value } ) }
+ />
+ <RangeControl
+ label={ __( 'Number of posts', 'jetpack' ) }
+ value={ postsToShow }
+ onChange={ value =>
+ setAttributes( { postsToShow: Math.min( value, MAX_POSTS_TO_SHOW ) } )
+ }
+ min={ 1 }
+ max={ MAX_POSTS_TO_SHOW }
+ />
+ </PanelBody>
+ </InspectorControls>
+
+ <BlockControls>
+ <Toolbar controls={ layoutControls } />
+ </BlockControls>
+
+ <div className={ className } id={ `related-posts-${ instanceId }` }>
+ <div className={ previewClassName } data-layout={ postLayout }>
+ <RelatedPostsPreviewRows posts={ displayPosts } />
+ </div>
+ </div>
+ </Fragment>
+ );
+ }
+}
+
+export default compose(
+ withInstanceId,
+ withSelect( select => {
+ const { getCurrentPost } = select( 'core/editor' );
+ const posts = get( getCurrentPost(), 'jetpack-related-posts', [] );
+
+ return {
+ posts,
+ };
+ } )
+)( RelatedPostsEdit );