diff --git a/client/gutenberg/extensions/tiled-gallery/constants.js b/client/gutenberg/extensions/tiled-gallery/constants.js index dfc706cf9415b..12efe5d530a83 100644 --- a/client/gutenberg/extensions/tiled-gallery/constants.js +++ b/client/gutenberg/extensions/tiled-gallery/constants.js @@ -11,23 +11,24 @@ export const DEFAULT_GALLERY_WIDTH = 580; export const DEFAULT_LAYOUT = 'rectangular'; export const LAYOUT_STYLES = [ { - label: _x( 'Tiled mosaic', 'Tiled gallery layout' ), - name: 'rectangular', isDefault: true, + label: _x( 'Tiled mosaic', 'Tiled gallery layout' ), + name: DEFAULT_LAYOUT, }, { - label: _x( 'Tiled columns', 'Tiled gallery layout' ), - name: 'columns', + label: _x( 'Circles', 'Tiled gallery layout' ), + name: 'circle', }, { label: _x( 'Square tiles', 'Tiled gallery layout' ), name: 'square', }, + /* Unimplemented { - label: _x( 'Circles', 'Tiled gallery layout' ), - name: 'circle', + label: _x( 'Tiled columns', 'Tiled gallery layout' ), + name: 'columns', }, + */ ]; -export const LAYOUTS = [ 'rectangular', 'columns', 'square', 'circle' ]; export const MAX_COLUMNS = 20; export const TILE_MARGIN = 2; diff --git a/client/gutenberg/extensions/tiled-gallery/edit.jsx b/client/gutenberg/extensions/tiled-gallery/edit.jsx index 2609690041211..3e3b558397a57 100644 --- a/client/gutenberg/extensions/tiled-gallery/edit.jsx +++ b/client/gutenberg/extensions/tiled-gallery/edit.jsx @@ -1,10 +1,15 @@ -/** @format */ - /** * External Dependencies */ -import { filter, pick } from 'lodash'; import { Component, Fragment } from '@wordpress/element'; +import { filter, get, pick } from 'lodash'; +import { + BlockControls, + InspectorControls, + MediaPlaceholder, + MediaUpload, + mediaUpload, +} from '@wordpress/editor'; import { DropZone, FormFileUpload, @@ -12,40 +17,40 @@ import { PanelBody, RangeControl, SelectControl, - ToggleControl, Toolbar, withNotices, } from '@wordpress/components'; -import { - BlockControls, - InspectorControls, - MediaPlaceholder, - mediaUpload, - MediaUpload, -} from '@wordpress/editor'; -import { create } from '@wordpress/rich-text'; /** * Internal dependencies */ +import Layout from './layout'; import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; -import { ALLOWED_MEDIA_TYPES, MAX_COLUMNS, DEFAULT_COLUMNS } from './constants'; -import GalleryGrid from './gallery-grid'; -import GalleryImage from './gallery-image'; -import { getActiveStyleName } from './layouts'; +import { ALLOWED_MEDIA_TYPES, LAYOUT_STYLES, MAX_COLUMNS } from './constants'; +import { getActiveStyleName } from 'gutenberg/extensions/utils'; + +const linkOptions = [ + { value: 'attachment', label: __( 'Attachment Page' ) }, + { value: 'media', label: __( 'Media File' ) }, + { value: 'none', label: __( 'None' ) }, +]; + +// @TODO keep here or move to ./layout ? +function layoutSupportsColumns( layout ) { + return [ 'circle', 'square' ].includes( layout ); +} export function defaultColumnsNumber( attributes ) { - return Math.min( DEFAULT_COLUMNS, attributes.images.length ); + return Math.min( 3, attributes.images.length ); } -const pickRelevantMediaFiles = image => { - let { caption } = image; - - if ( typeof caption !== 'object' ) { - caption = create( { html: caption } ); - } - - return Object.assign( pick( image, [ [ 'alt' ], [ 'id' ], [ 'link' ], [ 'url' ] ] ), caption ); +export const pickRelevantMediaFiles = image => { + const imageProps = pick( image, [ [ 'alt' ], [ 'id' ], [ 'link' ], [ 'caption' ] ] ); + imageProps.url = + get( image, [ 'sizes', 'large', 'url' ] ) || + get( image, [ 'media_details', 'sizes', 'large', 'source_url' ] ) || + image.url; + return imageProps; }; class TiledGalleryEdit extends Component { @@ -61,42 +66,50 @@ class TiledGalleryEdit extends Component { return null; } - handleAddFiles = files => { + setAttributes( attributes ) { + if ( attributes.ids ) { + throw new Error( + 'The "ids" attribute should not be changed directly. It is managed automatically when "images" attribute changes' + ); + } + + if ( attributes.images ) { + attributes = { + ...attributes, + ids: attributes.images.map( ( { id } ) => parseInt( id, 10 ) ), + }; + } + + this.props.setAttributes( attributes ); + } + + addFiles = files => { const currentImages = this.props.attributes.images || []; - const { noticeOperations, setAttributes } = this.props; + const { noticeOperations } = this.props; mediaUpload( { allowedTypes: ALLOWED_MEDIA_TYPES, filesList: files, onFileChange: images => { const imagesNormalized = images.map( image => pickRelevantMediaFiles( image ) ); - setAttributes( { - images: currentImages.concat( imagesNormalized ), - } ); + this.setAttributes( { images: currentImages.concat( imagesNormalized ) } ); }, onError: noticeOperations.createErrorNotice, } ); }; - handleColumnCountChange = columns => this.props.setAttributes( { columns } ); - - handleCropImageToggle = () => - this.props.setAttributes( { imageCrop: ! this.props.attributes.imageCrop } ); - - handleFormFileUpload = event => this.handleAddFiles( event.target.files ); - - handleLinkToChange = linkTo => this.props.setAttributes( { linkTo } ); - - handleRemveImageByIndex = index => () => { + onRemoveImage = index => () => { const images = filter( this.props.attributes.images, ( img, i ) => index !== i ); const { columns } = this.props.attributes; - this.setState( { selectedImage: null } ); - this.props.setAttributes( { + this.setState( { + selectedImage: null, + } ); + this.setAttributes( { images, columns: columns ? Math.min( images.length, columns ) : columns, } ); }; - handleSelectImageByIndex = index => () => { + onSelectImage = index => () => { if ( this.state.selectedImage !== index ) { this.setState( { selectedImage: index, @@ -104,58 +117,44 @@ class TiledGalleryEdit extends Component { } }; - handleSelectImages = images => - this.props.setAttributes( { - images: images.map( image => pickRelevantMediaFiles( image ) ), - } ); + onSelectImages = images => + this.setAttributes( { images: images.map( image => pickRelevantMediaFiles( image ) ) } ); - handleSetImageAttributesByIndex = index => newAttributes => { - const { attributes, setAttributes } = this.props; - const { images = [] } = attributes; + setColumnsNumber = value => this.setAttributes( { columns: value } ); + setImageAttributes = index => attributes => { + const { + attributes: { images }, + } = this.props; if ( ! images[ index ] ) { return; } - - setAttributes( { + this.setAttributes( { images: [ ...images.slice( 0, index ), - { - ...images[ index ], - ...newAttributes, - }, + { ...images[ index ], ...attributes }, ...images.slice( index + 1 ), ], } ); }; - getImageCropHelp( checked ) { - return checked ? __( 'Thumbnails are cropped to align.' ) : __( 'Thumbnails are not cropped.' ); - } + setLinkTo = value => this.setAttributes( { linkTo: value } ); + + uploadFromFiles = event => this.addFiles( event.target.files ); render() { const { selectedImage } = this.state; - const { attributes, isSelected, className, noticeOperations, noticeUI } = this.props; + const { align, columns = defaultColumnsNumber( attributes ), images, linkTo } = attributes; - const { - images, - columns = defaultColumnsNumber( attributes ), - align, - imageCrop, - linkTo, - } = attributes; - - const layoutsSupportingColumns = [ 'square', 'circle' ]; - - const dropZone = ; + const dropZone = ; const controls = ( { !! images.length && ( { - if ( ! images[ index ] ) { - return null; - } - - const image = images[ index ]; - - return ( - - ); - }; - - const layout = getActiveStyleName( this.props.className ); + const layoutStyle = getActiveStyleName( LAYOUT_STYLES, attributes.className ); return ( { controls } - { images.length > 1 && ( - - ) } - + { /* @TODO disable with title comment, don't remove */ layoutSupportsColumns( + layoutStyle + ) && + images.length > 1 && ( + + ) } + { noticeUI } - { dropZone } - + { dropZone } { isSelected && ( - - { __( 'Upload an image' ) } - +
+ + { __( 'Upload an image' ) } + +
) } -
+
); } diff --git a/client/gutenberg/extensions/tiled-gallery/editor.scss b/client/gutenberg/extensions/tiled-gallery/editor.scss index 4e8938018c7b8..6dd2a28a84b7e 100644 --- a/client/gutenberg/extensions/tiled-gallery/editor.scss +++ b/client/gutenberg/extensions/tiled-gallery/editor.scss @@ -1,90 +1,76 @@ - @import './view.scss'; - @import './variables.scss'; -.wp-block-jetpack-tiled-gallery.components-placeholder { - margin: 0; -} - .wp-block-jetpack-tiled-gallery { - .tiled-gallery__row { - .tiled-gallery__item { - // Hide the focus outline that otherwise briefly appears when selecting a block. - figure:not( .is-selected ):focus { - outline: none; - } + // Ensure that selected image outlines are visibile + padding-left: 4px; + padding-right: 4px; + + .tiled-gallery__item { + // Hide the focus outline that otherwise briefly appears when selecting a block. + > img:focus { + outline: none; + } - .is-selected { - outline: 4px solid $tiled-gallery-selection; - } + &.is-selected { + outline: 4px solid $tiled-gallery-selection; + } - /* - // Animation for photos being uploaded - // @TODO Import animation from Calypso - &.is-transient img { - @include loading_fade; - } - */ - - .editor-rich-text { - position: absolute; - bottom: 0; - width: 100%; - max-height: 100%; - overflow-y: auto; - } + &.is-transient img { + opacity: 0.3; + } - .editor-rich-text figcaption:not( [data-is-placeholder-visible='true'] ) { - position: relative; - overflow: hidden; - } + .editor-rich-text { + position: absolute; + bottom: 0; + width: 100%; + max-height: 100%; + overflow-y: auto; + } + + .editor-rich-text figcaption:not( [data-is-placeholder-visible='true'] ) { + position: relative; + overflow: hidden; + color: $white; + } - .is-selected .editor-rich-text { - // IE calculates this incorrectly, so leave it to modern browsers. - @supports ( position: sticky ) { - right: 0; - left: 0; - margin-top: -4px; - } - - // Override negative margins so this toolbar isn't hidden by overflow. Overflow is needed for long captions. - .editor-rich-text__inline-toolbar { - top: 0; - } - - // Make extra space for the inline toolbar. - .editor-rich-text__tinymce { - padding-top: 48px; - } + &.is-selected .editor-rich-text { + // IE calculates this incorrectly, so leave it to modern browsers. + @supports ( position: sticky ) { + right: 0; + left: 0; + margin-top: -4px; } - .editor-rich-text .editor-rich-text__tinymce { - a { - color: $white; - } + // Override negative margins so this toolbar isn't hidden by overflow. Overflow is needed for long captions. + .editor-rich-text__inline-toolbar { + top: 0; + } - &:focus a[data-mce-selected] { - color: rgba( 0, 0, 0, 0.2 ); - } + // Make extra space for the inline toolbar. + .editor-rich-text__tinymce { + padding-top: 48px; } } } // Circle layout doesn't support captions + // @TODO handle this in the component &.is-style-circle .tiled-gallery__item .editor-rich-text { display: none; } - .tiled-gallery__row-extras { - &, + .tiled-gallery__add-item { + margin-top: $tiled-gallery-gutter; + width: 100%; + .components-form-file-upload, - .components-button.block-library-gallery-add-item-button { + .components-button.tiled-gallery__add-item-button { width: 100%; height: 100%; } - .components-button.block-library-gallery-add-item-button { + .components-button.tiled-gallery__add-item-button { display: flex; flex-direction: column; justify-content: center; @@ -93,7 +79,7 @@ border-radius: 0; min-height: 100px; - & .dashicon { + .dashicon { margin-top: 10px; } @@ -104,14 +90,13 @@ } } - .block-library-gallery-item__inline-menu { - padding: 2px; - position: absolute; - top: -2px; - right: -2px; + .tiled-gallery__item__inline-menu { background-color: $tiled-gallery-selection; display: inline-flex; - // z-index: z-index( '.block-library-gallery-item__inline-menu' ); + padding: 0 0 2px 2px; + position: absolute; + right: 0; + top: 0; .components-button { color: $white; @@ -122,19 +107,22 @@ } } - .blocks-gallery-item__remove { + .tiled-gallery__item__remove { padding: 0; } - .blocks-gallery-item .components-spinner { + .tiled-gallery__item .components-spinner { position: absolute; top: 50%; left: 50%; transform: translate( -50%, -50% ); } -} -// Hide captions in style picker preview -.editor-block-preview__content .wp-block-jetpack-tiled-gallery figcaption { - display: none; + // Hide captions and upload buttons in style picker preview + .editor-block-preview__content & { + .editor-media-placeholder, + figcaption { + display: none; + } + } } diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx b/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx deleted file mode 100644 index e7f16c64118a3..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx +++ /dev/null @@ -1,189 +0,0 @@ -/** @format */ - -/** - * External dependencies - */ -import { Component, createRef } from '@wordpress/element'; -import classnames from 'classnames'; -import { defer } from 'lodash'; -import ResizeObserver from 'resize-observer-polyfill'; - -/** - * Internal dependencies - */ -import { DEFAULT_GALLERY_WIDTH } from './constants'; -import { getLayout } from './layouts'; - -class TiledGalleryGrid extends Component { - state = { - width: DEFAULT_GALLERY_WIDTH, - }; - - // Create a ref to store the wrapper DOM element for ResizeObserver - wrapper = createRef(); - - pendingRaf = null; - - handleResize = this.props.noResize - ? () => {} - : entries => { - if ( this.pendingRaf ) { - cancelAnimationFrame( this.pendingRaf ); - } - this.pendingRaf = requestAnimationFrame( () => { - this.pendingRaf = null; - for ( const entry of entries ) { - const { width } = entry.contentRect; - if ( width && width !== this.state.width ) { - this.setWidth( width ); - } - } - } ); - }; - - setWidth( width ) { - this.setState( { width } ); - } - - componentDidMount() { - if ( ! this.props.noResize ) { - this.deferredMount = defer( () => { - // ResizeObserver has checks for `window` & `document`: - // it does nothing if those are not available. - this.observer = new ResizeObserver( this.handleResize ); - this.observer.observe( this.wrapper.current.parentNode ); - } ); - } - } - - componentWillUnmount() { - if ( this.observer ) { - this.observer.disconnect(); - } - clearTimeout( this.deferredMount ); - } - - render() { - const { - align, - children, - className, - columns, - imageCrop, - images, - layout, - noResize, - renderGalleryImage, - } = this.props; - const { width } = this.state; - const rows = getLayout( { - columns, - images, - layout, - tileCount: images.length, - width, - } ); - let imageIndex = 0; - - return ( -
- { rows.map( ( row, rowIndex ) => { - return ( -
- { 'groups' in row - ? row.groups.map( ( group, groupI ) => ( -
- { group.images.map( image => { - const galleryItem = ( -
- { renderGalleryImage( imageIndex ) } -
- ); - - imageIndex++; - - return galleryItem; - } ) } -
- ) ) - : row.tiles.map( tile => { - const galleryItem = ( -
- { renderGalleryImage( imageIndex ) } -
- ); - - imageIndex++; - - return galleryItem; - } ) } -
- ); - } ) } - { children ? ( -
- { children } -
- ) : null } -
- ); - } -} - -export default TiledGalleryGrid; diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx b/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx deleted file mode 100644 index 4f18eb286d82d..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx +++ /dev/null @@ -1,168 +0,0 @@ -/** @format */ - -/** - * This component is originally from Gutenberg Gallery block: - * @link https://github.com/WordPress/gutenberg/blob/1cd604df7e9017e0dbe3ab64897ac3af35ca35c5/packages/block-library/src/gallery/gallery-image.js - */ - -/** - * External Dependencies - */ -import { BACKSPACE, DELETE } from '@wordpress/keycodes'; -import { Component } from '@wordpress/element'; -import { IconButton, Spinner } from '@wordpress/components'; -import { RichText } from '@wordpress/editor'; -import { withSelect } from '@wordpress/data'; -import classnames from 'classnames'; - -/** - * Internal Dependencies - */ -import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; - -class GalleryImage extends Component { - constructor() { - super( ...arguments ); - - this.onImageClick = this.onImageClick.bind( this ); - this.onSelectCaption = this.onSelectCaption.bind( this ); - this.onKeyDown = this.onKeyDown.bind( this ); - this.bindContainer = this.bindContainer.bind( this ); - - this.state = { - captionSelected: false, - }; - } - - bindContainer( ref ) { - this.container = ref; - } - - onSelectCaption() { - if ( ! this.state.captionSelected ) { - this.setState( { - captionSelected: true, - } ); - } - - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - } - - onImageClick() { - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - - if ( this.state.captionSelected ) { - this.setState( { - captionSelected: false, - } ); - } - } - - onKeyDown( event ) { - if ( - this.container === document.activeElement && - this.props.isSelected && - [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1 - ) { - event.stopPropagation(); - event.preventDefault(); - this.props.onRemove(); - } - } - - componentDidUpdate( prevProps ) { - const { isSelected, image, url } = this.props; - if ( image && ! url ) { - this.props.setAttributes( { - url: image.source_url, - alt: image.alt_text, - } ); - } - - // unselect the caption so when the user selects other image and comeback - // the caption is not immediately selected - if ( this.state.captionSelected && ! isSelected && prevProps.isSelected ) { - //eslint-disable-next-line - this.setState( { - captionSelected: false, - } ); - } - } - - render() { - const { url, alt, id, linkTo, link, isSelected, caption, onRemove, setAttributes } = this.props; - - let href; - - switch ( linkTo ) { - case 'media': - href = url; - break; - case 'attachment': - href = link; - break; - } - - const img = url ? ( - // Disable reason: Image itself is not meant to be - // interactive, but should direct image selection and unfocus caption fields - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events - { - ) : ( - - ); - - const className = classnames( { - 'is-selected': isSelected, - 'is-transient': url && 0 === url.indexOf( 'blob:' ), - } ); - - // Disable reason: Each block can be selected by clicking on it and we should keep the same saved markup - /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - return ( -
- { isSelected && ( -
- -
- ) } - { href ? { img } : img } - { ! RichText.isEmpty( caption ) || isSelected ? ( - setAttributes( { caption: newCaption } ) } - unstableOnFocus={ this.onSelectCaption } - inlineToolbar - /> - ) : null } -
- ); - /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - } -} - -export default withSelect( ( select, ownProps ) => { - const { getMedia } = select( 'core' ); - const { id } = ownProps; - - return { - image: id ? getMedia( id ) : null, - }; -} )( GalleryImage ); diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-image/edit.js b/client/gutenberg/extensions/tiled-gallery/gallery-image/edit.js new file mode 100644 index 0000000000000..45bc96ab81f42 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/gallery-image/edit.js @@ -0,0 +1,190 @@ +/** + * External Dependencies + */ +import classnames from 'classnames'; +import { BACKSPACE, DELETE } from '@wordpress/keycodes'; +import { Component, createRef, Fragment } from '@wordpress/element'; +import { IconButton, Spinner } from '@wordpress/components'; +import { isBlobURL } from '@wordpress/blob'; // @TODO Add dep Jetpack-side +import { RichText } from '@wordpress/editor'; +import { withSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; + +class GalleryImageEdit extends Component { + img = createRef(); + + state = { + captionSelected: false, + }; + + onSelectCaption = () => { + if ( ! this.state.captionSelected ) { + this.setState( { + captionSelected: true, + } ); + } + + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + }; + + onImageClick = e => { + // Don't let click event trigger naviagtion on . @TODO How does g7g handle this? + e.preventDefault(); + e.stopPropagation(); + + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + + if ( this.state.captionSelected ) { + this.setState( { + captionSelected: false, + } ); + } + }; + + onImageKeyDown = event => { + event.stopPropagation(); + if ( + this.img.current === document.activeElement && + this.props.isSelected && + [ BACKSPACE, DELETE ].includes( event.keyCode ) + ) { + this.props.onRemove(); + } + }; + + static getDerivedStateFromProps( props, state ) { + // unselect the caption so when the user selects other image and comeback + // the caption is not immediately selected + if ( ! props.isSelected && state.captionSelected ) { + return { captionSelected: false }; + } + return null; + } + + componentDidUpdate() { + const { alt, height, image, url, width } = this.props; + + if ( image ) { + const nextAtts = {}; + + if ( ! url && image.source_url ) { + nextAtts.url = image.source_url; + } + if ( ! alt && image.alt_text ) { + nextAtts.alt = image.alt_text; + } + if ( ! width && image.media_details && image.media_details.width ) { + nextAtts.width = +image.media_details.width; + } + if ( ! height && image.media_details && image.media_details.height ) { + nextAtts.height = +image.media_details.height; + } + + if ( Object.keys( nextAtts ).length ) { + this.props.setAttributes( nextAtts ); + } + } + } + + render() { + const { + 'aria-label': ariaLabel, + alt, + caption, + height, + id, + isSelected, + link, + linkTo, + onRemove, + origUrl, + setAttributes, + url, + width, + } = this.props; + + let href; + + switch ( linkTo ) { + case 'media': + href = url; + break; + case 'attachment': + href = link; + break; + } + + const img = ( + // Disable reason: Image itself is not meant to be interactive, but should + // direct image selection and unfocus caption fields. + /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/no-noninteractive-tabindex */ + + { + { isBlobURL( origUrl ) && } + + /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/no-noninteractive-tabindex */ + ); + + // Disable reason: Each block can be selected by clicking on it and we should keep the same saved markup + return ( +
+ { isSelected && ( +
+ +
+ ) } + { href ?
{ img } : img } + { ! RichText.isEmpty( caption ) || isSelected ? ( + setAttributes( { caption: newCaption } ) } + unstableOnFocus={ this.onSelectCaption } + inlineToolbar + /> + ) : null } +
+ ); + } +} + +export default withSelect( ( select, ownProps ) => { + const { getMedia } = select( 'core' ); + const { id } = ownProps; + + return { + image: id ? getMedia( id ) : null, + }; +} )( GalleryImageEdit ); diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-image/save.js b/client/gutenberg/extensions/tiled-gallery/gallery-image/save.js new file mode 100644 index 0000000000000..c4c0ff3ec1f6f --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/gallery-image/save.js @@ -0,0 +1,56 @@ +/** + * External Dependencies + */ +import { isBlobURL } from '@wordpress/blob'; // @TODO Add dep Jetpack-side +import { RichText } from '@wordpress/editor'; + +export default function GalleryImageSave( props ) { + const { + 'aria-label': ariaLabel, + alt, + caption, + 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 = ( + { + ); + + return ( +
+ { href ? { img } : img } + { ! RichText.isEmpty( caption ) && ( + + ) } +
+ ); +} diff --git a/client/gutenberg/extensions/tiled-gallery/index.js b/client/gutenberg/extensions/tiled-gallery/index.js index 2daaf7041b201..b82a47837c111 100644 --- a/client/gutenberg/extensions/tiled-gallery/index.js +++ b/client/gutenberg/extensions/tiled-gallery/index.js @@ -1,5 +1,3 @@ -/** @format */ - /** * External dependencies */ @@ -13,7 +11,7 @@ import { Rect, SVG } from '@wordpress/components'; import { __, _x } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; import edit from './edit'; import save from './save'; -import { DEFAULT_COLUMNS, DEFAULT_LAYOUT, LAYOUT_STYLES, LAYOUTS } from './constants'; +import { DEFAULT_LAYOUT, LAYOUT_STYLES } from './constants'; /** * Style dependencies @@ -21,50 +19,72 @@ import { DEFAULT_COLUMNS, DEFAULT_LAYOUT, LAYOUT_STYLES, LAYOUTS } from './const import './editor.scss'; const blockAttributes = { + // Set default align + align: { + default: 'center', + type: 'string', + }, + // Set default className (used with block styles) + className: { + default: `is-style-${ DEFAULT_LAYOUT }`, + type: 'string', + }, + columns: { + type: 'number', + }, + ids: { + default: [], + type: 'array', + }, images: { type: 'array', default: [], source: 'query', - selector: '.wp-block-jetpack-tiled-gallery .tiled-gallery__item', + selector: '.tiled-gallery__item', query: { - url: { - source: 'attribute', + alt: { + attribute: 'alt', + default: '', selector: 'img', - attribute: 'src', - }, - link: { source: 'attribute', - selector: 'img', - attribute: 'data-link', }, - alt: { - source: 'attribute', + caption: { + selector: 'figcaption', + source: 'html', + type: 'string', + }, + height: { + attribute: 'data-height', selector: 'img', - attribute: 'alt', - default: '', + source: 'attribute', + type: 'number', }, id: { + attribute: 'data-id', + selector: 'img', source: 'attribute', + }, + link: { + attribute: 'data-link', selector: 'img', - attribute: 'data-id', + source: 'attribute', }, - caption: { - source: 'html', - selector: 'figcaption', + url: { + attribute: 'data-url', + selector: 'img', + source: 'attribute', + }, + width: { + attribute: 'data-width', + selector: 'img', + source: 'attribute', + type: 'number', }, }, }, - columns: { - type: 'number', - default: DEFAULT_COLUMNS, - }, - imageCrop: { - type: 'boolean', - default: true, - }, linkTo: { - type: 'string', default: 'none', + type: 'string', }, }; @@ -90,8 +110,8 @@ export const settings = { ], styles: LAYOUT_STYLES, supports: { - align: true, - alignWide: true, + align: [ 'center', 'wide', 'full' ], + customClassName: false, html: false, }, title: __( 'Tiled gallery' ), @@ -155,7 +175,9 @@ export const settings = { type: 'string', shortcode: ( { named: { type = DEFAULT_LAYOUT } } ) => { // @TODO: if `type=slideshow`, return a slideshow block - return LAYOUTS.indexOf( type ) > -1 ? type : DEFAULT_LAYOUT; + return LAYOUT_STYLES.map( style => style.name ).includes( type ) + ? type + : DEFAULT_LAYOUT; }, }, }, @@ -165,8 +187,8 @@ export const settings = { { type: 'block', blocks: [ 'core/gallery' ], - transform: ( { images, columns, imageCrop, linkTo } ) => - createBlock( 'core/gallery', { images, columns, imageCrop, linkTo } ), + transform: ( { images, columns, linkTo } ) => + createBlock( 'core/gallery', { images, columns, imageCrop: true, linkTo } ), }, { type: 'block', diff --git a/client/gutenberg/extensions/tiled-gallery/layout/column.js b/client/gutenberg/extensions/tiled-gallery/layout/column.js new file mode 100644 index 0000000000000..a3ed5cdf04cbb --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/column.js @@ -0,0 +1,3 @@ +export default function Column( { children } ) { + return
{ children }
; +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/gallery.js b/client/gutenberg/extensions/tiled-gallery/layout/gallery.js new file mode 100644 index 0000000000000..94fc61e4be980 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/gallery.js @@ -0,0 +1,7 @@ +export default function Gallery( { children, galleryRef } ) { + return ( +
+ { children } +
+ ); +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/index.js b/client/gutenberg/extensions/tiled-gallery/layout/index.js new file mode 100644 index 0000000000000..bb9a4201cf3d0 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/index.js @@ -0,0 +1,107 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { isBlobURL } from '@wordpress/blob'; +import photon from 'photon'; + +/** + * Internal dependencies + */ +import GalleryImageEdit from '../gallery-image/edit'; +import GalleryImageSave from '../gallery-image/save'; +import Mosaic from './mosaic'; +import Square from './square'; + +// @TODO put in consts? +const PHOTON_MAX_RESIZE = 2000; + +export default class Layout extends Component { + photonize( { height, width, url } ) { + // Do not Photonize images that are still uploading or from localhost + if ( isBlobURL( url ) || /^https?:\/\/localhost/.test( url ) ) { + return url; + } + + const { layoutStyle } = this.props; + if ( isSquareishLayout( layoutStyle ) && width && height ) { + const size = Math.min( PHOTON_MAX_RESIZE, width, height ); + return photon( url, { resize: `${ size },${ size }` } ); + } + return photon( url ); + } + + // 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, + imageCrop, + images, + isSave, + linkTo, + onRemoveImage, + onSelectImage, + selectedImage, + setImageAttributes, + } = this.props; + + /* translators: %1$d is the order number of the image, %2$d is the total number of images. */ + const ariaLabel = sprintf( __( 'image %1$d of %2$d in gallery' ), i + 1, images.length ); + const Image = isSave ? GalleryImageSave : GalleryImageEdit; + + return ( + { + ); + } + + render() { + const { align, children, className, columns, images, layoutStyle } = this.props; + + // eslint-disable-next-line no-nested-ternary + const LayoutRenderer = isSquareishLayout( layoutStyle ) + ? Square + : 'columns' === layoutStyle + ? Square + : Mosaic; + + const renderedImages = this.props.images.map( this.renderImage, this ); + + return ( +
+ + { children } +
+ ); + } +} + +function isSquareishLayout( layout ) { + return [ 'circle', 'square' ].includes( layout ); +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/index.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/index.js new file mode 100644 index 0000000000000..01c676ab62b3b --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/index.js @@ -0,0 +1,98 @@ +/** + * External dependencies + */ +import { Component, createRef } from '@wordpress/element'; +import ResizeObserver from 'resize-observer-polyfill'; + +/** + * Internal dependencies + */ +import Column from '../column'; +import Gallery from '../gallery'; +import Row from '../row'; +import { getGalleryRows, handleRowResize } from './resize'; +import { imagesToRatios, ratiosToRows } from './ratios'; + +export default class Mosaic extends Component { + gallery = createRef(); + pendingRaf = null; + ro = null; // resizeObserver instance + + componentDidMount() { + this.observeResize(); + } + + componentWillUnmount() { + this.unobserveResize(); + } + + componentDidUpdate( prevProps ) { + if ( prevProps.images !== this.props.images || prevProps.align !== this.props.align ) { + this.triggerResize(); + } + } + + handleGalleryResize = entries => { + if ( this.pendingRaf ) { + cancelAnimationFrame( this.pendingRaf ); + this.pendingRaf = null; + } + this.pendingRaf = requestAnimationFrame( () => { + for ( const { contentRect, target } of entries ) { + const { width } = contentRect; + getGalleryRows( target ).forEach( row => handleRowResize( row, width ) ); + } + } ); + }; + + triggerResize() { + if ( this.gallery.current ) { + this.handleGalleryResize( [ + { + target: this.gallery.current, + contentRect: { width: this.gallery.current.clientWidth }, + }, + ] ); + } + } + + observeResize() { + this.triggerResize(); + this.ro = new ResizeObserver( this.handleGalleryResize ); + if ( this.gallery.current ) { + this.ro.observe( this.gallery.current ); + } + } + + unobserveResize() { + if ( this.ro ) { + this.ro.disconnect(); + this.ro = null; + } + if ( this.pendingRaf ) { + cancelAnimationFrame( this.pendingRaf ); + this.pendingRaf = null; + } + } + + render() { + const { images, align, renderedImages } = this.props; + const ratios = imagesToRatios( images ); + const rows = ratiosToRows( ratios, { isWide: [ 'full', 'wide' ].includes( align ) } ); + + let cursor = 0; + return ( + + { rows.map( ( row, rowIndex ) => ( + + { row.map( ( colSize, colIndex ) => { + const columnImages = renderedImages.slice( cursor, cursor + colSize ); + cursor += colSize; + return { columnImages }; + } ) } + + ) ) } + + ); + } +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/ratios.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/ratios.js new file mode 100644 index 0000000000000..aaf1e8b2c8f60 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/ratios.js @@ -0,0 +1,227 @@ +/** + * External dependencies + */ +import { every, isEqual, map, overEvery, some, sum, take, takeRight, zipWith } from 'lodash'; + +export function imagesToRatios( images ) { + return map( images, ratioFromImage ); +} + +export function ratioFromImage( { height, width } ) { + return height && width ? width / height : 1; +} + +/** + * These are partially applied functions. + * They rely on helper function (defined below) to create a function that expects to be passed ratios + * during processing. + * + * …FitsNextImages() functions should be passed ratios to be processed + * …IsNotRecent() functions should be passed the processed shapes + */ + +const reverseSymmetricRowIsNotRecent = isNotRecentShape( [ 2, 1, 2 ], 5 ); +const reverseSymmetricFitsNextImages = checkNextRatios( [ + isLandscape, + isLandscape, + isPortrait, + isLandscape, + isLandscape, +] ); +const longSymmetricRowFitsNextImages = checkNextRatios( [ + isLandscape, + isLandscape, + isLandscape, + isPortrait, + isLandscape, + isLandscape, + isLandscape, +] ); +const longSymmetricRowIsNotRecent = isNotRecentShape( [ 3, 1, 3 ], 5 ); +const symmetricRowFitsNextImages = checkNextRatios( [ + isPortrait, + isLandscape, + isLandscape, + isPortrait, +] ); +const symmetricRowIsNotRecent = isNotRecentShape( [ 1, 2, 1 ], 5 ); +const oneThreeFitsNextImages = checkNextRatios( [ + isPortrait, + isLandscape, + isLandscape, + isLandscape, +] ); +const oneThreeIsNotRecent = isNotRecentShape( [ 1, 3 ], 3 ); +const threeOneIsFitsNextImages = checkNextRatios( [ + isLandscape, + isLandscape, + isLandscape, + isPortrait, +] ); +const threeOneIsNotRecent = isNotRecentShape( [ 3, 1 ], 3 ); +const oneTwoFitsNextImages = checkNextRatios( [ + lt( 1.6 ), + overEvery( gte( 0.9 ), lt( 2 ) ), + overEvery( gte( 0.9 ), lt( 2 ) ), +] ); +const oneTwoIsNotRecent = isNotRecentShape( [ 1, 2 ], 3 ); +const fiveIsNotRecent = isNotRecentShape( [ 1, 1, 1, 1, 1 ], 1 ); +const fourIsNotRecent = isNotRecentShape( [ 1, 1, 1, 1 ], 1 ); +const threeIsNotRecent = isNotRecentShape( [ 1, 1, 1 ], 3 ); +const twoOneFitsNextImages = checkNextRatios( [ + overEvery( gte( 0.9 ), lt( 2 ) ), + overEvery( gte( 0.9 ), lt( 2 ) ), + lt( 1.6 ), +] ); +const twoOneIsNotRecent = isNotRecentShape( [ 2, 1 ], 3 ); +const panoramicFitsNextImages = checkNextRatios( [ isPanoramic ] ); + +export function ratiosToRows( ratios, { isWide } = {} ) { + // This function will recursively process the input until it is consumed + const go = ( processed, toProcess ) => { + if ( ! toProcess.length ) { + return processed; + } + + let next; + + if ( + /* Reverse_Symmetric_Row */ + toProcess.length > 15 && + reverseSymmetricFitsNextImages( toProcess ) && + reverseSymmetricRowIsNotRecent( processed ) + ) { + next = [ 2, 1, 2 ]; + } else if ( + /* Long_Symmetric_Row */ + toProcess.length > 15 && + longSymmetricRowFitsNextImages( toProcess ) && + longSymmetricRowIsNotRecent( processed ) + ) { + next = [ 3, 1, 3 ]; + } else if ( + /* Symmetric_Row */ + toProcess.length !== 5 && + symmetricRowFitsNextImages( toProcess ) && + symmetricRowIsNotRecent( processed ) + ) { + next = [ 1, 2, 1 ]; + } else if ( + /* One_Three */ + oneThreeFitsNextImages( toProcess ) && + oneThreeIsNotRecent( processed ) + ) { + next = [ 1, 3 ]; + } else if ( + /* Three_One */ + threeOneIsFitsNextImages( toProcess ) && + threeOneIsNotRecent( processed ) + ) { + next = [ 3, 1 ]; + } else if ( + /* One_Two */ + oneTwoFitsNextImages( toProcess ) && + oneTwoIsNotRecent( processed ) + ) { + next = [ 1, 2 ]; + } else if ( + /* Five */ + isWide && + ( toProcess.length === 5 || ( toProcess.length !== 10 && toProcess.length > 6 ) ) && + fiveIsNotRecent( processed ) && + sum( take( toProcess, 5 ) ) < 5 + ) { + next = [ 1, 1, 1, 1, 1 ]; + } else if ( + /* Four */ + isFourValidCandidate( processed, toProcess ) + ) { + next = [ 1, 1, 1, 1 ]; + } else if ( + /* Three */ + isThreeValidCandidate( processed, toProcess, isWide ) + ) { + next = [ 1, 1, 1 ]; + } else if ( + /* Two_One */ + twoOneFitsNextImages( toProcess ) && + twoOneIsNotRecent( processed ) + ) { + next = [ 2, 1 ]; + } else if ( /* Panoramic */ panoramicFitsNextImages( toProcess ) ) { + next = [ 1 ]; + } else if ( /* One_One */ toProcess.length > 3 ) { + next = [ 1, 1 ]; + } else { + // Everything left + next = Array( toProcess.length ).fill( 1 ); + } + + // Add row + const nextProcessed = processed.concat( [ next ] ); + + // Trim consumed images from next processing step + const consumedImages = sum( next ); + const nextToProcess = toProcess.slice( consumedImages ); + + return go( nextProcessed, nextToProcess ); + }; + return go( [], ratios ); +} + +function isThreeValidCandidate( processed, toProcess, isWide ) { + const ratio = sum( take( toProcess, 3 ) ); + return ( + toProcess.length >= 3 && + toProcess.length !== 4 && + toProcess.length !== 6 && + threeIsNotRecent( processed ) && + ( ratio < 2.5 || + ( ratio < 5 && + /* nextAreSymettric */ + ( toProcess.length >= 3 && + /* @FIXME floating point equality?? */ toProcess[ 0 ] === toProcess[ 2 ] ) ) || + isWide ) + ); +} + +function isFourValidCandidate( processed, toProcess ) { + const ratio = sum( take( toProcess, 4 ) ); + return ( + ( fourIsNotRecent( processed ) && ( ratio < 3.5 && toProcess.length > 5 ) ) || + ( ratio < 7 && toProcess.length === 4 ) + ); +} + +function isNotRecentShape( shape, numRecents ) { + return recents => + ! some( takeRight( recents, numRecents ), recentShape => isEqual( recentShape, shape ) ); +} + +function checkNextRatios( shape ) { + return ratios => + ratios.length >= shape.length && + every( zipWith( shape, ratios.slice( 0, shape.length ), ( f, r ) => f( r ) ) ); +} + +function isLandscape( ratio ) { + return ratio >= 1 && ratio < 2; +} + +function isPortrait( ratio ) { + return ratio < 1; +} + +function isPanoramic( ratio ) { + return ratio >= 2; +} + +// >= +function gte( n ) { + return m => m >= n; +} + +// < +function lt( n ) { + return m => m < n; +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/resize.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/resize.js new file mode 100644 index 0000000000000..c829e2c39e551 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/resize.js @@ -0,0 +1,99 @@ +const MARGIN = 4; + +/** + * Distribute a difference across ns so that their sum matches the target + * + * @param {Array} parts Array of numbers to fit + * @param {number} target Number that sum should match + * @return {Array} Adjusted parts + */ +function adjustFit( parts, target ) { + const diff = target - parts.reduce( ( sum, n ) => sum + n, 0 ); + const partialDiff = diff / parts.length; + return parts.map( p => p + partialDiff ); +} + +export function handleRowResize( row, width ) { + applyRowRatio( row, getRowRatio( row ), width ); +} + +function getRowRatio( row ) { + const result = getRowCols( row ) + .map( getColumnRatio ) + .reduce( + ( [ ratioA, weightedRatioA ], [ ratioB, weightedRatioB ] ) => { + return [ ratioA + ratioB, weightedRatioA + weightedRatioB ]; + }, + [ 0, 0 ] + ); + return result; +} + +export function getGalleryRows( gallery ) { + return Array.from( gallery.querySelectorAll( '.tiled-gallery__row' ) ); +} + +function getRowCols( row ) { + return Array.from( row.querySelectorAll( '.tiled-gallery__col' ) ); +} + +function getColImgs( col ) { + return Array.from( col.querySelectorAll( '.tiled-gallery__item > img' ) ); +} + +function getColumnRatio( col ) { + const imgs = getColImgs( col ); + const imgCount = imgs.length; + const ratio = + 1 / + imgs.map( getImageRatio ).reduce( ( partialColRatio, imgRatio ) => { + return partialColRatio + 1 / imgRatio; + }, 0 ); + const result = [ ratio, ratio * imgCount || 1 ]; + return result; +} + +function getImageRatio( img ) { + const w = parseInt( img.dataset.width, 10 ); + const h = parseInt( img.dataset.height, 10 ); + const result = w && ! Number.isNaN( w ) && h && ! Number.isNaN( h ) ? w / h : 1; + return result; +} + +function applyRowRatio( row, [ ratio, weightedRatio ], width ) { + const rawHeight = + ( 1 / ratio ) * + ( width - MARGIN * row.children.length * ( row.children.length - weightedRatio ) ); + + applyColRatio( row, { + rawHeight, + rowWidth: width - MARGIN * row.children.length, + } ); +} + +function applyColRatio( row, { rawHeight, rowWidth } ) { + const cols = getRowCols( row ); + + const colWidths = cols.map( + col => ( rawHeight - MARGIN * col.children.length ) * getColumnRatio( col )[ 0 ] + ); + + const adjustedWidths = adjustFit( colWidths, rowWidth ); + + cols.forEach( ( col, i ) => { + const rawWidth = colWidths[ i ]; + const width = adjustedWidths[ i ]; + applyImgRatio( col, { colHeight: rawHeight - MARGIN * col.children.length, width, rawWidth } ); + } ); +} + +function applyImgRatio( col, { colHeight, width, rawWidth } ) { + const imgHeights = getColImgs( col ).map( img => rawWidth / getImageRatio( img ) ); + const adjustedHeights = adjustFit( imgHeights, colHeight ); + + // Set size of col children, not the element + Array.from( col.children ).forEach( ( item, i ) => { + const height = adjustedHeights[ i ]; + item.setAttribute( 'style', `height:${ height }px;width:${ width }px;` ); + } ); +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/index.js.snap b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/index.js.snap new file mode 100644 index 0000000000000..e726fa521fa5b --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/index.js.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders as expected 1`] = ` + + + + 0 + + + + + 1 + + + + + 2 + + + 3 + + + 4 + + + 5 + + + + + 6 + + + 7 + + + + + 8 + + + 9 + 10 + + + + + 11 + 12 + + + 13 + + + +`; diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/ratios.js.snap b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/ratios.js.snap new file mode 100644 index 0000000000000..b9800f0fcb8d9 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/__snapshots__/ratios.js.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ratiosToRows transforms as expected 1`] = ` +Array [ + Array [ + 1, + ], + Array [ + 1, + ], + Array [ + 1, + 1, + 1, + 1, + ], + Array [ + 1, + 1, + ], + Array [ + 1, + 2, + ], + Array [ + 2, + 1, + ], +] +`; diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/fixtures/ratios.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/fixtures/ratios.js new file mode 100644 index 0000000000000..77db288c5b0f8 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/fixtures/ratios.js @@ -0,0 +1,16 @@ +export const ratios = [ + 4, + 2.26056338028169, + 0.6676143094053542, + 0.75, + 0.7444409646100846, + 0.6666666666666666, + 0.8000588062334607, + 3.6392174704276616, + 1.335559265442404, + 1.509433962264151, + 1.6, + 1.3208430913348945, + 1.3553937789543349, + 1.499531396438613, +]; diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/index.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/index.js new file mode 100644 index 0000000000000..72e49ba62b6cb --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/index.js @@ -0,0 +1,21 @@ +/** + * External dependencies + */ +import React from 'react'; +import { range } from 'lodash'; +import { shallow } from 'enzyme'; + +/** + * Internal dependencies + */ +import Mosaic from '..'; +import * as imageSets from '../../test/fixtures/image-sets'; + +test( 'renders as expected', () => { + Object.keys( imageSets ).forEach( k => { + const images = imageSets[ k ]; + expect( + shallow( ) + ).toMatchSnapshot(); + } ); +} ); diff --git a/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/ratios.js b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/ratios.js new file mode 100644 index 0000000000000..4628e6465a947 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/mosaic/test/ratios.js @@ -0,0 +1,11 @@ +/** + * Internal dependencies + */ +import { ratiosToRows } from '../ratios'; +import { ratios } from './fixtures/ratios'; + +describe( 'ratiosToRows', () => { + test( 'transforms as expected', () => { + expect( ratiosToRows( ratios ) ).toMatchSnapshot(); + } ); +} ); diff --git a/client/gutenberg/extensions/tiled-gallery/layout/row.js b/client/gutenberg/extensions/tiled-gallery/layout/row.js new file mode 100644 index 0000000000000..200a58c2e3acf --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/row.js @@ -0,0 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +export default function Row( { children, className } ) { + return
{ children }
; +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/square.js b/client/gutenberg/extensions/tiled-gallery/layout/square.js new file mode 100644 index 0000000000000..2a1ab888b1916 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/square.js @@ -0,0 +1,33 @@ +/** + * External dependencies + */ +import { chunk, drop, take } from 'lodash'; + +/** + * Internal dependencies + */ +import Row from './row'; +import Column from './column'; +import Gallery from './gallery'; +import { MAX_COLUMNS } from '../constants'; + +export default function Square( { columns, renderedImages } ) { + const columnCount = Math.min( MAX_COLUMNS, columns ); + + const remainder = renderedImages.length % columnCount; + + return ( + + { [ + ...( remainder ? [ take( renderedImages, remainder ) ] : [] ), + ...chunk( drop( renderedImages, remainder ), columnCount ), + ].map( ( imagesInRow, rowIndex ) => ( + + { imagesInRow.map( ( image, colIndex ) => ( + { image } + ) ) } + + ) ) } + + ); +} diff --git a/client/gutenberg/extensions/tiled-gallery/layout/test/fixtures/image-sets.js b/client/gutenberg/extensions/tiled-gallery/layout/test/fixtures/image-sets.js new file mode 100644 index 0000000000000..07c6bef746a9a --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layout/test/fixtures/image-sets.js @@ -0,0 +1,117 @@ +export const imageSet1 = [ + { + alt: '', + id: 163, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/architecture-bay-bridge-356830.jpg', + height: 2048, + width: 8192, + }, + { + alt: '', + id: 162, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/bloom-blossom-flora-40797-1.jpg', + height: 1562, + width: 3531, + }, + { + alt: '', + id: 161, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/architecture-building-city-597049.jpg', + height: 4221, + width: 2818, + }, + { + alt: '', + id: 160, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/architecture-art-blue-699466.jpg', + height: 4032, + width: 3024, + }, + { + alt: '', + id: 159, + caption: '', + url: + 'https://example.files.wordpress.com/2018/12/black-and-white-construction-ladder-54335.jpg', + height: 3193, + width: 2377, + }, + { + alt: '', + id: 158, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/architecture-buildings-city-1672110.jpg', + height: 6000, + width: 4000, + }, + { + alt: '', + id: 157, + caption: '', + url: + 'https://example.files.wordpress.com/2018/12/architectural-design-architecture-black-and-white-1672122-1.jpg', + height: 3401, + width: 2721, + }, + { + alt: '', + id: 156, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/grass-hd-wallpaper-lake-127753.jpg', + height: 2198, + width: 7999, + }, + { + alt: '', + id: 122, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/texaco-car-1.jpg', + height: 599, + width: 800, + }, + { + alt: '', + id: 92, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/43824553435_ea38cbc92a_m.jpg', + height: 159, + width: 240, + }, + { + alt: '', + id: 90, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/42924685680_7b5632e58e_m.jpg', + height: 150, + width: 240, + }, + { + alt: '', + id: 89, + caption: '', + url: + 'https://example.files.wordpress.com/2018/12/31962299833_1e106f7f7a_z-1-e1545262352979.jpg', + height: 427, + width: 564, + }, + { + alt: '', + id: 88, + caption: '', + url: 'https://example.files.wordpress.com/2018/12/29797558147_3c72afa8f4_k.jpg', + height: 1511, + width: 2048, + }, + { + alt: '', + id: 8, + caption: '', + url: 'https://example.files.wordpress.com/2018/11/person-smartphone-office-table.jpeg', + height: 1067, + width: 1600, + }, +]; diff --git a/client/gutenberg/extensions/tiled-gallery/layouts.js b/client/gutenberg/extensions/tiled-gallery/layouts.js deleted file mode 100644 index 54d7474957f42..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/layouts.js +++ /dev/null @@ -1,134 +0,0 @@ -/** @format */ - -/** - * External dependencies - */ -import { find } from 'lodash'; -import TokenList from '@wordpress/token-list'; - -/** - * Internal dependencies - */ -import { LAYOUT_STYLES, MAX_COLUMNS, TILE_MARGIN } from './constants'; -import { rectangularLayout } from './tiled-grid'; - -function squareLayout( { columns, margin, width, tileCount } ) { - columns = Math.min( MAX_COLUMNS, columns ); - const tilesPerRow = columns > 1 ? columns : 1; - const marginSpace = tilesPerRow * margin * 2; - const size = Math.floor( ( width - marginSpace ) / tilesPerRow ); - let remainderSize = size; - let tileSize = remainderSize; - const remainder = tileCount % tilesPerRow; - let remainderSpace = 0; - - if ( remainder > 0 ) { - remainderSpace = remainder * margin * 2; - remainderSize = Math.floor( ( width - remainderSpace ) / remainder ); - } - - let c = 1; - let tilesInRow = 0; - const rows = []; - let row = { - tiles: [], - }; - - for ( let i = 0; i < tileCount; i++ ) { - if ( remainder > 0 && c <= remainder ) { - tileSize = remainderSize; - } else { - tileSize = size; - } - - row.tiles.push( { - height: tileSize, - width: tileSize, - } ); - - c++; - tilesInRow++; - - if ( tilesPerRow === tilesInRow || remainder + 1 === c ) { - rows.push( row ); - tilesInRow = 0; - - row.height = tileSize + margin * 2; - row.width = width; - row.groupSize = tileSize + 2 * margin; - - row = { - tiles: [], - }; - } - } - - if ( row.tiles.length > 0 ) { - row.height = tileSize + margin * 2; - row.width = width; - row.groupSize = tileSize + 2 * margin; - - rows.push( row ); - } - - return rows; -} - -export function getLayout( { columns, images, layout, width } ) { - switch ( layout ) { - // @TODO Columns is unimplemented, fallthrough to square - case 'columns': - if ( process.env.NODE_ENV !== 'production' ) { - // eslint-disable-next-line no-console - console.warn( 'Columns layout is unimplemented. Fallback to square' ); - } - - // Circle and square rely on the same layout - case 'square': - case 'circle': { - return squareLayout( { - columns, - contentWidth: width, - tileCount: images.length, - margin: TILE_MARGIN, - } ); - } - case 'rectangular': - default: - return rectangularLayout( { - contentWidth: width, - images, - } ); - } -} - -/** - * Returns the active style from the given className. - * - * @param {Array} styles Block style variations. - * @param {string} className Class name - * - * @return {Object?} The active style. - * - * From https://github.com/WordPress/gutenberg/blob/077f6c4eb9ba061bc00d5f3ae956d4789a291fb5/packages/editor/src/components/block-styles/index.js#L21-L43 - */ -function getActiveStyle( styles, className ) { - for ( const style of new TokenList( className ).values() ) { - if ( style.indexOf( 'is-style-' ) === -1 ) { - continue; - } - - const potentialStyleName = style.substring( 9 ); - const activeStyle = find( styles, { name: potentialStyleName } ); - if ( activeStyle ) { - return activeStyle; - } - } - - return find( styles, 'isDefault' ); -} - -export function getActiveStyleName( className ) { - const activeStyle = getActiveStyle( LAYOUT_STYLES, className ); - return activeStyle.name; -} diff --git a/client/gutenberg/extensions/tiled-gallery/save.jsx b/client/gutenberg/extensions/tiled-gallery/save.jsx index 31869a69aff52..893dfd7983a9c 100644 --- a/client/gutenberg/extensions/tiled-gallery/save.jsx +++ b/client/gutenberg/extensions/tiled-gallery/save.jsx @@ -1,82 +1,28 @@ -/** @format */ - -/** - * External dependencies - */ -import { RichText } from '@wordpress/editor'; -import classnames from 'classnames'; - /** * Internal dependencies */ +import Layout from './layout'; import { defaultColumnsNumber } from './edit'; -import GalleryGrid from './gallery-grid'; -import { getActiveStyleName } from './layouts'; - -export default ( { attributes } ) => { - const { - align, - className, - columns = defaultColumnsNumber( attributes ), - imageCrop, - images, - linkTo, - } = attributes; - - const layout = getActiveStyleName( className ); - - const renderGalleryImage = index => { - if ( ! images[ index ] ) { - return null; - } - - const image = images[ index ]; - - let href; +import { getActiveStyleName } from 'gutenberg/extensions/utils'; +import { LAYOUT_STYLES } from './constants'; - switch ( linkTo ) { - case 'media': - href = image.url; - break; - case 'attachment': - href = image.link; - break; - } +export default function TiledGallerySave( { attributes } ) { + const { images } = attributes; - const img = ( - { - ); + if ( ! images.length ) { + return null; + } - return ( -
- { href ? { img } : img } - { layout !== 'circle' && - image.caption && - image.caption.length > 0 && ( - - ) } -
- ); - }; + const { className, columns = defaultColumnsNumber( attributes ), linkTo } = attributes; return ( - ); -}; +} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/index.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/index.js deleted file mode 100644 index 547079681d044..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/index.js +++ /dev/null @@ -1,82 +0,0 @@ -/** @format */ - -// Originally `Jetpack_Constrained_Array_Rounding` class from: -// https://github.com/Automattic/jetpack/blob/0d837791212dcfab0e75145a21857cc507e4c9d3/modules/tiled-gallery/math/class-constrained-array-rounding.php - -/** - * External dependencies - */ -import { map, sum } from 'lodash'; - -const get_int_floor_array = bound_array => { - return bound_array.map( ( value, i ) => ( { - floor: Math.floor( value ), - fraction: value - Math.floor( value ), - index: i, - } ) ); -}; - -const adjust_constrained_array = ( bound_array_int, adjustment ) => { - // Sorting function here was `cmp_desc_fraction()` in PHP - bound_array_int = bound_array_int.sort( ( a, b ) => { - if ( a.fraction === b.fraction ) { - return 0; - } - return a.fraction > b.fraction ? -1 : 1; - } ); - - const end = adjustment - 1; - - for ( let i = 0; i <= end; i++ ) { - bound_array_int[ i % bound_array_int.length ].floor++; - } - - // Sorting function here was `cmp_asc_index()` in PHP - return bound_array_int.sort( ( a, b ) => { - if ( a.index === b.index ) { - return 0; - } - return a.index < b.index ? -1 : 1; - } ); -}; - -/** - * Lets you round the numeric elements of an array to integers while preserving their sum. - * - * Usage: - * - * If a specific sum doesn't need to be specified for the bound array: - * ``` - * getRoundedConstrainedArray( bound_array ) - * ``` - * - * If the sum of bound_array must equal sum_value after rounding: - * ``` - * getRoundedConstrainedArray( bound_array, sum_value ) - * ``` - * - * If sum_value is less than the sum of the floor of the elements of the array, - * the function defaults to using the sum of the array elements. - * - * @param {Array} bound_array Array with numeric values - * @param {Boolean|Integer} sum_value Value that the sum of bound_array must equal after rounding - * - * @returns {Array} Array with numeric elements rounded to integers, while their sum is preserved. - */ -export const getRoundedConstrainedArray = ( bound_array, sum_value = false ) => { - let bound_array_int = get_int_floor_array( bound_array ); - - const lower_sum = sum( map( bound_array_int, 'floor' ) ); - - if ( ! sum_value || sum_value < lower_sum ) { - // If value of sum is not supplied or is invalid, - // calculate the sum that the returned array is constrained to match - sum_value = sum( bound_array ); - } - - const diff_sum = sum_value - lower_sum; - - bound_array_int = adjust_constrained_array( bound_array_int, diff_sum ); - - return map( bound_array_int, 'floor' ); -}; diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/test/index.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/test/index.js deleted file mode 100644 index 6970479576266..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/constrained-array-rounding/test/index.js +++ /dev/null @@ -1,18 +0,0 @@ -/** @format */ - -/** - * Internal dependencies - */ -import { getRoundedConstrainedArray } from '..'; - -describe( 'getRoundedConstrainedArray', () => { - test( 'Round floats to integers that fit the row', () => { - const rounded = getRoundedConstrainedArray( [ 427.33333333333337, 212.66666666666669 ], 640 ); - expect( rounded ).toEqual( [ 427, 213 ] ); - } ); - - test( 'No changes in integers that fit the row', () => { - const rounded = getRoundedConstrainedArray( [ 320, 320 ], 640 ); - expect( rounded ).toEqual( [ 320, 320 ] ); - } ); -} ); diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/group.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/group.js deleted file mode 100644 index b1ad889e4c4f8..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/group.js +++ /dev/null @@ -1,21 +0,0 @@ -export class Jetpack_Tiled_Gallery_Group { - constructor( images ) { - this.images = images; - this.ratio = this.get_ratio(); - } - - get_ratio = () => { - let ratio = 0; - for ( const image of this.images ) { - if ( image.ratio ) { - ratio += 1 / image.ratio; - } - } - - if ( ! ratio ) { - return 1; - } - - return 1 / ratio; - }; -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/grouper.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/grouper.js deleted file mode 100644 index 41531351bb290..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/grouper.js +++ /dev/null @@ -1,193 +0,0 @@ -/** - * External dependencies - */ -import { cloneDeep, find, repeat } from 'lodash'; - -/** - * Internal dependencies - */ -import { getRoundedConstrainedArray } from './constrained-array-rounding'; -import { Jetpack_Tiled_Gallery_Group } from './group.js'; -import { Jetpack_Tiled_Gallery_Row } from './row.js'; -import { - Five, - Four, - Jetpack_Tiled_Gallery_Shape, - Long_Symmetric_Row, - One_Three, - One_Two, - Panoramic, - Reverse_Symmetric_Row, - Symmetric_Row, - Three, - Three_One, - Two, - Two_One, -} from './shapes'; - -export class Jetpack_Tiled_Gallery_Grouper { - contentWidth; - - margin; - - // This list is ordered. If you put a shape that's likely to occur on top, it will happen all the time. - shapes = Object.freeze( [ - Reverse_Symmetric_Row, - Long_Symmetric_Row, - Symmetric_Row, - One_Three, - Three_One, - One_Two, - Five, - Four, - Three, - Two_One, - Panoramic, - Two, // Fallback option, always matches - ] ); - - images = []; - - constructor( { attachments, contentWidth, margin } ) { - this.contentWidth = contentWidth; - this.margin = margin; - - // @TODO This appears to be a pipeline attachments -> grouped images - // Layouts want grouped_images to define their rows - // - // This module could (should) become a transformation of > -> > - // - // If we redesign with that flow in mind, this may get much simpler and more testable - this.images = this.get_images_with_sizes( - // Use cloneDeep to avoid mutating the received attachments - // @FIXME In a future iteration, don't mutate and drop cloneDeep - cloneDeep( attachments ) - ); - this.grouped_images = this.get_grouped_images(); - this.apply_content_width( contentWidth ); - } - - get_current_row_size() { - if ( this.images.length < 3 ) { - return repeat( 1, this.images.length ); - } - - const Shape = find( this.shapes, Klass => { - return new Klass( this.images, this.contentWidth ).is_possible(); - } ); - - if ( Shape ) { - Jetpack_Tiled_Gallery_Shape.set_last_shape( Shape ); - return Shape.shape; - } - - Jetpack_Tiled_Gallery_Shape.set_last_shape( Two ); - return Two.shape; - } - - get_images_with_sizes = attachments => { - const images_with_sizes = []; - - // @TODO let's `return map( images… )` - for ( const image of attachments ) { - image.width_orig = image.width && image.width > 0 ? image.width : 1; - image.height_orig = image.height && image.height > 0 ? image.height : 1; - image.ratio = image.width_orig / image.height_orig; - image.ratio = image.ratio ? image.ratio : 1; - images_with_sizes.push( image ); - } - - return images_with_sizes; - }; - - read_row = () => { - const vector = this.get_current_row_size(); - - // @TODO `return map( vector… )` - const row = []; - for ( const group_size of vector ) { - // @TODO This deeply nested mutation drives iteration, can we improve that? - row.push( new Jetpack_Tiled_Gallery_Group( this.images.splice( 0, group_size ) ) ); - } - - return row; - }; - - // @FIXME In conjuction with read_row - get_grouped_images = () => { - const grouped_images = []; - - // this.read_row mutates this.images - while ( this.images.length ) { - grouped_images.push( new Jetpack_Tiled_Gallery_Row( this.read_row() ) ); - } - - return grouped_images; - }; - - apply_content_width = contentWidth => { - for ( const row of this.grouped_images ) { - row.width = contentWidth; - row.raw_height = - ( 1 / row.ratio ) * - ( contentWidth - this.margin * ( row.groups.length - row.weighted_ratio ) ); - row.height = Math.round( row.raw_height ); - - this.calculate_group_sizes( row ); - } - }; - - /** - * @TODO - * - * The following two methods are virtually same, right? 🤨 - * One for width, one for height? - * - * Area for improvement. - */ - - calculate_group_sizes = row => { - // Storing the calculated group heights in an array for rounding them later while preserving their sum - // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery - const group_widths_array = []; - for ( const group of row.groups ) { - group.height = row.height; - // Storing the raw calculations in a separate property to prevent - // rounding errors from cascading down and for diagnostics - group.raw_width = - ( row.raw_height - this.margin * group.images.length ) * group.ratio + this.margin; - group_widths_array.push( group.raw_width ); - } - - const rounded_group_widths_array = getRoundedConstrainedArray( group_widths_array, row.width ); - - for ( const group of row.groups ) { - group.width = rounded_group_widths_array.shift(); - this.calculate_image_sizes( group ); - } - }; - - calculate_image_sizes = group => { - // Storing the calculated image heights in an array for rounding them later while preserving their sum - // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery - const image_heights_array = []; - for ( const image of group.images ) { - image.width = group.width - this.margin; - // Storing the raw calculations in a separate property for diagnostics - image.raw_height = ( group.raw_width - this.margin ) / image.ratio; - image_heights_array.push( image.raw_height ); - } - - const image_height_sum = group.height - image_heights_array.length * this.margin; - const rounded_image_heights_array = getRoundedConstrainedArray( - image_heights_array, - image_height_sum - ); - - for ( const image of group.images ) { - // @TODO check what happens to `rounded_image_heights_array` - // in PHP `array_shift([])` vs JS `[].shift()` and if it has affects here - image.height = rounded_image_heights_array.shift(); - } - }; -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/index.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/index.js deleted file mode 100644 index 76fc85b33661f..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/index.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Grouper } from './grouper'; -import { Jetpack_Tiled_Gallery_Shape } from './shapes/jetpack-tiled-gallery-shape'; -import { DEFAULT_GALLERY_WIDTH, TILE_MARGIN } from '../constants.js'; - -/* - * Rectangular tiled gallery layout - * - * Implements `Jetpack_Tiled_Gallery_Layout_Rectangular` from: - * https://github.com/Automattic/jetpack/blob/0d837791212dcfab0e75145a21857cc507e4c9d3/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php - */ -export const rectangularLayout = ( { - images, - margin = TILE_MARGIN, - contentWidth = DEFAULT_GALLERY_WIDTH, -} ) => { - const grouper = new Jetpack_Tiled_Gallery_Grouper( { - attachments: images, - contentWidth, - margin, - } ); - Jetpack_Tiled_Gallery_Shape.reset_last_shape(); - return grouper.grouped_images; -}; diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/row.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/row.js deleted file mode 100644 index d18d52d2cd921..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/row.js +++ /dev/null @@ -1,23 +0,0 @@ -export class Jetpack_Tiled_Gallery_Row { - constructor( groups ) { - this.groups = groups; - this.ratio = this.get_ratio(); - this.weighted_ratio = this.get_weighted_ratio(); - } - - get_ratio = () => { - let ratio = 0; - for ( const group of this.groups ) { - ratio += group.ratio; - } - return ratio > 0 ? ratio : 1; - }; - - get_weighted_ratio = () => { - let weighted_ratio = 0; - for ( const group of this.groups ) { - weighted_ratio += group.ratio * group.images.length; - } - return weighted_ratio > 0 ? weighted_ratio : 1; - }; -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/five.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/five.js deleted file mode 100644 index d4aec6cc99998..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/five.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Five extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 1, 1, 1, 1 ]; - - is_possible() { - return ( - this.is_wide_theme() && - this.is_not_as_previous() && - this.sum_ratios( 5 ) < 5 && - ( this.images_left === 5 || ( this.images_left !== 10 && this.images_left > 6 ) ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/four.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/four.js deleted file mode 100644 index fe5db44f216eb..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/four.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Four extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 1, 1, 1 ]; - - is_possible() { - return ( - this.is_not_as_previous() && - ( ( this.sum_ratios( 4 ) < 3.5 && this.images_left > 5 ) || - ( this.sum_ratios( 4 ) < 7 && this.images_left === 4 ) ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/index.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/index.js deleted file mode 100644 index 61040b2258d25..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/index.js +++ /dev/null @@ -1,13 +0,0 @@ -export { Five } from './five'; -export { Four } from './four'; -export { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; -export { Long_Symmetric_Row } from './long-symmetric-row'; -export { One_Three } from './one-three'; -export { One_Two } from './one-two'; -export { Panoramic } from './panoramic'; -export { Reverse_Symmetric_Row } from './reverse-symmetric-row'; -export { Symmetric_Row } from './symmetric-row'; -export { Three } from './three'; -export { Three_One } from './three-one'; -export { Two } from './two'; -export { Two_One } from './two-one'; diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/jetpack-tiled-gallery-shape.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/jetpack-tiled-gallery-shape.js deleted file mode 100644 index e71c3ee44b550..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/jetpack-tiled-gallery-shape.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * External dependencies - */ -import { map, property, sum, take } from 'lodash'; - -export class Jetpack_Tiled_Gallery_Shape { - constructor( images, contentWidth ) { - this.contentWidth = contentWidth; - this.images = images; - this.images_left = images.length; - } - - static shapes_used = []; - - static set_last_shape( last_shape ) { - this.shapes_used.push( last_shape ); - } - - static reset_last_shape() { - this.shapes_used = []; - } - - sum_ratios( number_of_images = 3 ) { - return sum( map( take( this.images, number_of_images ), property( 'ratio' ) ) ); - } - - next_images_are_symmetric = () => { - return this.images_left > 2 && this.images[ 0 ].ratio === this.images[ 2 ].ratio; - }; - - is_not_as_previous( n = 1 ) { - return ! take( Jetpack_Tiled_Gallery_Shape.shapes_used, n ).includes( this.constructor ); - } - - // - // Replace this with something more appropriate. - // - // Check for full/wide block alignment? - // - // https://github.com/WordPress/gutenberg/blob/0416bae17c52b0a11ec1075c0928f879264b7d75/packages/editor/src/components/block-alignment-toolbar/index.js#L80 - // - is_wide_theme = () => { - return this.contentWidth > 1000; - }; - - image_is_landscape = image => { - return image.ratio >= 1 && image.ratio < 2; - }; - - image_is_portrait = image => { - return image.ratio < 1; - }; - - image_is_panoramic = image => { - return image.ratio >= 2; - }; -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/long-symmetric-row.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/long-symmetric-row.js deleted file mode 100644 index 8bac01fc4092a..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/long-symmetric-row.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Long_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 3, 1, 3 ]; - - is_possible() { - return ( - this.is_not_as_previous( 5 ) && - this.images_left > 15 && - this.image_is_landscape( this.images[ 0 ] ) && - this.image_is_landscape( this.images[ 1 ] ) && - this.image_is_landscape( this.images[ 2 ] ) && - this.image_is_portrait( this.images[ 3 ] ) && - this.image_is_landscape( this.images[ 4 ] ) && - this.image_is_landscape( this.images[ 5 ] ) && - this.image_is_landscape( this.images[ 6 ] ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-three.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-three.js deleted file mode 100644 index ac2a9a4ff108c..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-three.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class One_Three extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 3 ]; - - is_possible() { - return ( - this.is_not_as_previous( 3 ) && - this.images_left > 3 && - this.image_is_portrait( this.images[ 0 ] ) && - this.image_is_landscape( this.images[ 1 ] ) && - this.image_is_landscape( this.images[ 2 ] ) && - this.image_is_landscape( this.images[ 3 ] ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-two.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-two.js deleted file mode 100644 index fcbbff95547fb..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/one-two.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class One_Two extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 2 ]; - - // This seems buggy, we check >= 2 images, but look at 0,1,2?? - // https://github.com/Automattic/jetpack/blob/e07addf220d02226f04d874b1b565ceb9f502839/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php#L91-L94 - is_possible() { - return ( - this.is_not_as_previous( 3 ) && - this.images_left >= 2 && - this.images[ 0 ].ratio < 1.6 && - this.images[ 1 ].ratio >= 0.9 && - this.images[ 1 ].ratio < 2.0 && - this.images[ 2 ].ratio >= 0.9 && - this.images[ 2 ].ratio < 2.0 - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/panoramic.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/panoramic.js deleted file mode 100644 index e8ae3d5ba30a6..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/panoramic.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Panoramic extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1 ]; - - is_possible() { - return this.image_is_panoramic( this.images[ 0 ] ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/reverse-symmetric-row.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/reverse-symmetric-row.js deleted file mode 100644 index 6bf20c3228998..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/reverse-symmetric-row.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Reverse_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 2, 1, 2 ]; - - is_possible() { - return ( - this.is_not_as_previous( 5 ) && - this.images_left > 15 && - this.image_is_landscape( this.images[ 0 ] ) && - this.image_is_landscape( this.images[ 1 ] ) && - this.image_is_portrait( this.images[ 2 ] ) && - this.image_is_landscape( this.images[ 3 ] ) && - this.image_is_landscape( this.images[ 4 ] ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/symmetric-row.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/symmetric-row.js deleted file mode 100644 index e464b13711ade..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/symmetric-row.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Symmetric_Row extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 2, 1 ]; - - is_possible() { - return ( - this.is_not_as_previous( 5 ) && - this.images_left > 3 && - this.images_left !== 5 && - this.image_is_portrait( this.images[ 0 ] ) && - this.image_is_landscape( this.images[ 1 ] ) && - this.image_is_landscape( this.images[ 2 ] ) && - this.image_is_portrait( this.images[ 3 ] ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/test/jetpack-tiled-gallery-shape.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/test/jetpack-tiled-gallery-shape.js deleted file mode 100644 index f13eb18fee3c6..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/test/jetpack-tiled-gallery-shape.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from '../jetpack-tiled-gallery-shape'; - -describe( 'Jetpack_Tiled_Gallery_Shape', () => { - test( 'constructor', () => { - const contentWidth = 640; - const images = [ {}, {} ]; - const instance = new Jetpack_Tiled_Gallery_Shape( images, contentWidth ); - - expect( instance.images ).toBe( images ); - instance.images.map( ( img, i ) => expect( img ).toBe( images[ i ] ) ); - expect( instance.images_left ).toBe( 2 ); - } ); - - describe( 'sum_ratios', () => { - const vals = [ 3, 5, 7, 9, 13 ]; - let instance = beforeEach( () => { - const contentWidth = 640; - const images = vals.map( v => ( { ratio: v } ) ); - instance = new Jetpack_Tiled_Gallery_Shape( images, contentWidth ); - } ); - - test( 'sums', () => { - expect( instance.sum_ratios( 2 ) ).toBe( 3 + 5 ); - expect( instance.sum_ratios( vals.length ) ).toBe( 3 + 5 + 7 + 9 + 13 ); - } ); - } ); -} ); diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three-one.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three-one.js deleted file mode 100644 index 792803ff4b19f..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three-one.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Three_One extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 3, 1 ]; - - is_possible() { - return ( - this.is_not_as_previous( 3 ) && - this.images_left > 3 && - this.image_is_portrait( this.images[ 3 ] ) && - this.image_is_landscape( this.images[ 0 ] ) && - this.image_is_landscape( this.images[ 1 ] ) && - this.image_is_landscape( this.images[ 2 ] ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three.js deleted file mode 100644 index e7202a4c20b1e..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/three.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Three extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 1, 1 ]; - - is_possible() { - const ratio = this.sum_ratios( 3 ); - const hasEnoughImages = this.images_left >= 3 && ! [ 4, 6 ].includes( this.images_left ); - return ( - hasEnoughImages && - this.is_not_as_previous( 3 ) && - ( ratio < 2.5 || ( ratio < 5 && this.next_images_are_symmetric() ) || this.is_wide_theme() ) - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two-one.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two-one.js deleted file mode 100644 index 0b4cf03846a30..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two-one.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Two_One extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 2, 1 ]; - - // This seems buggy, we check >= 2 images, but look at 0,1,2?? - // https://github.com/Automattic/jetpack/blob/e07addf220d02226f04d874b1b565ceb9f502839/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php#L83-L84 - is_possible() { - return ( - this.is_not_as_previous( 3 ) && - this.images_left >= 2 && - this.images[ 2 ].ratio < 1.6 && - this.images[ 0 ].ratio >= 0.9 && - this.images[ 0 ].ratio < 2.0 && - this.images[ 1 ].ratio >= 0.9 && - this.images[ 1 ].ratio < 2.0 - ); - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two.js deleted file mode 100644 index 8eaee0b7b86f9..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/shapes/two.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Internal dependencies - */ -import { Jetpack_Tiled_Gallery_Shape } from './jetpack-tiled-gallery-shape'; - -export class Two extends Jetpack_Tiled_Gallery_Shape { - static shape = [ 1, 1 ]; - - is_possible() { - return true; - } -} diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/__snapshots__/grouper.js.snap b/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/__snapshots__/grouper.js.snap deleted file mode 100644 index 2cc1caca34f76..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/__snapshots__/grouper.js.snap +++ /dev/null @@ -1,376 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`grouper groups as expected 1`] = ` -Array [ - Jetpack_Tiled_Gallery_Row { - "get_ratio": [Function], - "get_weighted_ratio": [Function], - "groups": Array [ - Jetpack_Tiled_Gallery_Group { - "get_ratio": [Function], - "height": 282, - "images": Array [ - Object { - "file": "2018/09/demo1.jpg", - "height": 278, - "height_orig": 3648, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.5, - "raw_height": 278.23361711843955, - "sizes": Object { - "large": Object { - "file": "demo1-1024x683.jpg", - "height": 683, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo1-300x200.jpg", - "height": 200, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo1-768x512.jpg", - "height": 512, - "mime-type": "image/jpeg", - "width": 768, - }, - "thumbnail": Object { - "file": "demo1-150x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 417, - "width_orig": 5472, - }, - ], - "ratio": 1.5, - "raw_width": 421.35042567765936, - "width": 421, - }, - Jetpack_Tiled_Gallery_Group { - "get_ratio": [Function], - "height": 282, - "images": Array [ - Object { - "file": "2018/09/demo2.jpg", - "height": 143, - "height_orig": 3264, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.5, - "raw_height": 143.09971621489385, - "sizes": Object { - "large": Object { - "file": "demo2-1024x683.jpg", - "height": 683, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo2-300x200.jpg", - "height": 200, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo2-768x512.jpg", - "height": 512, - "mime-type": "image/jpeg", - "width": 768, - }, - "thumbnail": Object { - "file": "demo2-150x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 215, - "width_orig": 4896, - }, - Object { - "file": "2018/09/demo3.jpg", - "height": 131, - "height_orig": 3211, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.6368732482092807, - "raw_height": 131.1339009035457, - "sizes": Object { - "large": Object { - "file": "demo3-1024x626.jpg", - "height": 626, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo3-300x183.jpg", - "height": 183, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo3-768x469.jpg", - "height": 469, - "mime-type": "image/jpeg", - "width": 768, - }, - "post-thumbnail": Object { - "file": "demo3-1200x733.jpg", - "height": 733, - "mime-type": "image/jpeg", - "width": 1200, - }, - "thumbnail": Object { - "file": "demo3-150x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 215, - "width_orig": 5256, - }, - ], - "ratio": 0.7827252419955324, - "raw_width": 218.64957432234078, - "width": 219, - }, - ], - "height": 282, - "ratio": 2.282725241995532, - "raw_height": 282.23361711843955, - "weighted_ratio": 3.065450483991065, - "width": 640, - }, - Jetpack_Tiled_Gallery_Row { - "get_ratio": [Function], - "get_weighted_ratio": [Function], - "groups": Array [ - Jetpack_Tiled_Gallery_Group { - "get_ratio": [Function], - "height": 279, - "images": Array [ - Object { - "file": "2018/09/demo4.jpg", - "height": 137, - "height_orig": 1600, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.6, - "raw_height": 137.094, - "sizes": Object { - "large": Object { - "file": "demo4-1024x640.jpg", - "height": 640, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo4-300x188.jpg", - "height": 188, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo4-768x480.jpg", - "height": 480, - "mime-type": "image/jpeg", - "width": 768, - }, - "post-thumbnail": Object { - "file": "demo4-1200x750.jpg", - "height": 750, - "mime-type": "image/jpeg", - "width": 1200, - }, - "thumbnail": Object { - "file": "demo4-150x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 219, - "width_orig": 2560, - }, - Object { - "file": "2018/09/demo5.jpg", - "height": 134, - "height_orig": 3211, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.6368732482092807, - "raw_height": 134.00573333333332, - "sizes": Object { - "large": Object { - "file": "demo3024x626.jpg", - "height": 626, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo5-300x183.jpg", - "height": 183, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo5-768x469.jpg", - "height": 469, - "mime-type": "image/jpeg", - "width": 768, - }, - "post-thumbnail": Object { - "file": "demo3200x733.jpg", - "height": 733, - "mime-type": "image/jpeg", - "width": 1200, - }, - "thumbnail": Object { - "file": "demo350x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 219, - "width_orig": 5256, - }, - ], - "ratio": 0.8091133004926109, - "raw_width": 223.3504, - "width": 223, - }, - Jetpack_Tiled_Gallery_Group { - "get_ratio": [Function], - "height": 279, - "images": Array [ - Object { - "file": "2018/09/demo6.jpg", - "height": 275, - "height_orig": 2848, - "image_meta": Object { - "aperture": "0", - "camera": "", - "caption": "", - "copyright": "", - "created_timestamp": "0", - "credit": "", - "focal_length": "0", - "iso": "0", - "keywords": Array [], - "orientation": "0", - "shutter_speed": "0", - "title": "", - }, - "ratio": 1.5, - "raw_height": 275.09973333333335, - "sizes": Object { - "large": Object { - "file": "demo6-1024x683.jpg", - "height": 683, - "mime-type": "image/jpeg", - "width": 1024, - }, - "medium": Object { - "file": "demo6-300x200.jpg", - "height": 200, - "mime-type": "image/jpeg", - "width": 300, - }, - "medium_large": Object { - "file": "demo6-768x512.jpg", - "height": 512, - "mime-type": "image/jpeg", - "width": 768, - }, - "thumbnail": Object { - "file": "demo6-150x150.jpg", - "height": 150, - "mime-type": "image/jpeg", - "width": 150, - }, - }, - "width": 413, - "width_orig": 4272, - }, - ], - "ratio": 1.5, - "raw_width": 416.6496, - "width": 417, - }, - ], - "height": 279, - "ratio": 2.3091133004926108, - "raw_height": 279.09973333333335, - "weighted_ratio": 3.1182266009852215, - "width": 640, - }, -] -`; diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/fixtures/attachments.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/fixtures/attachments.js deleted file mode 100644 index b458b50e70676..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/fixtures/attachments.js +++ /dev/null @@ -1,300 +0,0 @@ -/** - * External dependencies - */ -import deepFreeze from 'deep-freeze'; - -export const attachments = deepFreeze( [ - { - width: 5472, - height: 3648, - file: '2018/09/demo1.jpg', - sizes: { - thumbnail: { - file: 'demo1-150x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo1-300x200.jpg', - width: 300, - height: 200, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo1-768x512.jpg', - width: 768, - height: 512, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo1-1024x683.jpg', - width: 1024, - height: 683, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, - - { - width: 4896, - height: 3264, - file: '2018/09/demo2.jpg', - sizes: { - thumbnail: { - file: 'demo2-150x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo2-300x200.jpg', - width: 300, - height: 200, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo2-768x512.jpg', - width: 768, - height: 512, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo2-1024x683.jpg', - width: 1024, - height: 683, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, - - { - width: 5256, - height: 3211, - file: '2018/09/demo3.jpg', - sizes: { - thumbnail: { - file: 'demo3-150x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo3-300x183.jpg', - width: 300, - height: 183, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo3-768x469.jpg', - width: 768, - height: 469, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo3-1024x626.jpg', - width: 1024, - height: 626, - 'mime-type': 'image/jpeg', - }, - 'post-thumbnail': { - file: 'demo3-1200x733.jpg', - width: 1200, - height: 733, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, - - { - width: 2560, - height: 1600, - file: '2018/09/demo4.jpg', - sizes: { - thumbnail: { - file: 'demo4-150x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo4-300x188.jpg', - width: 300, - height: 188, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo4-768x480.jpg', - width: 768, - height: 480, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo4-1024x640.jpg', - width: 1024, - height: 640, - 'mime-type': 'image/jpeg', - }, - 'post-thumbnail': { - file: 'demo4-1200x750.jpg', - width: 1200, - height: 750, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, - - { - width: 5256, - height: 3211, - file: '2018/09/demo5.jpg', - sizes: { - thumbnail: { - file: 'demo350x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo5-300x183.jpg', - width: 300, - height: 183, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo5-768x469.jpg', - width: 768, - height: 469, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo3024x626.jpg', - width: 1024, - height: 626, - 'mime-type': 'image/jpeg', - }, - 'post-thumbnail': { - file: 'demo3200x733.jpg', - width: 1200, - height: 733, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, - - { - width: 4272, - height: 2848, - file: '2018/09/demo6.jpg', - sizes: { - thumbnail: { - file: 'demo6-150x150.jpg', - width: 150, - height: 150, - 'mime-type': 'image/jpeg', - }, - medium: { - file: 'demo6-300x200.jpg', - width: 300, - height: 200, - 'mime-type': 'image/jpeg', - }, - medium_large: { - file: 'demo6-768x512.jpg', - width: 768, - height: 512, - 'mime-type': 'image/jpeg', - }, - large: { - file: 'demo6-1024x683.jpg', - width: 1024, - height: 683, - 'mime-type': 'image/jpeg', - }, - }, - image_meta: { - aperture: '0', - credit: '', - camera: '', - caption: '', - created_timestamp: '0', - copyright: '', - focal_length: '0', - iso: '0', - shutter_speed: '0', - title: '', - orientation: '0', - keywords: [], - }, - }, -] ); diff --git a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/grouper.js b/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/grouper.js deleted file mode 100644 index 93c8cb94c687e..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/tiled-grid/test/grouper.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * External dependencies - */ -import { cloneDeep } from 'lodash'; - -/** - * Internal dependencies - */ -import { attachments } from './fixtures/attachments'; -import { Jetpack_Tiled_Gallery_Grouper } from '../grouper'; - -describe( 'grouper', () => { - test( 'groups as expected', () => { - const grouper = new Jetpack_Tiled_Gallery_Grouper( { - attachments: cloneDeep( attachments ), - contentWidth: 640, - margin: 4, - } ); - expect( grouper.grouped_images ).toMatchSnapshot(); - } ); -} ); diff --git a/client/gutenberg/extensions/tiled-gallery/variables.scss b/client/gutenberg/extensions/tiled-gallery/variables.scss index a9bc2c745447a..f5a7177060370 100644 --- a/client/gutenberg/extensions/tiled-gallery/variables.scss +++ b/client/gutenberg/extensions/tiled-gallery/variables.scss @@ -1,4 +1,3 @@ - $tiled-gallery-add-item-border-color: #555d66; // Gutenberg $dark-gray-500 $tiled-gallery-add-item-border-width: 1px; // Gutenberg $border-width $tiled-gallery-caption-background-color: #000; diff --git a/client/gutenberg/extensions/tiled-gallery/view.js b/client/gutenberg/extensions/tiled-gallery/view.js index 57cb7d5c1a579..192236b73bd41 100644 --- a/client/gutenberg/extensions/tiled-gallery/view.js +++ b/client/gutenberg/extensions/tiled-gallery/view.js @@ -1,88 +1,41 @@ -/** @format */ - -/** - * External dependencies - */ -import ResizeObserver from 'resize-observer-polyfill'; - /** * Internal dependencies */ -import { DEFAULT_GALLERY_WIDTH } from './constants'; -import { getActiveStyleName, getLayout } from './layouts'; - -/** - * Styles - */ import './view.scss'; - -const applyNodeSize = ( node, { width, height } ) => { - node.style.width = `${ width }px`; - node.style.height = `${ height }px`; -}; - -/** - * Calculate new size for the gallery and apply it - */ -const resizeGallery = ( { galleryNode, width, columns, layout } ) => { - const tileCount = galleryNode.querySelectorAll( '.tiled-gallery__item' ).length; - - const galleryLayout = getLayout( { - columns, - layout, - tileCount, - width, - } ); - - // Resize rows within the gallery - galleryNode.childNodes.forEach( ( rowNode, rowIndex ) => { - const rowLayout = galleryLayout[ rowIndex ]; - applyNodeSize( rowNode, rowLayout ); - - // Resize tiles within the row - const tileNodes = rowNode.querySelectorAll( '.tiled-gallery__item' ); - tileNodes.forEach( ( tileNode, tileIndex ) => { - const tileLayout = rowLayout.tiles[ tileIndex ]; - applyNodeSize( tileNode, tileLayout ); - } ); - } ); -}; +import ResizeObserver from 'resize-observer-polyfill'; +import { handleRowResize } from './layout/mosaic/resize'; /** - * Compares gallery width to its previous width to decide if to resize it. - * @param {Array} entries Resized entries + * Handler for Gallery ResizeObserver + * + * @param {Array} galleries Resized galleries */ -function handleResize( entries ) { - if ( handleResize.pendingRaf ) { - cancelAnimationFrame( handleResize.pendingRaf ); +function handleObservedResize( galleries ) { + if ( handleObservedResize.pendingRaf ) { + cancelAnimationFrame( handleObservedResize.pendingRaf ); } - handleResize.pendingRaf = requestAnimationFrame( () => { - handleResize.pendingRaf = null; - for ( const entry of entries ) { - const { width } = entry.contentRect; - // Don't resize if width didn't chance - if ( width !== entry.target.getAttribute( 'data-width' ) ) { - // Store width for later comparison - entry.target.setAttribute( 'data-width', width ); - resizeGallery( { - columns: parseInt( entry.target.getAttribute( 'data-columns' ), 10 ), - galleryNode: entry.target, - layout: getActiveStyleName( entry.target.className ), - width, - } ); - } + handleObservedResize.pendingRaf = requestAnimationFrame( () => { + handleObservedResize.pendingRaf = null; + for ( const gallery of galleries ) { + const { width: galleryWidth } = gallery.contentRect; + const rows = Array.from( gallery.target.childNodes ); + rows.forEach( row => handleRowResize( row, galleryWidth ) ); } } ); } /** - * Get different galleries on the page + * Get all the galleries on the document * - * @returns {Array} List of gallery nodes on the page + * @return {Array} List of gallery nodes */ -const getGalleries = () => { - return document ? [ ...document.querySelectorAll( '.wp-block-jetpack-tiled-gallery' ) ] : []; -}; +function getGalleries() { + return Array.from( + document.querySelectorAll( + '.wp-block-jetpack-tiled-gallery.is-style-rectangular > .tiled-gallery__gallery' + ) + ); +} /** * Setup ResizeObserver to follow each gallery on the page @@ -94,22 +47,9 @@ const observeGalleries = () => { return; } - const observer = new ResizeObserver( handleResize ); + const observer = new ResizeObserver( handleObservedResize ); - galleries.forEach( gallery => { - // Observe only if gallery has child nodes - if ( gallery.childNodes.length > 0 ) { - // By default gallery has fixed width; element fluid fluid and move - // width to `data-` to be able to compare changes in element's - // current width to element's previous width. - gallery.setAttribute( - 'data-width', - parseInt( gallery.style.width, 10 ) || DEFAULT_GALLERY_WIDTH - ); - gallery.style.width = 'auto'; - observer.observe( gallery ); - } - } ); + galleries.forEach( gallery => observer.observe( gallery ) ); }; if ( typeof window !== 'undefined' && typeof document !== 'undefined' ) { diff --git a/client/gutenberg/extensions/tiled-gallery/view.scss b/client/gutenberg/extensions/tiled-gallery/view.scss index dacfa5095fc6b..c2797d59ae80c 100644 --- a/client/gutenberg/extensions/tiled-gallery/view.scss +++ b/client/gutenberg/extensions/tiled-gallery/view.scss @@ -1,112 +1,105 @@ @import './variables.scss'; -.wp-block-jetpack-tiled-gallery { - display: flex; - flex-wrap: wrap; - padding: 0; +$tiled-gallery-max-column-count: 20; - .tiled-gallery__row { - // flex-grow: 1; - display: flex; - flex-direction: column; - flex-wrap: wrap; - justify-content: center; - margin: 0 auto; - - & + & { - margin-top: $tiled-gallery-gutter; - } +.wp-block-jetpack-tiled-gallery { + margin: 0 auto; - .tiled-gallery__item { - justify-content: center; - position: relative; + &.is-style-circle .tiled-gallery__item img { + border-radius: 50%; + } - & + & { - margin-left: $tiled-gallery-gutter; - } - } + [data-align='left'] &, + [data-align='right'] &, + &.alignleft, + &.alignright { + max-width: ( $tiled-gallery-content-width / 2 ); + width: 100%; + } - figure { - margin: 0; - height: 100%; + &.is-style-square, + &.is-style-circle { + .tiled-gallery__row { + flex-grow: 1; + width: 100%; - // IE doesn't support flex so omit that. - @supports ( position: sticky ) { - display: flex; - align-items: flex-end; - justify-content: flex-start; + @for $cols from 1 through $tiled-gallery-max-column-count { + &.columns-#{$cols} { + .tiled-gallery__col { + width: calc( ( 100% - ( #{$tiled-gallery-gutter} * ( #{$cols} - 1 ) ) ) / #{$cols} ); + } + } } } + } +} - img { - display: block; - max-width: 100%; - height: auto; - } +.tiled-gallery__gallery { + width: 100%; + display: flex; + padding: 0; + flex-wrap: wrap; +} - // IE doesn't handle cropping, so we need an explicit width here. - img { - width: 100%; +.tiled-gallery__row { + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + margin: 0; - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports ( position: sticky ) { - width: auto; - } - } + & + & { + margin-top: $tiled-gallery-gutter; + } +} - figcaption { - position: absolute; - bottom: 0; - width: 100%; - max-height: 100%; - overflow: auto; - padding: 40px 10px 5px; - color: $white; - text-align: center; - font-size: $root-font-size; - // @TODO: conflicting linting rules - // stylelint-disable function-parentheses-space-inside - background: linear-gradient( - 0deg, - rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.7 ) 0, - rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.3 ) 60%, - transparent - ); - // stylelint-enable function-parentheses-space-inside +.tiled-gallery__col { + display: flex; + flex-direction: column; + justify-content: center; + margin: 0; - img { - display: inline; - } - } + & + & { + margin-left: $tiled-gallery-gutter; } +} - &.is-style-circle .tiled-gallery__item img { - border-radius: 50%; - } +.tiled-gallery__item { + justify-content: center; + position: relative; + margin: 0; + overflow: hidden; - // Cropped - &.is-cropped .tiled-gallery__item { - a, - img { - // IE11 doesn't support object-fit, so just make sure images aren't skewed. - // The following rules are for all browsers. - width: 100%; + & + & { + margin-top: $tiled-gallery-gutter; + } - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports ( position: sticky ) { - height: 100%; - flex: 1; - object-fit: cover; - } - } + > a > img, + > img { + display: block; + height: auto; + max-width: 100%; + width: 100%; } - // Apply max-width to floated items that have no intrinsic width - [data-align='left'] &, - [data-align='right'] &, - &.alignleft, - &.alignright { - max-width: ( $tiled-gallery-content-width / 2 ); + figcaption { + position: absolute; + bottom: 0; width: 100%; + max-height: 100%; + overflow: auto; + padding: 40px 10px 5px; + color: $white; + text-align: center; + font-size: $root-font-size; + // @TODO: conflicting linting rules + // stylelint-disable function-parentheses-space-inside + background: linear-gradient( + 0deg, + rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.7 ) 0, + rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.3 ) 60%, + transparent + ); + // stylelint-enable function-parentheses-space-inside } } diff --git a/client/gutenberg/extensions/utils/block-styles.js b/client/gutenberg/extensions/utils/block-styles.js new file mode 100644 index 0000000000000..5a278356fc6d3 --- /dev/null +++ b/client/gutenberg/extensions/utils/block-styles.js @@ -0,0 +1,52 @@ +/** + * External dependencies + */ +import TokenList from '@wordpress/token-list'; +import { find } from 'lodash'; + +/** + * Returns the active style from the given className. + * + * From @link https://github.com/WordPress/gutenberg/blob/ddac4f3cf8fd311169c7e125411343a437bdbb5a/packages/editor/src/components/block-styles/index.js#L20-L42 + * + * @param {Array} styles Block style variations. + * @param {string} className Class name + * + * @return {Object?} The active style. + */ +function getActiveStyle( styles, className ) { + for ( const style of new TokenList( className ).values() ) { + if ( style.indexOf( 'is-style-' ) === -1 ) { + continue; + } + + const potentialStyleName = style.substring( 9 ); + const activeStyle = find( styles, { name: potentialStyleName } ); + if ( activeStyle ) { + return activeStyle; + } + } + + return find( styles, 'isDefault' ); +} + +export function getActiveStyleName( styles, className ) { + const style = getActiveStyle( styles, className ); + return style ? style.name : null; +} + +export function getDefaultStyleClass( styles ) { + const defaultStyle = find( styles, 'isDefault' ); + return defaultStyle ? `is-style-${ defaultStyle.name }` : null; +} + +/** + * Checks if className has a class selector starting with `is-style-` + * Does not check validity of found style. + * + * @param {String} classNames Optional. Space separated classNames. Defaults to ''. + * @return {Boolean} true if `classNames` has a Gutenberg style class + */ +export function hasStyleClass( classNames = '' ) { + return classNames.split( ' ' ).some( className => className.startsWith( 'is-style-' ) ); +} diff --git a/client/gutenberg/extensions/utils/index.js b/client/gutenberg/extensions/utils/index.js new file mode 100644 index 0000000000000..13e2e308b4974 --- /dev/null +++ b/client/gutenberg/extensions/utils/index.js @@ -0,0 +1 @@ +export { getActiveStyleName, getDefaultStyleClass, hasStyleClass } from './block-styles'; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 16a97d79566b8..b0667f1fd403c 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -58,9 +58,9 @@ }, "dependencies": { "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } @@ -853,9 +853,9 @@ }, "dependencies": { "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } @@ -6868,9 +6868,9 @@ } }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -8966,9 +8966,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.0.tgz", - "integrity": "sha512-vpydAvIJvPODZNagCPuHG87O9JNPtvFEtjHHRVwNVsVVRBqemvPJkc2SYbxJsiZXawJdtZNmkmnsPuE3IgsG0A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9125,9 +9125,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -11541,9 +11541,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { "p-try": "^2.0.0" } @@ -12062,24 +12062,34 @@ }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + } } }, "mississippi": { @@ -12120,6 +12130,11 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } }, @@ -12690,13 +12705,13 @@ "dev": true }, "nearley": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz", - "integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "dev": true, "requires": { + "commander": "^2.19.0", "moo": "^0.4.3", - "nomnom": "~1.6.2", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" @@ -12779,9 +12794,9 @@ }, "dependencies": { "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -13135,24 +13150,6 @@ } } }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "dev": true, - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - }, - "dependencies": { - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "dev": true - } - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -14064,16 +14061,16 @@ } }, "pacote": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.2.3.tgz", - "integrity": "sha512-Y3+yY3nBRAxMlZWvr62XLJxOwCmG9UmkGZkFurWHoCjqF0cZL72cTOCRJTvWw8T4OhJS2RTg13x4oYYriauvEw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.3.0.tgz", + "integrity": "sha512-uy5xghB5wUtmFS+uNhQGhlsIF9rfsfxw6Zsu2VpmSz4/f+8D2+5V1HwjHdSn7W6aQTrxNNmmoUF5qNE10/EVdA==", "requires": { - "bluebird": "^3.5.2", - "cacache": "^11.2.0", + "bluebird": "^3.5.3", + "cacache": "^11.3.2", "figgy-pudding": "^3.5.1", "get-stream": "^4.1.0", "glob": "^7.1.3", - "lru-cache": "^4.1.3", + "lru-cache": "^5.1.1", "make-fetch-happen": "^4.0.1", "minimatch": "^3.0.4", "minipass": "^2.3.5", @@ -14092,29 +14089,29 @@ "safe-buffer": "^5.1.2", "semver": "^5.6.0", "ssri": "^6.0.1", - "tar": "^4.4.6", + "tar": "^4.4.8", "unique-filename": "^1.1.1", "which": "^1.3.1" }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, @@ -14126,6 +14123,14 @@ "pump": "^3.0.0" } }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -19421,9 +19426,9 @@ } }, "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.0.tgz", + "integrity": "sha512-AQxrNqu4EXWt03dJdgKXI+Au9+pvEuM5+Nk5g6+TmuxMCkEL03VhZ31HM+VKeaaZbFpDHaoSruiHq4PW9AIrOQ==" }, "serve-static": { "version": "1.13.2", @@ -20416,9 +20421,9 @@ }, "dependencies": { "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -20700,23 +20705,23 @@ }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, @@ -20747,6 +20752,14 @@ "path-exists": "^3.0.0" } }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -20765,9 +20778,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { "p-try": "^2.0.0" } @@ -20819,6 +20832,11 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } }, @@ -21442,12 +21460,6 @@ "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", - "dev": true - }, "unescape": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/unescape/-/unescape-0.2.0.tgz", @@ -22037,9 +22049,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { "p-try": "^2.0.0" } @@ -22586,12 +22598,12 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -22607,6 +22619,14 @@ "locate-path": "^3.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -22640,19 +22660,19 @@ } }, "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "requires": { - "execa": "^0.10.0", + "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { "p-try": "^2.0.0" } @@ -22670,6 +22690,15 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "yargs-parser": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", diff --git a/package.json b/package.json index ae98d9a6dd777..e74ea78455bff 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@wordpress/a11y": "2.0.2", "@wordpress/api-fetch": "2.2.6", "@wordpress/babel-plugin-import-jsx-pragma": "1.1.2", + "@wordpress/blob": "2.1.0", "@wordpress/block-library": "2.2.10", "@wordpress/blocks": "6.0.4", "@wordpress/components": "7.0.4", diff --git a/packages/babel-plugin-i18n-calypso/package-lock.json b/packages/babel-plugin-i18n-calypso/package-lock.json index 8fc2ecaf9edaa..232579eda9b88 100644 --- a/packages/babel-plugin-i18n-calypso/package-lock.json +++ b/packages/babel-plugin-i18n-calypso/package-lock.json @@ -197,9 +197,9 @@ } }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" diff --git a/packages/i18n-calypso/package-lock.json b/packages/i18n-calypso/package-lock.json index b61f36e499686..ebfa3f052758a 100644 --- a/packages/i18n-calypso/package-lock.json +++ b/packages/i18n-calypso/package-lock.json @@ -277,12 +277,6 @@ "timers-ext": "^0.1.5" } }, - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "dev": true - }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -1270,13 +1264,13 @@ "dev": true }, "nearley": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz", - "integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "dev": true, "requires": { + "commander": "^2.19.0", "moo": "^0.4.3", - "nomnom": "~1.6.2", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" @@ -1297,16 +1291,6 @@ "is-stream": "^1.0.1" } }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "dev": true, - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - } - }, "npm-path": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", @@ -1627,9 +1611,9 @@ } }, "readable-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.0.tgz", - "integrity": "sha512-vpydAvIJvPODZNagCPuHG87O9JNPtvFEtjHHRVwNVsVVRBqemvPJkc2SYbxJsiZXawJdtZNmkmnsPuE3IgsG0A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -1921,12 +1905,6 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", - "dev": true - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",