From eea516dee37019df84a097843892e75162bf1f47 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Mon, 17 Jul 2023 14:55:00 +0200 Subject: [PATCH 1/3] Add new helper `findBlocks` --- src/config/index.js | 1 + src/helpers/Blocks/Blocks.js | 22 ++++++++++++ src/helpers/Blocks/Blocks.test.js | 60 ++++++++++++++++++++++++++++++- src/helpers/index.js | 1 + test-setup-config.js | 1 + 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/config/index.js b/src/config/index.js index ae852f5236..74b5c24172 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -184,6 +184,7 @@ let config = { querystringSearchGet: false, blockSettingsTabFieldsetsInitialStateOpen: true, excludeLinksAndReferencesMenuItem: false, + containerBlockTypes: ['gridBlock'], }, experimental: { addBlockButton: { diff --git a/src/helpers/Blocks/Blocks.js b/src/helpers/Blocks/Blocks.js index 3d7e45c9ff..c208050528 100644 --- a/src/helpers/Blocks/Blocks.js +++ b/src/helpers/Blocks/Blocks.js @@ -550,3 +550,25 @@ export const getPreviousNextBlock = ({ content, block }) => { return [previousBlock, nextBlock]; }; + +/** + * Given a `block` object and a list of block types, return a list of block ids matching the types + * + * @function findBlocks + * @param {Object} types A list with the list of types to be matched + * @return {Array} An array of block ids + */ +export function findBlocks(blocks, types, result = []) { + const containerBlockTypes = config.settings.containerBlockTypes; + + Object.keys(blocks).forEach((blockId) => { + const block = blocks[blockId]; + if (types.includes(block['@type'])) { + result.push(blockId); + } else if (containerBlockTypes.includes(block['@type']) || block.blocks) { + findBlocks(block.blocks, types, result); + } + }); + + return result; +} diff --git a/src/helpers/Blocks/Blocks.test.js b/src/helpers/Blocks/Blocks.test.js index 8984bb85ea..951aa6e496 100644 --- a/src/helpers/Blocks/Blocks.test.js +++ b/src/helpers/Blocks/Blocks.test.js @@ -20,6 +20,7 @@ import { buildStyleClassNamesExtenders, getPreviousNextBlock, blocksFormGenerator, + findBlocks, } from './Blocks'; import config from '@plone/volto/registry'; @@ -1284,7 +1285,7 @@ describe('Blocks', () => { blocks_layout: { items: [] }, }); }); - it.only('Returns a filled blocks/blocks_layout pair with type block', () => { + it('Returns a filled blocks/blocks_layout pair with type block', () => { const result = blocksFormGenerator(2, 'teaser'); expect(Object.keys(result.blocks).length).toEqual(2); expect(result.blocks_layout.items.length).toEqual(2); @@ -1297,3 +1298,60 @@ describe('Blocks', () => { }); }); }); + +describe('findBlocks', () => { + it('Get all blocks in the first level (main block container)', () => { + const blocks = { + '1': { title: 'title', '@type': 'title' }, + '2': { title: 'an image', '@type': 'image' }, + '3': { title: 'description', '@type': 'description' }, + '4': { title: 'a text', '@type': 'slate' }, + }; + const types = ['description']; + expect(findBlocks(blocks, types)).toStrictEqual(['3']); + }); + + it('Get all blocks in the first level (main block container) given a list', () => { + const blocks = { + '1': { title: 'title', '@type': 'title' }, + '2': { title: 'an image', '@type': 'image' }, + '3': { title: 'description', '@type': 'description' }, + '4': { title: 'a text', '@type': 'slate' }, + }; + const types = ['description', 'slate']; + expect(findBlocks(blocks, types)).toStrictEqual(['3', '4']); + }); + + it('Get all blocks in the first level (main block container) given a list', () => { + const blocks = { + '1': { title: 'title', '@type': 'title' }, + '2': { title: 'an image', '@type': 'image' }, + '3': { title: 'description', '@type': 'description' }, + '4': { title: 'a text', '@type': 'slate' }, + '5': { title: 'a text', '@type': 'slate' }, + }; + const types = ['description', 'slate']; + expect(findBlocks(blocks, types)).toStrictEqual(['3', '4', '5']); + }); + + it('Get all blocks, including containers, given a list', () => { + const blocks = { + '1': { title: 'title', '@type': 'title' }, + '2': { title: 'an image', '@type': 'image' }, + '3': { title: 'description', '@type': 'description' }, + '4': { title: 'a text', '@type': 'slate' }, + '5': { + title: 'a container', + '@type': 'gridBlock', + blocks: { + '6': { title: 'title', '@type': 'title' }, + '7': { title: 'an image', '@type': 'image' }, + '8': { title: 'description', '@type': 'description' }, + '9': { title: 'a text', '@type': 'slate' }, + }, + }, + }; + const types = ['description', 'slate']; + expect(findBlocks(blocks, types)).toStrictEqual(['3', '4', '8', '9']); + }); +}); diff --git a/src/helpers/index.js b/src/helpers/index.js index 633c3da5c1..c4985f5361 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -58,6 +58,7 @@ export { buildStyleClassNamesFromData, buildStyleClassNamesExtenders, getPreviousNextBlock, + findBlocks, } from '@plone/volto/helpers/Blocks/Blocks'; export { default as BodyClass } from '@plone/volto/helpers/BodyClass/BodyClass'; export { default as ScrollToTop } from '@plone/volto/helpers/ScrollToTop/ScrollToTop'; diff --git a/test-setup-config.js b/test-setup-config.js index 0e41216f7e..1bb744c063 100644 --- a/test-setup-config.js +++ b/test-setup-config.js @@ -83,6 +83,7 @@ config.set('settings', { styleClassNameConverters, styleClassNameExtenders, blockSettingsTabFieldsetsInitialStateOpen: true, + containerBlockTypes: [], }); config.set('blocks', { blocksConfig: { From 4c498b002628b63c3487b265f01264aff9dd9f47 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Mon, 17 Jul 2023 15:03:29 +0200 Subject: [PATCH 2/3] Fix the condition for pagination format taking into account container blocks as well --- src/helpers/Utils/usePagination.js | 9 ++------- src/helpers/index.js | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/helpers/Utils/usePagination.js b/src/helpers/Utils/usePagination.js index 083ec48682..674b072bde 100644 --- a/src/helpers/Utils/usePagination.js +++ b/src/helpers/Utils/usePagination.js @@ -2,7 +2,7 @@ import React, { useRef, useEffect } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import qs from 'query-string'; import { useSelector } from 'react-redux'; -import { slugify } from '@plone/volto/helpers/Utils/Utils'; +import { findBlocks, slugify } from '@plone/volto/helpers'; /** * @function useCreatePageQueryStringKey @@ -12,13 +12,8 @@ import { slugify } from '@plone/volto/helpers/Utils/Utils'; const useCreatePageQueryStringKey = (id) => { const blockTypesWithPagination = ['search', 'listing']; const blocks = useSelector((state) => state?.content?.data?.blocks) || []; - const blocksLayout = - useSelector((state) => state?.content?.data?.blocks_layout?.items) || []; - const displayedBlocks = blocksLayout?.map((item) => blocks[item]); const hasMultiplePaginations = - displayedBlocks.filter((item) => - blockTypesWithPagination.includes(item['@type']), - ).length > 1 || false; + findBlocks(blocks, blockTypesWithPagination).length > 1; return hasMultiplePaginations ? slugify(`page-${id}`) : 'page'; }; diff --git a/src/helpers/index.js b/src/helpers/index.js index c4985f5361..41a989c8d4 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -94,6 +94,7 @@ export { arrayRange, reorderArray, isInteractiveElement, + slugify, } from '@plone/volto/helpers/Utils/Utils'; export { messages } from './MessageLabels/MessageLabels'; export { From 22e56a5abd5c5f605d4ea119d174384e99ade1eb Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Mon, 17 Jul 2023 15:05:24 +0200 Subject: [PATCH 3/3] Changelog --- news/4978.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/4978.bugfix diff --git a/news/4978.bugfix b/news/4978.bugfix new file mode 100644 index 0000000000..5e4e82448f --- /dev/null +++ b/news/4978.bugfix @@ -0,0 +1 @@ +Fix the condition deciding on listing pagination format so it takes into account container blocks as well @sneridagh