@plone/volto 17.0.0-alpha.2 → 17.0.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +530 -15
- package/CONTRIBUTING.md +1 -1
- package/README.md +11 -14
- package/addon-registry.js +34 -0
- package/create-theme-addons-loader.js +79 -0
- package/cypress/support/commands.js +56 -4
- package/cypress/support/volto-slate.js +4 -5
- package/docker-compose.yml +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +272 -6
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +291 -25
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +271 -5
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +281 -15
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +272 -6
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +4882 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +272 -6
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +273 -7
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +272 -6
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +927 -649
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +272 -6
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +281 -15
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +272 -6
- package/locales/ro.json +1 -1
- package/locales/volto.pot +272 -6
- package/locales/zh_CN/LC_MESSAGES/volto.po +272 -6
- package/locales/zh_CN.json +1 -1
- package/package.json +5 -3
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/actions/index.js +1 -1
- package/packages/volto-slate/src/blocks/Table/TableBlockEdit.jsx +21 -212
- package/packages/volto-slate/src/blocks/Table/schema.js +122 -0
- package/packages/volto-slate/src/blocks/Text/DefaultTextBlockEditor.jsx +8 -3
- package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
- package/packages/volto-slate/src/blocks/Text/TextBlockView.jsx +20 -16
- package/packages/volto-slate/src/blocks/Text/extensions/withDeserializers.js +3 -1
- package/packages/volto-slate/src/blocks/Text/index.js +10 -2
- package/packages/volto-slate/src/editor/config.jsx +5 -4
- package/packages/volto-slate/src/editor/deserialize.js +0 -1
- package/packages/volto-slate/src/editor/index.js +4 -4
- package/packages/volto-slate/src/editor/less/slate.less +28 -0
- package/packages/volto-slate/src/editor/plugins/StyleMenu/StyleMenu.jsx +14 -4
- package/packages/volto-slate/src/editor/plugins/StyleMenu/utils.js +14 -5
- package/packages/volto-slate/src/editor/render.jsx +68 -8
- package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
- package/packages/volto-slate/src/editor/ui/index.js +15 -15
- package/packages/volto-slate/src/index.js +2 -2
- package/packages/volto-slate/src/utils/blocks.js +7 -0
- package/packages/volto-slate/src/widgets/RichTextWidget.jsx +15 -8
- package/razzle.config.js +28 -0
- package/src/actions/index.js +6 -0
- package/src/actions/language/language.js +9 -8
- package/src/actions/querystringsearch/querystringsearch.js +20 -14
- package/src/actions/relations/rebuild.js +25 -0
- package/src/actions/relations/relations.js +86 -0
- package/src/actions/relations/relations.test.js +15 -0
- package/src/components/index.js +2 -0
- package/src/components/manage/Add/Add.jsx +2 -2
- package/src/components/manage/AnchorPlugin/index.jsx +2 -2
- package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
- package/src/components/manage/BlockChooser/BlockChooser.jsx +14 -5
- package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
- package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
- package/src/components/manage/Blocks/Block/Style.jsx +2 -2
- package/src/components/manage/Blocks/Container/Data.jsx +32 -0
- package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
- package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
- package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
- package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
- package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
- package/src/components/manage/Blocks/Grid/View.jsx +43 -0
- package/src/components/manage/Blocks/Grid/adapter.js +14 -0
- package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
- package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
- package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
- package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
- package/src/components/manage/Blocks/Grid/schema.js +35 -0
- package/src/components/manage/Blocks/Grid/templates.js +47 -0
- package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +6 -1
- package/src/components/manage/Blocks/Image/Edit.jsx +11 -7
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +2 -1
- package/src/components/manage/Blocks/Image/schema.js +11 -0
- package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
- package/src/components/manage/Blocks/Listing/ListingBody.jsx +30 -8
- package/src/components/manage/Blocks/Listing/ListingBody.test.jsx +20 -0
- package/src/components/manage/Blocks/Listing/getAsyncData.js +9 -3
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +26 -18
- package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +5 -4
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
- package/src/components/manage/Blocks/Search/components/Facets.jsx +64 -4
- package/src/components/manage/Blocks/Search/components/SearchInput.jsx +9 -2
- package/src/components/manage/Blocks/Search/components/index.js +13 -13
- package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
- package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +43 -15
- package/src/components/manage/Blocks/Search/layout/LeftColumnFacets.jsx +17 -5
- package/src/components/manage/Blocks/Search/layout/RightColumnFacets.jsx +17 -5
- package/src/components/manage/Blocks/Search/layout/TopSideFacets.jsx +21 -5
- package/src/components/manage/Blocks/Search/schema.js +16 -1
- package/src/components/manage/Blocks/Teaser/Body.jsx +0 -1
- package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +20 -15
- package/src/components/manage/Blocks/Teaser/schema.js +5 -0
- package/src/components/manage/Blocks/Title/View.jsx +15 -5
- package/src/components/manage/Blocks/Title/View.test.jsx +16 -1
- package/src/components/manage/Blocks/ToC/Schema.jsx +5 -1
- package/src/components/manage/Blocks/ToC/View.jsx +8 -1
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +17 -4
- package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +148 -10
- package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
- package/src/components/manage/Contents/Contents.jsx +39 -26
- package/src/components/manage/Contents/ContentsItem.jsx +6 -0
- package/src/components/manage/Contents/ContentsUploadModal.jsx +10 -5
- package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Controlpanels.jsx +199 -224
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
- package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
- package/src/components/manage/Form/Form.jsx +5 -3
- package/src/components/manage/Form/InlineForm.jsx +39 -9
- package/src/components/manage/Form/InlineFormState.js +8 -0
- package/src/components/manage/History/History.jsx +11 -1
- package/src/components/manage/LinksToItem/LinksToItem.jsx +209 -0
- package/src/components/manage/LinksToItem/LinksToItem.test.jsx +97 -0
- package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
- package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
- package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
- package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
- package/src/components/manage/Sharing/Sharing.jsx +5 -1
- package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
- package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
- package/src/components/manage/TemplateChooser/template.svg +10 -0
- package/src/components/manage/Toast/Toast.jsx +2 -2
- package/src/components/manage/Toolbar/More.jsx +15 -0
- package/src/components/manage/Toolbar/Types.jsx +2 -2
- package/src/components/manage/UniversalLink/UniversalLink.jsx +2 -6
- package/src/components/manage/UniversalLink/UniversalLink.test.jsx +36 -0
- package/src/components/manage/Widgets/ColorPickerWidget.jsx +6 -1
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
- package/src/components/manage/Widgets/FileWidget.jsx +2 -1
- package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
- package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +8 -3
- package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Widgets/SelectWidget.jsx +1 -1
- package/src/components/theme/Anontools/Anontools.jsx +44 -72
- package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
- package/src/components/theme/Anontools/Anontools.test.jsx +16 -2
- package/src/components/theme/Breadcrumbs/Breadcrumbs.jsx +52 -99
- package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.jsx +14 -13
- package/src/components/theme/Comments/CommentEditModal.jsx +63 -115
- package/src/components/theme/Component/Component.jsx +1 -1
- package/src/components/theme/ContactForm/ContactForm.jsx +108 -192
- package/src/components/theme/ContactForm/ContactForm.stories.jsx +1 -1
- package/src/components/theme/ContactForm/ContactForm.test.jsx +2 -3
- package/src/components/theme/Footer/Footer.jsx +2 -13
- package/src/components/theme/Header/Header.jsx +37 -63
- package/src/components/theme/Header/Header.test.jsx +18 -0
- package/src/components/theme/Icon/Icon.jsx +2 -2
- package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
- package/src/components/theme/Login/Login.jsx +1 -0
- package/src/components/theme/Logo/Logo.jsx +2 -1
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
- package/src/components/theme/Navigation/NavItem.jsx +4 -2
- package/src/components/theme/NotFound/NotFound.jsx +55 -41
- package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -4
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +1 -1
- package/src/components/theme/SearchWidget/SearchWidget.jsx +38 -98
- package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
- package/src/components/theme/View/AlbumView.jsx +9 -1
- package/src/components/theme/View/DefaultView.jsx +1 -1
- package/src/components/theme/View/EventDatesInfo.jsx +2 -1
- package/src/components/theme/View/EventView.jsx +6 -2
- package/src/components/theme/View/FileView.jsx +23 -18
- package/src/components/theme/View/ImageView.jsx +37 -32
- package/src/components/theme/View/LinkView.jsx +53 -78
- package/src/components/theme/View/ListingView.jsx +33 -27
- package/src/components/theme/View/NewsItemView.jsx +10 -5
- package/src/components/theme/View/RenderBlocks.jsx +56 -21
- package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
- package/src/components/theme/View/SummaryView.jsx +47 -38
- package/src/components/theme/View/TabularView.jsx +59 -53
- package/src/components/theme/Widgets/DateWidget.jsx +2 -1
- package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
- package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
- package/src/config/Blocks.jsx +44 -0
- package/src/config/ControlPanels.js +2 -0
- package/src/config/NonContentRoutes.jsx +1 -0
- package/src/config/RichTextEditor/Blocks.jsx +2 -2
- package/src/config/RichTextEditor/FromHTML.jsx +2 -2
- package/src/config/RichTextEditor/Styles.jsx +1 -1
- package/src/config/Widgets.jsx +2 -0
- package/src/config/index.js +24 -0
- package/src/config/server.js +2 -0
- package/src/constants/ActionTypes.js +4 -0
- package/src/constants/Indexes.js +3 -1
- package/src/constants/Languages.js +8 -4
- package/src/express-middleware/devproxy.js +1 -1
- package/src/express-middleware/files.js +3 -3
- package/src/express-middleware/images.js +4 -4
- package/src/express-middleware/ok.js +16 -0
- package/src/express-middleware/robotstxt.js +1 -1
- package/src/express-middleware/sitemap.js +37 -5
- package/src/express-middleware/static.js +3 -3
- package/src/helpers/Api/Api.js +1 -1
- package/src/helpers/Blocks/Blocks.js +48 -0
- package/src/helpers/Blocks/Blocks.test.js +79 -0
- package/src/helpers/Extensions/index.js +2 -1
- package/src/helpers/Extensions/withBlockSchemaEnhancer.js +15 -11
- package/src/helpers/Extensions/withBlockSchemaEnhancer.test.js +145 -0
- package/src/helpers/FormValidation/FormValidation.js +40 -2
- package/src/helpers/FormValidation/FormValidation.test.js +73 -0
- package/src/helpers/Html/Html.jsx +3 -1
- package/src/helpers/Html/Html.test.jsx +5 -0
- package/src/helpers/MessageLabels/MessageLabels.js +80 -0
- package/src/helpers/Robots/Robots.js +24 -6
- package/src/helpers/ScrollToTop/ScrollToTop.jsx +5 -3
- package/src/helpers/Sitemap/Sitemap.js +44 -2
- package/src/helpers/Url/Url.js +27 -6
- package/src/helpers/Url/Url.test.js +26 -0
- package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
- package/src/helpers/Utils/Utils.js +63 -13
- package/src/helpers/Utils/Utils.test.js +4 -4
- package/src/helpers/Utils/usePagination.js +67 -14
- package/src/helpers/Utils/usePagination.test.js +115 -0
- package/src/helpers/index.js +20 -10
- package/src/hooks/client/useClient.js +11 -0
- package/src/hooks/clipboard/useClipboard.js +26 -0
- package/src/hooks/index.js +2 -0
- package/src/icons/grid-block.svg +11 -0
- package/src/middleware/Api.test.js +54 -0
- package/src/middleware/api.js +24 -6
- package/src/middleware/index.js +2 -2
- package/src/reducers/actions/actions.js +8 -6
- package/src/reducers/actions/actions.test.js +70 -0
- package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
- package/src/reducers/index.js +2 -0
- package/src/reducers/navigation/navigation.js +1 -1
- package/src/reducers/relations/relations.js +173 -0
- package/src/reducers/types/types.js +1 -1
- package/src/routes.js +14 -0
- package/src/server.jsx +28 -23
- package/src/start-server.js +2 -2
- package/test-setup-config.js +2 -0
- package/theme/themes/pastanaga/extras/blocks.less +3 -1
- package/theme/themes/pastanaga/extras/contents.less +1 -0
- package/theme/themes/pastanaga/extras/grid.less +426 -0
- package/theme/themes/pastanaga/extras/main.less +3 -1
- package/theme/themes/pastanaga/extras/search.less +6 -0
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/theme/themes/pastanaga/extras/toc.less +29 -0
- package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
- package/.changelog.draft +0 -31
- package/.editorconfig +0 -36
- package/.storybook/main.js +0 -127
- package/.storybook/manager.js +0 -15
- package/.storybook/preview.js +0 -21
- package/.storybook/static/previewImage.svg +0 -48
- package/.yarnrc.yml +0 -5
- package/jsdoc.json +0 -16
- package/netlify.toml +0 -5
- package/pyvenv.cfg +0 -3
- package/share/man/man1/ttx.1 +0 -225
- package/src/components/theme/Header/Header.md +0 -27
- package/towncrier.toml +0 -33
|
@@ -343,6 +343,32 @@ export function emptyBlocksForm() {
|
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Generate empty blocks blocks/blocks_layout pair given the type
|
|
348
|
+
* (could be empty, if not type given) and the number of blocks
|
|
349
|
+
* @function blocksFormGenerator
|
|
350
|
+
* @param {number} number How many blocks to generate of the type (could be "empty", if no type provided)
|
|
351
|
+
* @param {number} type The type of the blocks
|
|
352
|
+
* @return {Object} blocks/blocks_layout pair filled with the generated blocks
|
|
353
|
+
*/
|
|
354
|
+
export function blocksFormGenerator(number, type) {
|
|
355
|
+
const idMap = [...Array(number).keys()].map(() => uuid());
|
|
356
|
+
const start = {
|
|
357
|
+
blocks: {},
|
|
358
|
+
blocks_layout: { items: idMap },
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
...start,
|
|
363
|
+
blocks: Object.fromEntries(
|
|
364
|
+
start.blocks_layout.items.map((item) => [
|
|
365
|
+
item,
|
|
366
|
+
{ '@type': type || 'empty' },
|
|
367
|
+
]),
|
|
368
|
+
),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
346
372
|
/**
|
|
347
373
|
* Recursively discover blocks in data and call the provided callback
|
|
348
374
|
* @function visitBlocks
|
|
@@ -524,3 +550,25 @@ export const getPreviousNextBlock = ({ content, block }) => {
|
|
|
524
550
|
|
|
525
551
|
return [previousBlock, nextBlock];
|
|
526
552
|
};
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Given a `block` object and a list of block types, return a list of block ids matching the types
|
|
556
|
+
*
|
|
557
|
+
* @function findBlocks
|
|
558
|
+
* @param {Object} types A list with the list of types to be matched
|
|
559
|
+
* @return {Array} An array of block ids
|
|
560
|
+
*/
|
|
561
|
+
export function findBlocks(blocks, types, result = []) {
|
|
562
|
+
const containerBlockTypes = config.settings.containerBlockTypes;
|
|
563
|
+
|
|
564
|
+
Object.keys(blocks).forEach((blockId) => {
|
|
565
|
+
const block = blocks[blockId];
|
|
566
|
+
if (types.includes(block['@type'])) {
|
|
567
|
+
result.push(blockId);
|
|
568
|
+
} else if (containerBlockTypes.includes(block['@type']) || block.blocks) {
|
|
569
|
+
findBlocks(block.blocks, types, result);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
buildStyleClassNamesFromData,
|
|
20
20
|
buildStyleClassNamesExtenders,
|
|
21
21
|
getPreviousNextBlock,
|
|
22
|
+
blocksFormGenerator,
|
|
23
|
+
findBlocks,
|
|
22
24
|
} from './Blocks';
|
|
23
25
|
|
|
24
26
|
import config from '@plone/volto/registry';
|
|
@@ -1275,4 +1277,81 @@ describe('Blocks', () => {
|
|
|
1275
1277
|
]);
|
|
1276
1278
|
});
|
|
1277
1279
|
});
|
|
1280
|
+
|
|
1281
|
+
describe('blocksFormGenerator', () => {
|
|
1282
|
+
it('Returns an empty blocks/blocks_layout pair', () => {
|
|
1283
|
+
expect(blocksFormGenerator(0, '')).toEqual({
|
|
1284
|
+
blocks: {},
|
|
1285
|
+
blocks_layout: { items: [] },
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1288
|
+
it('Returns a filled blocks/blocks_layout pair with type block', () => {
|
|
1289
|
+
const result = blocksFormGenerator(2, 'teaser');
|
|
1290
|
+
expect(Object.keys(result.blocks).length).toEqual(2);
|
|
1291
|
+
expect(result.blocks_layout.items.length).toEqual(2);
|
|
1292
|
+
expect(result.blocks[result.blocks_layout.items[0]]['@type']).toEqual(
|
|
1293
|
+
'teaser',
|
|
1294
|
+
);
|
|
1295
|
+
expect(result.blocks[result.blocks_layout.items[1]]['@type']).toEqual(
|
|
1296
|
+
'teaser',
|
|
1297
|
+
);
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
describe('findBlocks', () => {
|
|
1303
|
+
it('Get all blocks in the first level (main block container)', () => {
|
|
1304
|
+
const blocks = {
|
|
1305
|
+
'1': { title: 'title', '@type': 'title' },
|
|
1306
|
+
'2': { title: 'an image', '@type': 'image' },
|
|
1307
|
+
'3': { title: 'description', '@type': 'description' },
|
|
1308
|
+
'4': { title: 'a text', '@type': 'slate' },
|
|
1309
|
+
};
|
|
1310
|
+
const types = ['description'];
|
|
1311
|
+
expect(findBlocks(blocks, types)).toStrictEqual(['3']);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
it('Get all blocks in the first level (main block container) given a list', () => {
|
|
1315
|
+
const blocks = {
|
|
1316
|
+
'1': { title: 'title', '@type': 'title' },
|
|
1317
|
+
'2': { title: 'an image', '@type': 'image' },
|
|
1318
|
+
'3': { title: 'description', '@type': 'description' },
|
|
1319
|
+
'4': { title: 'a text', '@type': 'slate' },
|
|
1320
|
+
};
|
|
1321
|
+
const types = ['description', 'slate'];
|
|
1322
|
+
expect(findBlocks(blocks, types)).toStrictEqual(['3', '4']);
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
it('Get all blocks in the first level (main block container) given a list', () => {
|
|
1326
|
+
const blocks = {
|
|
1327
|
+
'1': { title: 'title', '@type': 'title' },
|
|
1328
|
+
'2': { title: 'an image', '@type': 'image' },
|
|
1329
|
+
'3': { title: 'description', '@type': 'description' },
|
|
1330
|
+
'4': { title: 'a text', '@type': 'slate' },
|
|
1331
|
+
'5': { title: 'a text', '@type': 'slate' },
|
|
1332
|
+
};
|
|
1333
|
+
const types = ['description', 'slate'];
|
|
1334
|
+
expect(findBlocks(blocks, types)).toStrictEqual(['3', '4', '5']);
|
|
1335
|
+
});
|
|
1336
|
+
|
|
1337
|
+
it('Get all blocks, including containers, given a list', () => {
|
|
1338
|
+
const blocks = {
|
|
1339
|
+
'1': { title: 'title', '@type': 'title' },
|
|
1340
|
+
'2': { title: 'an image', '@type': 'image' },
|
|
1341
|
+
'3': { title: 'description', '@type': 'description' },
|
|
1342
|
+
'4': { title: 'a text', '@type': 'slate' },
|
|
1343
|
+
'5': {
|
|
1344
|
+
title: 'a container',
|
|
1345
|
+
'@type': 'gridBlock',
|
|
1346
|
+
blocks: {
|
|
1347
|
+
'6': { title: 'title', '@type': 'title' },
|
|
1348
|
+
'7': { title: 'an image', '@type': 'image' },
|
|
1349
|
+
'8': { title: 'description', '@type': 'description' },
|
|
1350
|
+
'9': { title: 'a text', '@type': 'slate' },
|
|
1351
|
+
},
|
|
1352
|
+
},
|
|
1353
|
+
};
|
|
1354
|
+
const types = ['description', 'slate'];
|
|
1355
|
+
expect(findBlocks(blocks, types)).toStrictEqual(['3', '4', '8', '9']);
|
|
1356
|
+
});
|
|
1278
1357
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineMessages } from 'react-intl';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
|
+
import { find, isEmpty } from 'lodash';
|
|
4
5
|
import config from '@plone/volto/registry';
|
|
5
6
|
import { cloneDeepSchema } from '@plone/volto/helpers/Utils/Utils';
|
|
6
7
|
|
|
@@ -291,20 +292,23 @@ export const EMPTY_STYLES_SCHEMA = {
|
|
|
291
292
|
};
|
|
292
293
|
|
|
293
294
|
/**
|
|
294
|
-
*
|
|
295
|
+
* Adds the `styles` field and 'styling' fieldset in a given schema
|
|
295
296
|
*/
|
|
296
297
|
export const addStyling = ({ schema, formData, intl }) => {
|
|
297
|
-
schema.fieldsets
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
298
|
+
if (isEmpty(find(schema.fieldsets, { id: 'styling' }))) {
|
|
299
|
+
schema.fieldsets.push({
|
|
300
|
+
id: 'styling',
|
|
301
|
+
title: intl.formatMessage(messages.styling),
|
|
302
|
+
fields: ['styles'],
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
schema.properties.styles = {
|
|
306
|
+
widget: 'object',
|
|
307
|
+
title: intl.formatMessage(messages.styling),
|
|
308
|
+
schema: cloneDeepSchema(EMPTY_STYLES_SCHEMA),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
302
311
|
|
|
303
|
-
schema.properties.styles = {
|
|
304
|
-
widget: 'object',
|
|
305
|
-
title: intl.formatMessage(messages.styling),
|
|
306
|
-
schema: EMPTY_STYLES_SCHEMA,
|
|
307
|
-
};
|
|
308
312
|
return schema;
|
|
309
313
|
};
|
|
310
314
|
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
addExtensionFieldToSchema,
|
|
3
3
|
applySchemaEnhancer,
|
|
4
4
|
composeSchema,
|
|
5
|
+
addStyling,
|
|
5
6
|
} from './withBlockSchemaEnhancer';
|
|
6
7
|
|
|
7
8
|
import config from '@plone/volto/registry';
|
|
@@ -246,3 +247,147 @@ describe('composeSchema', () => {
|
|
|
246
247
|
expect(res).toStrictEqual([6, 9]);
|
|
247
248
|
});
|
|
248
249
|
});
|
|
250
|
+
|
|
251
|
+
describe('addStyling', () => {
|
|
252
|
+
it('returns an enhanced schema with the styling wrapper object on it', () => {
|
|
253
|
+
const intl = { formatMessage: () => 'Styling' };
|
|
254
|
+
|
|
255
|
+
const schema = {
|
|
256
|
+
fieldsets: [
|
|
257
|
+
{
|
|
258
|
+
id: 'default',
|
|
259
|
+
title: 'Default',
|
|
260
|
+
fields: [],
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
properties: {},
|
|
264
|
+
required: [],
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const result = addStyling({ schema, intl });
|
|
268
|
+
|
|
269
|
+
expect(result).toStrictEqual({
|
|
270
|
+
fieldsets: [
|
|
271
|
+
{ id: 'default', title: 'Default', fields: [] },
|
|
272
|
+
{ id: 'styling', title: 'Styling', fields: ['styles'] },
|
|
273
|
+
],
|
|
274
|
+
properties: {
|
|
275
|
+
styles: {
|
|
276
|
+
widget: 'object',
|
|
277
|
+
title: 'Styling',
|
|
278
|
+
schema: {
|
|
279
|
+
fieldsets: [
|
|
280
|
+
{
|
|
281
|
+
fields: [],
|
|
282
|
+
id: 'default',
|
|
283
|
+
title: 'Default',
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
properties: {},
|
|
287
|
+
required: [],
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
required: [],
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('multiple schema enhancers', () => {
|
|
296
|
+
const intl = { formatMessage: () => 'Styling' };
|
|
297
|
+
|
|
298
|
+
const schema1 = {
|
|
299
|
+
fieldsets: [
|
|
300
|
+
{
|
|
301
|
+
id: 'default',
|
|
302
|
+
title: 'Default',
|
|
303
|
+
fields: [],
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
properties: {},
|
|
307
|
+
required: [],
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const schema2 = {
|
|
311
|
+
fieldsets: [
|
|
312
|
+
{
|
|
313
|
+
id: 'default',
|
|
314
|
+
title: 'Default',
|
|
315
|
+
fields: [],
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
properties: {},
|
|
319
|
+
required: [],
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const result = addStyling({ schema: schema1, intl });
|
|
323
|
+
|
|
324
|
+
// We add some fields to the styling schema
|
|
325
|
+
result.properties.styles.schema.properties.align = {
|
|
326
|
+
widget: 'align',
|
|
327
|
+
title: 'align',
|
|
328
|
+
actions: ['left', 'right', 'center'],
|
|
329
|
+
default: 'left',
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
result.properties.styles.schema.fieldsets[0].fields = ['align'];
|
|
333
|
+
|
|
334
|
+
const result2 = addStyling({ schema: schema2, intl });
|
|
335
|
+
|
|
336
|
+
expect(result).toStrictEqual({
|
|
337
|
+
fieldsets: [
|
|
338
|
+
{ id: 'default', title: 'Default', fields: [] },
|
|
339
|
+
{ id: 'styling', title: 'Styling', fields: ['styles'] },
|
|
340
|
+
],
|
|
341
|
+
properties: {
|
|
342
|
+
styles: {
|
|
343
|
+
widget: 'object',
|
|
344
|
+
title: 'Styling',
|
|
345
|
+
schema: {
|
|
346
|
+
fieldsets: [
|
|
347
|
+
{
|
|
348
|
+
fields: ['align'],
|
|
349
|
+
id: 'default',
|
|
350
|
+
title: 'Default',
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
properties: {
|
|
354
|
+
align: {
|
|
355
|
+
widget: 'align',
|
|
356
|
+
title: 'align',
|
|
357
|
+
actions: ['left', 'right', 'center'],
|
|
358
|
+
default: 'left',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
required: [],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
required: [],
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
expect(result2).toStrictEqual({
|
|
369
|
+
fieldsets: [
|
|
370
|
+
{ id: 'default', title: 'Default', fields: [] },
|
|
371
|
+
{ id: 'styling', title: 'Styling', fields: ['styles'] },
|
|
372
|
+
],
|
|
373
|
+
properties: {
|
|
374
|
+
styles: {
|
|
375
|
+
widget: 'object',
|
|
376
|
+
title: 'Styling',
|
|
377
|
+
schema: {
|
|
378
|
+
fieldsets: [
|
|
379
|
+
{
|
|
380
|
+
fields: [],
|
|
381
|
+
id: 'default',
|
|
382
|
+
title: 'Default',
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
properties: {},
|
|
386
|
+
required: [],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
required: [],
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { map, uniq, keys, intersection, isEmpty } from 'lodash';
|
|
2
2
|
import { messages } from '../MessageLabels/MessageLabels';
|
|
3
|
+
import config from '@plone/volto/registry';
|
|
4
|
+
import { toast } from 'react-toastify';
|
|
5
|
+
import Toast from '@plone/volto/components/manage/Toast/Toast';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Will return the intl message if invalid
|
|
@@ -65,7 +68,16 @@ const widgetValidation = {
|
|
|
65
68
|
},
|
|
66
69
|
url: {
|
|
67
70
|
isValidURL: (urlValue, urlObj, intlFunc) => {
|
|
68
|
-
|
|
71
|
+
var urlRegex = new RegExp(
|
|
72
|
+
'^(https?:\\/\\/)?' + // validate protocol
|
|
73
|
+
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
|
|
74
|
+
'((\\d{1,3}\\.){3}\\d{1,3}))|' + // validate OR ip (v4) address
|
|
75
|
+
'(localhost)' + // validate OR localhost address
|
|
76
|
+
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
|
|
77
|
+
'(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
|
|
78
|
+
'(\\#[-a-z\\d_]*)?$', // validate fragment locator
|
|
79
|
+
'i',
|
|
80
|
+
);
|
|
69
81
|
const isValid = urlRegex.test(urlValue);
|
|
70
82
|
return !isValid ? intlFunc(messages.isValidURL) : null;
|
|
71
83
|
},
|
|
@@ -194,7 +206,7 @@ const validateRequiredFields = (
|
|
|
194
206
|
const type = schema.properties[requiredField]?.type;
|
|
195
207
|
const widget = schema.properties[requiredField]?.widget;
|
|
196
208
|
|
|
197
|
-
let isEmpty = !formData[requiredField];
|
|
209
|
+
let isEmpty = !formData[requiredField] && formData[requiredField] !== 0;
|
|
198
210
|
if (!isEmpty) {
|
|
199
211
|
if (type === 'array') {
|
|
200
212
|
isEmpty = formData[requiredField]
|
|
@@ -360,3 +372,29 @@ class FormValidation {
|
|
|
360
372
|
}
|
|
361
373
|
|
|
362
374
|
export default FormValidation;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Check if a file upload is within the maximum size limit.
|
|
378
|
+
* @param {File} file
|
|
379
|
+
* @param {Function} intlFunc
|
|
380
|
+
* @returns {Boolean}
|
|
381
|
+
*/
|
|
382
|
+
export const validateFileUploadSize = (file, intlFunc) => {
|
|
383
|
+
const isValid =
|
|
384
|
+
!config.settings.maxFileUploadSize ||
|
|
385
|
+
file.size <= config.settings.maxFileUploadSize;
|
|
386
|
+
if (!isValid) {
|
|
387
|
+
toast.error(
|
|
388
|
+
<Toast
|
|
389
|
+
error
|
|
390
|
+
title={intlFunc(messages.error)}
|
|
391
|
+
content={intlFunc(messages.fileTooLarge, {
|
|
392
|
+
limit: `${Math.floor(
|
|
393
|
+
config.settings.maxFileUploadSize / 1024 / 1024,
|
|
394
|
+
)}MB`,
|
|
395
|
+
})}
|
|
396
|
+
/>,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return isValid;
|
|
400
|
+
};
|
|
@@ -5,6 +5,7 @@ const schema = {
|
|
|
5
5
|
properties: {
|
|
6
6
|
username: { title: 'Username', type: 'string', description: '' },
|
|
7
7
|
email: { title: 'Email', type: 'string', widget: 'email', description: '' },
|
|
8
|
+
url: { title: 'url', type: 'string', widget: 'url', description: '' },
|
|
8
9
|
},
|
|
9
10
|
fieldsets: [
|
|
10
11
|
{ id: 'default', title: 'FIXME: User Data', fields: ['username'] },
|
|
@@ -65,6 +66,38 @@ describe('FormValidation', () => {
|
|
|
65
66
|
});
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
it('do not treat 0 as missing required value', () => {
|
|
70
|
+
let newSchema = {
|
|
71
|
+
...schema,
|
|
72
|
+
properties: {
|
|
73
|
+
...schema.properties,
|
|
74
|
+
age: {
|
|
75
|
+
title: 'age',
|
|
76
|
+
type: 'integer',
|
|
77
|
+
widget: 'number',
|
|
78
|
+
description: '',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ['age'],
|
|
82
|
+
};
|
|
83
|
+
expect(
|
|
84
|
+
FormValidation.validateFieldsPerFieldset({
|
|
85
|
+
schema: newSchema,
|
|
86
|
+
formData: { username: 'test username', age: null },
|
|
87
|
+
formatMessage,
|
|
88
|
+
}),
|
|
89
|
+
).toEqual({
|
|
90
|
+
age: [messages.required.defaultMessage],
|
|
91
|
+
});
|
|
92
|
+
expect(
|
|
93
|
+
FormValidation.validateFieldsPerFieldset({
|
|
94
|
+
schema: newSchema,
|
|
95
|
+
formData: { username: 'test username', age: 0 },
|
|
96
|
+
formatMessage,
|
|
97
|
+
}),
|
|
98
|
+
).toEqual({});
|
|
99
|
+
});
|
|
100
|
+
|
|
68
101
|
it('validates incorrect email', () => {
|
|
69
102
|
expect(
|
|
70
103
|
FormValidation.validateFieldsPerFieldset({
|
|
@@ -87,5 +120,45 @@ describe('FormValidation', () => {
|
|
|
87
120
|
}),
|
|
88
121
|
).toEqual({});
|
|
89
122
|
});
|
|
123
|
+
it('validates incorrect url', () => {
|
|
124
|
+
formData.url = 'foo';
|
|
125
|
+
expect(
|
|
126
|
+
FormValidation.validateFieldsPerFieldset({
|
|
127
|
+
schema,
|
|
128
|
+
formData,
|
|
129
|
+
formatMessage,
|
|
130
|
+
}),
|
|
131
|
+
).toEqual({ url: [messages.isValidURL.defaultMessage] });
|
|
132
|
+
});
|
|
133
|
+
it('validates url', () => {
|
|
134
|
+
formData.url = 'https://plone.org/';
|
|
135
|
+
expect(
|
|
136
|
+
FormValidation.validateFieldsPerFieldset({
|
|
137
|
+
schema,
|
|
138
|
+
formData,
|
|
139
|
+
formatMessage,
|
|
140
|
+
}),
|
|
141
|
+
).toEqual({});
|
|
142
|
+
});
|
|
143
|
+
it('validates url with ip', () => {
|
|
144
|
+
formData.url = 'http://127.0.0.1:8080/Plone';
|
|
145
|
+
expect(
|
|
146
|
+
FormValidation.validateFieldsPerFieldset({
|
|
147
|
+
schema,
|
|
148
|
+
formData,
|
|
149
|
+
formatMessage,
|
|
150
|
+
}),
|
|
151
|
+
).toEqual({});
|
|
152
|
+
});
|
|
153
|
+
it('validates url with localhost', () => {
|
|
154
|
+
formData.url = 'http://localhost:8080/Plone';
|
|
155
|
+
expect(
|
|
156
|
+
FormValidation.validateFieldsPerFieldset({
|
|
157
|
+
schema,
|
|
158
|
+
formData,
|
|
159
|
+
formatMessage,
|
|
160
|
+
}),
|
|
161
|
+
).toEqual({});
|
|
162
|
+
});
|
|
90
163
|
});
|
|
91
164
|
});
|
|
@@ -97,8 +97,10 @@ class Html extends Component {
|
|
|
97
97
|
} = this.props;
|
|
98
98
|
const head = Helmet.rewind();
|
|
99
99
|
const bodyClass = join(BodyClass.rewind(), ' ');
|
|
100
|
+
const htmlAttributes = head.htmlAttributes.toComponent();
|
|
101
|
+
|
|
100
102
|
return (
|
|
101
|
-
<html lang=
|
|
103
|
+
<html lang={htmlAttributes.lang}>
|
|
102
104
|
<head>
|
|
103
105
|
<meta charSet="utf-8" />
|
|
104
106
|
{head.base.toComponent()}
|
|
@@ -260,4 +260,84 @@ export const messages = defineMessages({
|
|
|
260
260
|
id: 'Show groups of users below',
|
|
261
261
|
defaultMessage: 'Show groups of users below',
|
|
262
262
|
},
|
|
263
|
+
urlClipboardCopy: {
|
|
264
|
+
id: 'Link copied to clipboard',
|
|
265
|
+
defaultMessage: 'Link copied to clipboard',
|
|
266
|
+
},
|
|
267
|
+
inspectRelations: {
|
|
268
|
+
id: 'Inspect relations',
|
|
269
|
+
defaultMessage: 'Inspect relations',
|
|
270
|
+
},
|
|
271
|
+
relations: {
|
|
272
|
+
id: 'Relations',
|
|
273
|
+
defaultMessage: 'Relations',
|
|
274
|
+
},
|
|
275
|
+
fixRelations: {
|
|
276
|
+
id: 'Fix relations',
|
|
277
|
+
defaultMessage: 'Fix relations',
|
|
278
|
+
},
|
|
279
|
+
searchRelationSource: {
|
|
280
|
+
id: 'Search sources by title or path',
|
|
281
|
+
defaultMessage: 'Search sources by title or path',
|
|
282
|
+
},
|
|
283
|
+
searchRelationTarget: {
|
|
284
|
+
id: 'Search targets by title or path',
|
|
285
|
+
defaultMessage: 'Search targets by title or path',
|
|
286
|
+
},
|
|
287
|
+
createOrDeleteRelationsToTarget: {
|
|
288
|
+
id: 'Create or delete relations to target',
|
|
289
|
+
defaultMessage: 'Create or delete relations to target',
|
|
290
|
+
},
|
|
291
|
+
relationName: {
|
|
292
|
+
id: 'Relation name',
|
|
293
|
+
defaultMessage: 'relation',
|
|
294
|
+
},
|
|
295
|
+
selectRelation: {
|
|
296
|
+
id: 'Select relation',
|
|
297
|
+
defaultMessage: 'Select relation',
|
|
298
|
+
},
|
|
299
|
+
norelationfound: {
|
|
300
|
+
id: 'No relation found',
|
|
301
|
+
defaultMessage: 'No relation found',
|
|
302
|
+
},
|
|
303
|
+
toomanyrelationsfound: {
|
|
304
|
+
id: 'Many relations found. Please search.',
|
|
305
|
+
defaultMessage: 'Many relations found. Please search.',
|
|
306
|
+
},
|
|
307
|
+
rebuildRelations: {
|
|
308
|
+
id: 'rebuild relations',
|
|
309
|
+
defaultMessage: 'rebuild relations',
|
|
310
|
+
},
|
|
311
|
+
flushAndRebuildRelations: {
|
|
312
|
+
id: 'flush intIds and rebuild relations',
|
|
313
|
+
defaultMessage: 'flush intIds and rebuild relations',
|
|
314
|
+
},
|
|
315
|
+
addPotentialTargetsPath: {
|
|
316
|
+
id: 'target path',
|
|
317
|
+
defaultMessage: 'target path',
|
|
318
|
+
},
|
|
319
|
+
addPotentialSourcesPath: {
|
|
320
|
+
id: 'sources path',
|
|
321
|
+
defaultMessage: 'sources path',
|
|
322
|
+
},
|
|
323
|
+
relationsUpdated: {
|
|
324
|
+
id: 'Relations updated',
|
|
325
|
+
defaultMessage: 'Relations updated',
|
|
326
|
+
},
|
|
327
|
+
select: {
|
|
328
|
+
id: 'Select',
|
|
329
|
+
defaultMessage: 'Select',
|
|
330
|
+
},
|
|
331
|
+
selected: {
|
|
332
|
+
id: 'Selected',
|
|
333
|
+
defaultMessage: 'Selected',
|
|
334
|
+
},
|
|
335
|
+
filter: {
|
|
336
|
+
id: 'Filter',
|
|
337
|
+
defaultMessage: 'Filter',
|
|
338
|
+
},
|
|
339
|
+
fileTooLarge: {
|
|
340
|
+
id: 'fileTooLarge',
|
|
341
|
+
defaultMessage: 'This website does not accept files larger than {limit}',
|
|
342
|
+
},
|
|
263
343
|
});
|
|
@@ -15,12 +15,9 @@ import { addHeadersFactory } from '@plone/volto/helpers/Proxy/Proxy';
|
|
|
15
15
|
*/
|
|
16
16
|
export const generateRobots = (req) =>
|
|
17
17
|
new Promise((resolve) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
config.settings.internalApiPath ?? config.settings.apiPath
|
|
22
|
-
}/robots.txt`,
|
|
23
|
-
);
|
|
18
|
+
const internalUrl =
|
|
19
|
+
config.settings.internalApiPath ?? config.settings.apiPath;
|
|
20
|
+
const request = superagent.get(`${internalUrl}/robots.txt`);
|
|
24
21
|
request.set('Accept', 'text/plain');
|
|
25
22
|
const authToken = req.universalCookies.get('auth_token');
|
|
26
23
|
if (authToken) {
|
|
@@ -31,6 +28,27 @@ export const generateRobots = (req) =>
|
|
|
31
28
|
if (error) {
|
|
32
29
|
resolve(text || error);
|
|
33
30
|
} else {
|
|
31
|
+
// It appears that express does not take the x-forwarded headers into
|
|
32
|
+
// consideration, so we do it ourselves.
|
|
33
|
+
const {
|
|
34
|
+
'x-forwarded-proto': forwardedProto,
|
|
35
|
+
'x-forwarded-host': forwardedHost,
|
|
36
|
+
'x-forwarded-port': forwardedPort,
|
|
37
|
+
} = req.headers;
|
|
38
|
+
const proto = forwardedProto ?? req.protocol;
|
|
39
|
+
const host = forwardedHost ?? req.get('Host');
|
|
40
|
+
const portNum = forwardedPort ?? req.get('Port');
|
|
41
|
+
const port =
|
|
42
|
+
(proto === 'https' && '' + portNum === '443') ||
|
|
43
|
+
(proto === 'http' && '' + portNum === '80')
|
|
44
|
+
? ''
|
|
45
|
+
: `:${portNum}`;
|
|
46
|
+
// Plone has probably returned the sitemap link with the internal url.
|
|
47
|
+
// If so, let's replace it with the current one.
|
|
48
|
+
const url = `${proto}://${host}${port}`;
|
|
49
|
+
text = text.replace(internalUrl, url);
|
|
50
|
+
// Replace the sitemap with the sitemap index.
|
|
51
|
+
text = text.replace('sitemap.xml.gz', 'sitemap-index.xml');
|
|
34
52
|
resolve(text);
|
|
35
53
|
}
|
|
36
54
|
});
|
|
@@ -28,15 +28,17 @@ class ScrollToTop extends React.Component {
|
|
|
28
28
|
* @memberof ScrollToTop
|
|
29
29
|
*/
|
|
30
30
|
componentDidUpdate(prevProps) {
|
|
31
|
+
const { location } = this.props;
|
|
31
32
|
const noInitialBlocksFocus = // Do not scroll on /edit
|
|
32
33
|
config.blocks?.initialBlocksFocus === null
|
|
33
34
|
? this.props.location?.pathname.slice(-5) !== '/edit'
|
|
34
35
|
: true;
|
|
36
|
+
|
|
37
|
+
const isHash = location?.hash || location?.pathname.hash;
|
|
35
38
|
if (
|
|
36
|
-
!
|
|
37
|
-
!this.props.location?.pathname.hash &&
|
|
39
|
+
!isHash &&
|
|
38
40
|
noInitialBlocksFocus &&
|
|
39
|
-
|
|
41
|
+
location?.pathname !== prevProps.location?.pathname
|
|
40
42
|
) {
|
|
41
43
|
window.scrollTo(0, 0);
|
|
42
44
|
}
|