Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tiled Gallery: Fix block validation errors caused by inconsistent flex-basis style #18971

Merged
merged 5 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: bugfix

Tiled Gallery: Prevent block validation errors for mosaic and column layouts.
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
*/
import * as deprecatedV1 from './v1';
import * as deprecatedV2 from './v2';
import * as deprecatedV3 from './v3';

export default [ deprecatedV1, deprecatedV2 ];
export default [ deprecatedV3, deprecatedV2, deprecatedV1 ];
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const ALLOWED_MEDIA_TYPES = [ 'image' ];
export const DEFAULT_GALLERY_WIDTH = 580;
export const GUTTER_WIDTH = 4;
export const MAX_COLUMNS = 20;
export const MAX_ROUNDED_CORNERS = 20;
export const PHOTON_MAX_RESIZE = 2000;

/**
* Layouts
*/
export const LAYOUT_CIRCLE = 'circle';
export const LAYOUT_COLUMN = 'columns';
export const LAYOUT_DEFAULT = 'rectangular';
export const LAYOUT_SQUARE = 'square';
export const LAYOUT_STYLES = [
{
isDefault: true,
name: LAYOUT_DEFAULT,
},
{
name: LAYOUT_CIRCLE,
},
{
name: LAYOUT_SQUARE,
},
{
name: LAYOUT_COLUMN,
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* External Dependencies
*/
import classnames from 'classnames';
import { isBlobURL } from '@wordpress/blob';

export default function GalleryImageSave( props ) {
const { alt, imageFilter, height, id, link, linkTo, origUrl, url, width } = props;

if ( isBlobURL( origUrl ) ) {
return null;
}

let href;

switch ( linkTo ) {
case 'media':
href = url;
break;
case 'attachment':
href = link;
break;
}

const img = (
<img
alt={ alt }
data-height={ height }
data-id={ id }
data-link={ link }
data-url={ origUrl }
data-width={ width }
src={ url }
/>
);

return (
<figure
className={ classnames( 'tiled-gallery__item', {
[ `filter__${ imageFilter }` ]: !! imageFilter,
} ) }
>
{ href ? <a href={ href }>{ img }</a> : img }
</figure>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* Internal dependencies
*/
import { LAYOUT_DEFAULT } from './constants';

export { default as save } from './save';

export const attributes = {
// Set default align
align: {
default: 'center',
type: 'string',
},
// Set default className (used with block styles)
className: {
default: `is-style-${ LAYOUT_DEFAULT }`,
type: 'string',
},
columns: {
type: 'number',
},
columnWidths: {
default: [],
type: 'array',
},
ids: {
default: [],
type: 'array',
},
imageFilter: {
type: 'string',
},
images: {
type: 'array',
default: [],
source: 'query',
selector: '.tiled-gallery__item',
query: {
alt: {
attribute: 'alt',
default: '',
selector: 'img',
source: 'attribute',
},
height: {
attribute: 'data-height',
selector: 'img',
source: 'attribute',
type: 'number',
},
id: {
attribute: 'data-id',
selector: 'img',
source: 'attribute',
},
link: {
attribute: 'data-link',
selector: 'img',
source: 'attribute',
},
url: {
attribute: 'data-url',
selector: 'img',
source: 'attribute',
},
width: {
attribute: 'data-width',
selector: 'img',
source: 'attribute',
type: 'number',
},
},
},
linkTo: {
default: 'none',
type: 'string',
},
roundedCorners: {
type: 'integer',
default: 0,
},
};

export const supports = {
align: [ 'center', 'wide', 'full' ],
customClassName: false,
html: false,
};

export const migrate = oldAttributes => {
// The column widths need to be updated to match the new precision
// implemented in the current version.
const precision = Math.pow( 10, 5 );

return {
...oldAttributes,
columnWidths: oldAttributes.columnWidths.map( column =>
column.map( width => Math.round( width * precision ) / precision )
),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function Column( { children, width } ) {
// This deprecation fixes inconsistent precision of flex-basis style decimal.
// It needs to be adjusted here so that the style value matches the post
// content to then trigger re-saving the block.
const precision = Math.pow( 10, 12 ); // 1000000000000.
const roundedWidth = Math.round( width * precision ) / precision;
const style = width ? { flexBasis: `${ roundedWidth }%` } : undefined;

return (
<div className="tiled-gallery__col" style={ style }>
{ children }
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Gallery( { children, galleryRef } ) {
return (
<div className="tiled-gallery__gallery" ref={ galleryRef }>
{ children }
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import classnames from 'classnames';

/**
* Internal dependencies
*/
import GalleryImageSave from '../gallery-image/save';
import Mosaic from './mosaic';
import Square from './square';
import { isSquareishLayout, photonizedImgProps } from '../utils';
import { LAYOUT_CIRCLE, MAX_ROUNDED_CORNERS } from '../constants';

export default class Layout extends Component {
// This is tricky:
// - We need to "photonize" to resize the images at appropriate dimensions
// - The resize will depend on the image size and the layout in some cases
// - Handlers need to be created by index so that the image changes can be applied correctly.
// This is because the images are stored in an array in the block attributes.
renderImage( img, i ) {
const {
columns,
imageFilter,
images,
isSave,
linkTo,
layoutStyle,
onMoveBackward,
onMoveForward,
onRemoveImage,
onSelectImage,
selectedImage,
setImageAttributes,
} = this.props;

const ariaLabel = sprintf(
/* translators: %1$d is the order number of the image, %2$d is the total number of images. */
__( 'image %1$d of %2$d in gallery', 'jetpack' ),
i + 1,
images.length
);

const { src, srcSet } = photonizedImgProps( img, { layoutStyle } );

return (
<GalleryImageSave
alt={ img.alt }
aria-label={ ariaLabel }
columns={ columns }
height={ img.height }
id={ img.id }
imageFilter={ imageFilter }
isFirstItem={ i === 0 }
isLastItem={ i + 1 === images.length }
isSelected={ selectedImage === i }
key={ i }
link={ img.link }
linkTo={ linkTo }
onMoveBackward={ isSave ? undefined : onMoveBackward( i ) }
onMoveForward={ isSave ? undefined : onMoveForward( i ) }
onRemove={ isSave ? undefined : onRemoveImage( i ) }
onSelect={ isSave ? undefined : onSelectImage( i ) }
origUrl={ img.url }
setAttributes={ isSave ? undefined : setImageAttributes( i ) }
showMovers={ images.length > 1 }
srcSet={ srcSet }
url={ src }
width={ img.width }
/>
);
}

render() {
const {
align,
children,
className,
columns,
images,
layoutStyle,
roundedCorners,
onResize,
isSave,
columnWidths,
} = this.props;
const LayoutRenderer = isSquareishLayout( layoutStyle ) ? Square : Mosaic;
const renderedImages = this.props.images.map( this.renderImage, this );
const roundedCornersValue =
layoutStyle !== LAYOUT_CIRCLE ? Math.min( roundedCorners, MAX_ROUNDED_CORNERS ) : 0;

return (
<div
className={ classnames( className, {
[ `has-rounded-corners-${ roundedCornersValue }` ]: roundedCornersValue > 0,
} ) }
>
<LayoutRenderer
align={ align }
columns={ columns }
columnWidths={ isSave ? columnWidths : undefined }
images={ images }
layoutStyle={ layoutStyle }
renderedImages={ renderedImages }
onResize={ isSave ? undefined : onResize }
/>
{ children }
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* External dependencies
*/
import { Component, createRef } from '@wordpress/element';

/**
* Internal dependencies
*/
import Column from '../column';
import Gallery from '../gallery';
import Row from '../row';
import { imagesToRatios, ratiosToColumns, ratiosToMosaicRows } from './ratios';

export default class Mosaic extends Component {
gallery = createRef();
pendingRaf = null;

render() {
const { align, columns, images, layoutStyle, renderedImages, columnWidths } = this.props;

const ratios = imagesToRatios( images );
const rows =
'columns' === layoutStyle
? ratiosToColumns( ratios, columns )
: ratiosToMosaicRows( ratios, { isWide: [ 'full', 'wide' ].includes( align ) } );

let cursor = 0;
return (
<Gallery galleryRef={ this.gallery }>
{ rows.map( ( row, rowIndex ) => (
<Row key={ rowIndex }>
{ row.map( ( colSize, colIndex ) => {
const columnImages = renderedImages.slice( cursor, cursor + colSize );
cursor += colSize;
return (
<Column
key={ colIndex }
width={ columnWidths ? columnWidths[ rowIndex ][ colIndex ] : undefined }
>
{ columnImages }
</Column>
);
} ) }
</Row>
) ) }
</Gallery>
);
}
}
Loading