diff --git a/src/helpers.js b/src/helpers.js index 0954929..e745c7b 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -2,6 +2,7 @@ import isArray from 'lodash/isArray'; import isObject from 'lodash/isObject'; import isString from 'lodash/isString'; import { isInternalURL, flattenToAppURL } from '@plone/volto/helpers'; +import config from '@plone/volto/registry'; export const getFieldURL = (data) => { let url = data; @@ -17,3 +18,57 @@ export const getFieldURL = (data) => { if (isString(url) && isInternalURL(url)) return flattenToAppURL(url); return url; }; + +export function getImageScaleParams(image, size) { + const imageScale = + config.blocks.blocksConfig?.['teaser']?.imageScale || size || 'preview'; + + if (isString(image)) + return isInternalURL(image) + ? { download: flattenToAppURL(`${image}/@@images/image/${imageScale}`) } + : { download: image }; + + if (image) { + if (isInternalURL(getFieldURL(image))) { + if (image?.image_scales?.[image?.image_field]) { + const scale = + image.image_scales[image.image_field]?.[0].scales?.[imageScale] || + image.image_scales[image.image_field]?.[0]; + + const download = flattenToAppURL( + `${getFieldURL(image)}/${scale?.download}`, + ); + const width = scale?.width; + const height = scale?.height; + + return { + download, + width, + height, + }; + } else if (image?.image?.scales) { + const scale = image.image?.scales?.[imageScale] || image.image; + const download = flattenToAppURL(scale?.download); + const width = scale?.width; + const height = scale?.height; + + return { + download, + width, + height, + }; + } else { + //fallback if we do not have scales + return { + download: flattenToAppURL( + `${getFieldURL(image)}/@@images/${ + image.image_field || 'image' + }/${imageScale}`, + ), + }; + } + } else { + return { download: getFieldURL(image) }; + } + } +} diff --git a/src/helpers.test.js b/src/helpers.test.js index 35e19a7..f46ff26 100644 --- a/src/helpers.test.js +++ b/src/helpers.test.js @@ -1,5 +1,148 @@ -import { getFieldURL } from './helpers'; +import { getFieldURL, getImageScaleParams } from './helpers'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers'; +jest.mock('@plone/volto/helpers', () => ({ + flattenToAppURL: jest.fn((url) => url), + isInternalURL: jest.fn((url) => true), +})); + +describe('getImageScaleParams', () => { + it('returns expected image scale URL obj when image_field and image_scales properties are passed', () => { + const image = { + '@id': 'http://localhost:3000/image', + image_field: 'image', + image_scales: { + image: [ + { + download: '@@images/image.png', + width: 400, + height: 400, + scales: { + preview: { + download: '@@images/image-400.png', + width: 400, + height: 400, + }, + }, + }, + ], + }, + }; + + const expectedUrlObj = { + download: 'http://localhost:3000/image/@@images/image-400.png', + width: 400, + height: 400, + }; + expect(getImageScaleParams(image, 'preview')).toEqual(expectedUrlObj); + }); + + it('returns expected image scale URL obj when image_field and image_scales properties are passed but with no scales', () => { + const image = { + '@id': 'http://localhost:3000/image', + image_field: 'image', + image_scales: { + image: [ + { + download: '@@images/image.png', + width: 400, + height: 400, + }, + ], + }, + }; + + const expectedUrlObj = { + download: 'http://localhost:3000/image/@@images/image.png', + width: 400, + height: 400, + }; + expect(getImageScaleParams(image, 'preview')).toEqual(expectedUrlObj); + }); + + it('returns expected image scale URL obj when image properties are passed', () => { + const image = { + '@id': 'http://localhost:3000/image', + image: { + download: 'http://localhost:3000/image/@@images/image.png', + width: 400, + height: 400, + scales: { + preview: { + download: 'http://localhost:3000/image/@@images/image-400.png', + width: 400, + height: 400, + }, + }, + }, + }; + const expectedUrlObj = { + download: 'http://localhost:3000/image/@@images/image-400.png', + width: 400, + height: 400, + }; + expect(getImageScaleParams(image, 'preview')).toEqual(expectedUrlObj); + }); + + it('calls flattenToAppURL when internalUrl', () => { + const url = 'http://localhost:3000/image'; + const size = 'large'; + getImageScaleParams(url, size); + expect(flattenToAppURL).toHaveBeenCalledWith('http://localhost:3000/image'); + }); + + it('returns expected image scale URL string when image url (string) is passed', () => { + const image = 'http://localhost:3000/image/@@images/image.png'; + expect(getImageScaleParams(image, 'preview')).toEqual({ + download: `${image}/@@images/image/preview`, + }); + }); + + it('returns image URL string when external image url (string) is passed', () => { + isInternalURL.mockReturnValue(false); + const image = 'http://external-url.com'; + expect(getImageScaleParams(image)).toEqual({ + download: image, + }); + }); + + it('returns image URL string when image url (object) with no scales is passed', () => { + isInternalURL.mockReturnValue(true); + const image = { + '@id': 'http://localhost:3000/image', + image: { + download: 'http://localhost:3000/image/@@images/image.png', + width: 400, + height: 400, + }, + }; + expect(getImageScaleParams(image)).toEqual({ + download: `${image['@id']}/@@images/image/preview`, + }); + }); + + it('returns image URL string when external image url (object) is passed', () => { + isInternalURL.mockReturnValue(false); + const image = { + '@id': 'http://external-url.com', + image: { + download: 'http://external-url.com', + width: 400, + height: 400, + scales: { + preview: { + download: 'hhttp://external-url.com', + width: 400, + height: 400, + }, + }, + }, + }; + expect(getImageScaleParams(image)).toEqual({ + download: image['@id'], + }); + }); +}); describe('getFieldURL', () => { it('handles a URL type object with type and value', () => { const data = { diff --git a/src/hocs/withCachedImages.jsx b/src/hocs/withCachedImages.jsx index 99ff94b..b388104 100644 --- a/src/hocs/withCachedImages.jsx +++ b/src/hocs/withCachedImages.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { isEmpty } from 'lodash'; +import { getImageScaleParams } from '@eeacms/volto-block-style/helpers'; export default function withCachedImages(WrappedComponent, config = {}) { return (props) => { @@ -13,7 +14,7 @@ export default function withCachedImages(WrappedComponent, config = {}) { if (!mounted.current) mounted.current = true; if (image && !images[image]) { const newImage = new Image(); - newImage.src = `${image}/@@images/image`; + newImage.src = getImageScaleParams(image)?.download; setImages({ ...images, [image]: null }); newImage.onload = () => { if (mounted.current) {