@plone/volto 17.0.0-alpha.9 → 17.0.1
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/.eslintrc +26 -3
- package/CHANGELOG.md +774 -5
- package/CONTRIBUTING.md +5 -1
- package/README.md +12 -9
- package/RELEASING.md +5 -5
- package/addon-registry.js +10 -1
- package/create-addons-loader.js +1 -1
- package/cypress/support/commands.js +70 -14
- package/cypress/support/e2e.js +1 -2
- package/cypress/support/volto-slate.js +4 -5
- package/cypress.config.js +1 -0
- package/docker-compose.yml +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +281 -53
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +289 -61
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +279 -51
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +318 -90
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +280 -52
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +280 -52
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +281 -53
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +474 -246
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +280 -52
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +281 -53
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +281 -53
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +314 -86
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +281 -53
- package/locales/ro.json +1 -1
- package/locales/volto.pot +284 -52
- package/locales/zh_CN/LC_MESSAGES/volto.po +281 -53
- package/locales/zh_CN.json +1 -1
- package/package.json +44 -34
- 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/TextBlockView.jsx +21 -16
- package/packages/volto-slate/src/blocks/Text/extensions/withDeserializers.js +3 -1
- package/packages/volto-slate/src/blocks/Text/index.js +10 -7
- package/packages/volto-slate/src/editor/config.jsx +5 -4
- 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/Link/render.jsx +5 -6
- 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 +77 -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 +4 -6
- package/src/actions/index.js +4 -0
- package/src/actions/navroot/navroot.js +16 -0
- package/src/actions/navroot/navroot.test.js +15 -0
- package/src/actions/relations/rebuild.js +7 -7
- package/src/actions/relations/relations.js +17 -0
- package/src/actions/site/site.js +16 -0
- package/src/actions/site/site.test.js +15 -0
- package/src/actions/userSession/userSession.js +17 -1
- package/src/components/index.js +194 -192
- package/src/components/manage/Actions/Actions.jsx +133 -243
- package/src/components/manage/Add/Add.jsx +7 -8
- package/src/components/manage/AnchorPlugin/index.jsx +2 -2
- package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
- 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/Settings.jsx +2 -0
- package/src/components/manage/Blocks/Block/Settings.test.jsx +92 -0
- 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 +177 -0
- package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +121 -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 +47 -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/HTML/Edit.jsx +8 -8
- package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +36 -26
- package/src/components/manage/Blocks/Image/Edit.jsx +51 -12
- package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +66 -16
- package/src/components/manage/Blocks/Image/View.jsx +26 -5
- package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
- package/src/components/manage/Blocks/Image/schema.js +17 -10
- package/src/components/manage/Blocks/Image/utils.js +14 -0
- package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
- package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
- package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
- package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
- package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
- package/src/components/manage/Blocks/Listing/ListingBody.jsx +32 -8
- package/src/components/manage/Blocks/Listing/ListingBody.test.jsx +20 -0
- package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -1
- package/src/components/manage/Blocks/Listing/getAsyncData.js +3 -5
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +27 -17
- package/src/components/manage/Blocks/Maps/Edit.jsx +135 -209
- package/src/components/manage/Blocks/Maps/Edit.test.jsx +1 -2
- package/src/components/manage/Blocks/Maps/View.test.jsx +1 -2
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +3 -2
- package/src/components/manage/Blocks/Search/components/Facets.jsx +66 -7
- package/src/components/manage/Blocks/Search/components/FilterList.jsx +4 -6
- package/src/components/manage/Blocks/Search/components/SearchInput.jsx +9 -2
- package/src/components/manage/Blocks/Search/components/SelectFacet.jsx +2 -9
- 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 +5 -2
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +70 -36
- 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 +29 -14
- package/src/components/manage/Blocks/Table/Cell.jsx +2 -3
- package/src/components/manage/Blocks/Teaser/Body.jsx +0 -1
- package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +5 -10
- package/src/components/manage/Blocks/Teaser/schema.js +5 -0
- package/src/components/manage/Blocks/Text/Edit.jsx +2 -3
- package/src/components/manage/Blocks/Title/View.jsx +0 -23
- package/src/components/manage/Blocks/Title/View.test.jsx +16 -1
- package/src/components/manage/Blocks/ToC/Schema.jsx +40 -7
- package/src/components/manage/Blocks/ToC/View.jsx +84 -14
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +8 -3
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
- package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +149 -10
- package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
- package/src/components/manage/Blocks/Video/View.test.jsx +1 -1
- package/src/components/manage/Contents/Contents.jsx +285 -114
- package/src/components/manage/Contents/ContentsPropertiesModal.jsx +90 -166
- package/src/components/manage/Contents/ContentsRenameModal.jsx +88 -139
- package/src/components/manage/Contents/ContentsRenameModal.stories.jsx +61 -0
- package/src/components/manage/Contents/ContentsTagsModal.jsx +83 -130
- package/src/components/manage/Contents/ContentsTagsModal.stories.jsx +68 -0
- package/src/components/manage/Contents/ContentsUploadModal.jsx +11 -7
- package/src/components/manage/Contents/ContentsWorkflowModal.jsx +87 -154
- package/src/components/manage/Controlpanels/Aliases.jsx +4 -12
- package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
- package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +2 -2
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +38 -13
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +5 -5
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +68 -68
- package/src/components/manage/Controlpanels/Rules/AddRule.jsx +3 -10
- package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
- package/src/components/manage/Controlpanels/UndoControlpanel.jsx +6 -9
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +97 -7
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +127 -99
- package/src/components/manage/Delete/Delete.jsx +96 -171
- package/src/components/manage/Diff/DiffField.jsx +25 -1
- package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
- package/src/components/manage/Form/BlockDataForm.jsx +3 -2
- package/src/components/manage/Form/BlockDataForm.test.jsx +51 -17
- package/src/components/manage/Form/Form.jsx +7 -6
- package/src/components/manage/Form/InlineForm.test.jsx +16 -14
- 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 +100 -0
- package/src/components/manage/LockingToastsFactory/LockingToastsFactory.jsx +1 -2
- package/src/components/manage/Messages/Messages.jsx +32 -99
- package/src/components/manage/Messages/Messages.test.jsx +0 -1
- package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
- package/src/components/manage/Sharing/Sharing.jsx +80 -22
- package/src/components/manage/Sidebar/AlignBlock.jsx +1 -1
- package/src/components/manage/Sidebar/Sidebar.jsx +139 -220
- 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 +1 -1
- package/src/components/manage/Toolbar/More.jsx +17 -2
- package/src/components/manage/Toolbar/PersonalTools.jsx +97 -155
- package/src/components/manage/Toolbar/Toolbar.jsx +2 -2
- package/src/components/manage/UniversalLink/UniversalLink.jsx +6 -12
- package/src/components/manage/UniversalLink/UniversalLink.test.jsx +37 -0
- package/src/components/manage/Widgets/AlignWidget.jsx +2 -4
- package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
- package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
- package/src/components/manage/Widgets/ColorPickerWidget.jsx +6 -1
- package/src/components/manage/Widgets/ColorPickerWidget.test.jsx +9 -7
- package/src/components/manage/Widgets/DatetimeWidget.jsx +2 -8
- package/src/components/manage/Widgets/FileWidget.jsx +2 -1
- package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
- package/src/components/manage/Widgets/IdWidget.jsx +1 -2
- package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +2 -9
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +3 -10
- package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.jsx +4 -4
- package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
- package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
- package/src/components/manage/Widgets/SchemaWidget.jsx +6 -9
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
- package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
- package/src/components/manage/Widgets/WysiwygWidget.jsx +2 -9
- package/src/components/manage/Workflow/Workflow.jsx +75 -184
- 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/Comment.stories.jsx +84 -0
- package/src/components/theme/Comments/CommentEditModal.jsx +63 -115
- package/src/components/theme/Comments/Comments.jsx +268 -380
- 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/ContentMetadataTags/ContentMetadataTags.jsx +41 -3
- package/src/components/theme/Error/ServerError.jsx +29 -0
- package/src/components/theme/Header/Header.jsx +37 -63
- package/src/components/theme/Header/Header.test.jsx +18 -0
- package/src/components/theme/Image/Image.jsx +96 -0
- package/src/components/theme/Image/Image.test.jsx +125 -0
- package/src/components/theme/Login/Login.jsx +160 -243
- package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
- package/src/components/theme/Logo/Logo.jsx +35 -27
- package/src/components/theme/Logo/Logo.test.jsx +135 -1
- package/src/components/theme/Logout/Logout.jsx +36 -83
- package/src/components/theme/Navigation/Navigation.jsx +86 -171
- package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -5
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +95 -170
- package/src/components/theme/PreviewImage/PreviewImage.jsx +31 -15
- package/src/components/theme/PreviewImage/PreviewImage.test.js +53 -13
- package/src/components/theme/Register/Register.jsx +2 -4
- package/src/components/theme/Search/SearchTags.jsx +30 -60
- package/src/components/theme/SearchWidget/SearchWidget.jsx +49 -97
- package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
- package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
- package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
- package/src/components/theme/TsTest/TsTest.test.tsx +11 -0
- package/src/components/theme/TsTest/TsTest.tsx +15 -0
- package/src/components/theme/View/AlbumView.jsx +21 -16
- package/src/components/theme/View/EventView.jsx +36 -25
- package/src/components/theme/View/FileView.jsx +23 -18
- package/src/components/theme/View/ImageView.jsx +40 -32
- package/src/components/theme/View/ImageView.test.jsx +4 -0
- package/src/components/theme/View/LinkView.jsx +53 -78
- package/src/components/theme/View/ListingView.jsx +36 -28
- package/src/components/theme/View/NewsItemView.jsx +16 -17
- package/src/components/theme/View/RenderBlocks.jsx +56 -27
- package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
- package/src/components/theme/View/SummaryView.jsx +49 -39
- package/src/components/theme/View/TabularView.jsx +59 -53
- package/src/components/theme/View/View.jsx +2 -0
- package/src/components/theme/Widgets/ImageWidget.stories.jsx +1 -2
- package/src/config/Blocks.jsx +46 -0
- package/src/config/Components.jsx +3 -1
- package/src/config/ControlPanels.js +0 -1
- package/src/config/Loadables.jsx +1 -1
- package/src/config/NonContentRoutes.jsx +1 -0
- package/src/config/RichTextEditor/Blocks.jsx +4 -5
- package/src/config/RichTextEditor/FromHTML.jsx +2 -2
- package/src/config/RichTextEditor/Plugins.jsx +2 -3
- package/src/config/RichTextEditor/Styles.jsx +1 -1
- package/src/config/RichTextEditor/ToHTML.jsx +12 -10
- package/src/config/RichTextEditor/index.js +2 -3
- package/src/config/Views.jsx +6 -4
- package/src/config/Widgets.jsx +3 -0
- package/src/config/index.js +36 -2
- package/src/config/server.js +2 -0
- package/src/constants/ActionTypes.js +4 -0
- package/src/constants/Indexes.js +3 -1
- package/src/express-middleware/devproxy.js +1 -1
- package/src/express-middleware/files.js +11 -9
- package/src/express-middleware/images.js +12 -5
- package/src/express-middleware/ok.js +16 -0
- package/src/express-middleware/robotstxt.js +1 -1
- package/src/express-middleware/sitemap.js +1 -1
- package/src/express-middleware/static.js +3 -3
- package/src/helpers/Blocks/Blocks.js +52 -6
- package/src/helpers/Blocks/Blocks.test.js +92 -13
- package/src/helpers/Extensions/index.js +2 -1
- package/src/helpers/Extensions/withBlockSchemaEnhancer.js +63 -61
- package/src/helpers/Extensions/withBlockSchemaEnhancer.test.js +145 -0
- package/src/helpers/FormValidation/FormValidation.js +37 -7
- package/src/helpers/FormValidation/FormValidation.test.js +32 -0
- package/src/helpers/Html/Html.jsx +2 -8
- package/src/helpers/Loadable/__mocks__/Loadable.js +18 -18
- package/src/helpers/MessageLabels/MessageLabels.js +39 -4
- package/src/helpers/ScrollToTop/ScrollToTop.jsx +5 -3
- package/src/helpers/Site/index.js +21 -0
- package/src/helpers/Url/Url.js +22 -1
- package/src/helpers/Url/Url.test.js +41 -0
- package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +190 -0
- package/src/helpers/Utils/Utils.js +35 -0
- package/src/helpers/Utils/Utils.test.js +13 -0
- package/src/helpers/Utils/usePagination.js +67 -14
- package/src/helpers/Utils/usePagination.test.js +115 -0
- package/src/helpers/index.js +15 -8
- 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.js +203 -173
- package/src/middleware/blacklistRoutes.js +25 -22
- package/src/middleware/index.js +2 -2
- package/src/middleware/storeProtectLoadUtils.js +61 -62
- package/src/middleware/storeProtectLoadUtils.test.js +47 -43
- package/src/reducers/actions/actions.js +7 -5
- package/src/reducers/actions/actions.test.js +70 -0
- package/src/reducers/content/content.test.js +4 -4
- package/src/reducers/index.js +4 -0
- package/src/reducers/navigation/navigation.js +5 -5
- package/src/reducers/navigation/navigation.test.js +30 -0
- package/src/reducers/navroot/navroot.js +79 -0
- package/src/reducers/navroot/navroot.test.js +110 -0
- package/src/reducers/relations/relations.js +74 -46
- package/src/reducers/site/site.js +51 -0
- package/src/reducers/site/site.test.js +67 -0
- package/src/reducers/userSession/userSession.js +15 -1
- package/src/registry.js +2 -2
- package/src/routes.js +9 -0
- package/src/server.jsx +9 -0
- package/src/start-server.js +6 -2
- package/src/storybook.jsx +24 -38
- package/test-setup-config.js +11 -1
- package/theme/themes/pastanaga/collections/form.overrides +46 -0
- package/theme/themes/pastanaga/collections/menu.overrides +3 -2
- package/theme/themes/pastanaga/elements/container.overrides +5 -2
- package/theme/themes/pastanaga/elements/input.overrides +11 -1
- package/theme/themes/pastanaga/elements/label.overrides +10 -0
- package/theme/themes/pastanaga/elements/step.overrides +2 -1
- package/theme/themes/pastanaga/extras/blocks.less +25 -15
- package/theme/themes/pastanaga/extras/color-picker-widget.less +1 -1
- package/theme/themes/pastanaga/extras/contents.less +6 -1
- package/theme/themes/pastanaga/extras/draftjs.less +4 -4
- package/theme/themes/pastanaga/extras/grid.less +427 -0
- package/theme/themes/pastanaga/extras/login.less +3 -0
- package/theme/themes/pastanaga/extras/main.less +14 -7
- package/theme/themes/pastanaga/extras/react-dates-overrides.less +4 -2
- package/theme/themes/pastanaga/extras/search.less +7 -1
- package/theme/themes/pastanaga/extras/sidebar.less +5 -4
- package/theme/themes/pastanaga/extras/time-picker-overrides.less +5 -3
- package/theme/themes/pastanaga/extras/toc.less +29 -0
- package/theme/themes/pastanaga/extras/toolbar.less +6 -2
- package/theme/themes/pastanaga/extras/userscontrolpanel.less +17 -9
- package/theme/themes/pastanaga/extras/widgets.less +1 -1
- package/theme/themes/pastanaga/modules/rating.overrides +2 -1
- package/theme/themes/pastanaga-cms-ui/elements/container.overrides +2 -1
- package/theme/themes/pastanaga-cms-ui/extras/cms-ui.elements.container.less +6 -2
- package/theme/themes/pastanaga-cms-ui/extras/cms-ui.site.less +2 -2
- package/tsconfig.json +33 -0
- package/webpack-plugins/webpack-less-plugin.js +19 -0
- package/.yarn/install-state.gz +0 -0
- package/.yarn/releases/yarn-3.2.3.cjs +0 -783
- package/src/components/manage/Blocks/Teaser/utils.js +0 -44
- package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
- package/src/components/theme/Header/Header.md +0 -27
|
@@ -18,22 +18,22 @@ export const __setLoadables = async () => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
// TODO: filter mockAllLoadables
|
|
21
|
-
export const injectLazyLibs = jest
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
export const injectLazyLibs = jest.fn().mockImplementation(function ([
|
|
22
|
+
libraries,
|
|
23
|
+
]) {
|
|
24
|
+
return jest.fn((WrappedComponent) =>
|
|
25
|
+
jest.fn((props) => {
|
|
26
|
+
return <WrappedComponent {...props} {...mockAllLoadables} />;
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
30
|
|
|
31
|
-
export const preloadLazyLibs = jest
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
export const preloadLazyLibs = jest.fn().mockImplementation(function ([
|
|
32
|
+
libraries,
|
|
33
|
+
]) {
|
|
34
|
+
return jest.fn((WrappedComponent) =>
|
|
35
|
+
jest.fn((props) => {
|
|
36
|
+
return <WrappedComponent {...props} />;
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
});
|
|
@@ -172,6 +172,27 @@ export const messages = defineMessages({
|
|
|
172
172
|
id: 'Roles',
|
|
173
173
|
defaultMessage: 'Roles',
|
|
174
174
|
},
|
|
175
|
+
addUserFormPasswordAndSendPasswordTogetherNotAllowed: {
|
|
176
|
+
id: 'It is not allowed to define both the password and to request sending the password reset message by e-mail. You need to select one of them.',
|
|
177
|
+
defaultMessage:
|
|
178
|
+
'It is not allowed to define both the password and to request sending the password reset message by e-mail. You need to select one of them.',
|
|
179
|
+
},
|
|
180
|
+
userSearchNoResults: {
|
|
181
|
+
id: 'There are no users with the searched criteria',
|
|
182
|
+
defaultMessage: 'There are no users with the searched criteria',
|
|
183
|
+
},
|
|
184
|
+
groupSearchNoResults: {
|
|
185
|
+
id: 'There are no groups with the searched criteria',
|
|
186
|
+
defaultMessage: 'There are no groups with the searched criteria',
|
|
187
|
+
},
|
|
188
|
+
updateUserFormTitle: {
|
|
189
|
+
id: 'Update User',
|
|
190
|
+
defaultMessage: 'Update User',
|
|
191
|
+
},
|
|
192
|
+
updateUserSuccess: {
|
|
193
|
+
id: 'User updated successfuly',
|
|
194
|
+
defaultMessage: 'User updated successfuly',
|
|
195
|
+
},
|
|
175
196
|
updateRoles: {
|
|
176
197
|
id: 'User roles updated',
|
|
177
198
|
defaultMessage: 'User roles updated',
|
|
@@ -234,19 +255,19 @@ export const messages = defineMessages({
|
|
|
234
255
|
},
|
|
235
256
|
copyBlocks: {
|
|
236
257
|
id: 'Copy blocks',
|
|
237
|
-
|
|
258
|
+
defaultMessage: 'Copy blocks',
|
|
238
259
|
},
|
|
239
260
|
cutBlocks: {
|
|
240
261
|
id: 'Cut blocks',
|
|
241
|
-
|
|
262
|
+
defaultMessage: 'Cut blocks',
|
|
242
263
|
},
|
|
243
264
|
pasteBlocks: {
|
|
244
265
|
id: 'Paste blocks',
|
|
245
|
-
|
|
266
|
+
defaultMessage: 'Paste blocks',
|
|
246
267
|
},
|
|
247
268
|
deleteBlocks: {
|
|
248
269
|
id: 'Delete blocks',
|
|
249
|
-
|
|
270
|
+
defaultMessage: 'Delete blocks',
|
|
250
271
|
},
|
|
251
272
|
showAllUserButton: {
|
|
252
273
|
id: 'Show All',
|
|
@@ -260,6 +281,10 @@ export const messages = defineMessages({
|
|
|
260
281
|
id: 'Show groups of users below',
|
|
261
282
|
defaultMessage: 'Show groups of users below',
|
|
262
283
|
},
|
|
284
|
+
urlClipboardCopy: {
|
|
285
|
+
id: 'Link copied to clipboard',
|
|
286
|
+
defaultMessage: 'Anchor link copied to the clipboard',
|
|
287
|
+
},
|
|
263
288
|
inspectRelations: {
|
|
264
289
|
id: 'Inspect relations',
|
|
265
290
|
defaultMessage: 'Inspect relations',
|
|
@@ -308,6 +333,12 @@ export const messages = defineMessages({
|
|
|
308
333
|
id: 'flush intIds and rebuild relations',
|
|
309
334
|
defaultMessage: 'flush intIds and rebuild relations',
|
|
310
335
|
},
|
|
336
|
+
flushAndRebuildRelationsHints: {
|
|
337
|
+
id: 'flushAndRebuildRelationsHints',
|
|
338
|
+
defaultMessage:
|
|
339
|
+
'<ul><li>Regenerate intIds (tokens of relations in relation catalog)</li><li>Rebuild relations</li></ul><p>Check the log for details!</p><p><b>Warning</b>: If you have add-ons relying on intIds, you should not flush them.</p>',
|
|
340
|
+
},
|
|
341
|
+
|
|
311
342
|
addPotentialTargetsPath: {
|
|
312
343
|
id: 'target path',
|
|
313
344
|
defaultMessage: 'target path',
|
|
@@ -332,4 +363,8 @@ export const messages = defineMessages({
|
|
|
332
363
|
id: 'Filter',
|
|
333
364
|
defaultMessage: 'Filter',
|
|
334
365
|
},
|
|
366
|
+
fileTooLarge: {
|
|
367
|
+
id: 'fileTooLarge',
|
|
368
|
+
defaultMessage: 'This website does not accept files larger than {limit}',
|
|
369
|
+
},
|
|
335
370
|
});
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GET_SITE } from '@plone/volto/constants/ActionTypes';
|
|
2
|
+
import { getSite } from '@plone/volto/actions';
|
|
3
|
+
|
|
4
|
+
const getSiteAsyncPropExtender = {
|
|
5
|
+
path: '/',
|
|
6
|
+
extend: (dispatchActions) => {
|
|
7
|
+
if (
|
|
8
|
+
dispatchActions.filter((asyncAction) => asyncAction.key === GET_SITE)
|
|
9
|
+
.length === 0
|
|
10
|
+
) {
|
|
11
|
+
dispatchActions.push({
|
|
12
|
+
key: GET_SITE,
|
|
13
|
+
promise: ({ location, store: { dispatch } }) =>
|
|
14
|
+
__SERVER__ && dispatch(getSite()),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return dispatchActions;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export { getSiteAsyncPropExtender };
|
package/src/helpers/Url/Url.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module helpers/Url
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { last, memoize } from 'lodash';
|
|
6
|
+
import { last, memoize, isArray, isObject, isString } from 'lodash';
|
|
7
7
|
import { urlRegex, telRegex, mailRegex } from './urlRegex';
|
|
8
8
|
import prependHttp from 'prepend-http';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
@@ -251,6 +251,27 @@ export function isUrl(url) {
|
|
|
251
251
|
return urlRegex().test(url);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Get field url
|
|
256
|
+
* @method getFieldURL
|
|
257
|
+
* @param {object} data
|
|
258
|
+
* @returns {string | any} URL string value if field is of url type or any.
|
|
259
|
+
*/
|
|
260
|
+
export const getFieldURL = (data) => {
|
|
261
|
+
let url = data;
|
|
262
|
+
const _isObject = data && isObject(data) && !isArray(data);
|
|
263
|
+
if (_isObject && data['@type'] === 'URL') {
|
|
264
|
+
url = data['value'] ?? data['url'] ?? data['href'] ?? data;
|
|
265
|
+
} else if (_isObject) {
|
|
266
|
+
url = data['@id'] ?? data['url'] ?? data['href'] ?? data;
|
|
267
|
+
}
|
|
268
|
+
if (isArray(data)) {
|
|
269
|
+
url = data.map((item) => getFieldURL(item));
|
|
270
|
+
}
|
|
271
|
+
if (isString(url) && isInternalURL(url)) return flattenToAppURL(url);
|
|
272
|
+
return url;
|
|
273
|
+
};
|
|
274
|
+
|
|
254
275
|
/**
|
|
255
276
|
* Normalize URL, adds protocol (if required eg. user has not entered the protocol)
|
|
256
277
|
* @method normalizeUrl
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isCmsUi,
|
|
11
11
|
isInternalURL,
|
|
12
12
|
isUrl,
|
|
13
|
+
getFieldURL,
|
|
13
14
|
normalizeUrl,
|
|
14
15
|
removeProtocol,
|
|
15
16
|
addAppURL,
|
|
@@ -260,6 +261,46 @@ describe('Url', () => {
|
|
|
260
261
|
expect(isUrl(href)).toBe(false);
|
|
261
262
|
});
|
|
262
263
|
});
|
|
264
|
+
describe('getFieldURL', () => {
|
|
265
|
+
it('returns app URL if the field is a string', () => {
|
|
266
|
+
const field = `${settings.apiPath}/foo/bar`;
|
|
267
|
+
expect(getFieldURL(field)).toBe('/foo/bar');
|
|
268
|
+
});
|
|
269
|
+
it('returns app URL if the field is an object with "@id"', () => {
|
|
270
|
+
const field = { '@id': '/foo/bar' };
|
|
271
|
+
expect(getFieldURL(field)).toBe('/foo/bar');
|
|
272
|
+
});
|
|
273
|
+
it('returns app URL if the field is an object with type URL', () => {
|
|
274
|
+
const field = { '@type': 'URL', value: '/foo/bar' };
|
|
275
|
+
expect(getFieldURL(field)).toBe('/foo/bar');
|
|
276
|
+
});
|
|
277
|
+
it('returns app URL if the field is an object with url or href properties', () => {
|
|
278
|
+
const fieldUrl = { url: '/foo/bar' };
|
|
279
|
+
const fieldHref = { href: '/foo/bar' };
|
|
280
|
+
expect(getFieldURL(fieldUrl)).toBe('/foo/bar');
|
|
281
|
+
expect(getFieldURL(fieldHref)).toBe('/foo/bar');
|
|
282
|
+
});
|
|
283
|
+
it('returns array of app URL if the field is an array of strings', () => {
|
|
284
|
+
const field = [
|
|
285
|
+
`${settings.apiPath}/foo/bar/1`,
|
|
286
|
+
`${settings.apiPath}/foo/bar/2`,
|
|
287
|
+
];
|
|
288
|
+
expect(getFieldURL(field)).toStrictEqual(['/foo/bar/1', '/foo/bar/2']);
|
|
289
|
+
});
|
|
290
|
+
it('returns array of app URL if the field is an array of objects', () => {
|
|
291
|
+
const field = [
|
|
292
|
+
{
|
|
293
|
+
'@type': 'URL',
|
|
294
|
+
value: `${settings.apiPath}/foo/bar/1`,
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
'@type': 'URL',
|
|
298
|
+
value: `${settings.apiPath}/foo/bar/2`,
|
|
299
|
+
},
|
|
300
|
+
];
|
|
301
|
+
expect(getFieldURL(field)).toStrictEqual(['/foo/bar/1', '/foo/bar/2']);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
263
304
|
describe('normalizeUrl', () => {
|
|
264
305
|
it('normalizeUrl test', () => {
|
|
265
306
|
const href = `www.example.com`;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useDetectClickOutside } from './useDetectClickOutside';
|
|
3
|
+
import { Portal } from 'react-portal';
|
|
4
|
+
import { usePopper } from 'react-popper';
|
|
5
|
+
import { BlockChooser } from '@plone/volto/components';
|
|
6
|
+
|
|
7
|
+
function OpenedChooser(props) {
|
|
8
|
+
const blockChooserRef = useDetectClickOutside({
|
|
9
|
+
onTriggered: () => props.setOpenMenu(false),
|
|
10
|
+
triggerKeys: ['Escape'],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div ref={blockChooserRef} style={{ marginLeft: '20px' }}>
|
|
15
|
+
Hello
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function TestComponent(props) {
|
|
21
|
+
const [isOpenMenu, setOpenMenu] = React.useState(false);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div style={{ display: 'flex', marginBottom: '20px' }}>
|
|
25
|
+
<button onClick={() => setOpenMenu(true)}>Click me</button>
|
|
26
|
+
{isOpenMenu && <OpenedChooser setOpenMenu={setOpenMenu} />}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function StoryComponent(args) {
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<TestComponent />
|
|
35
|
+
<TestComponent />
|
|
36
|
+
<TestComponent />
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function OpenedChooserWithPortal(props) {
|
|
42
|
+
const blockChooserRef = useDetectClickOutside({
|
|
43
|
+
onTriggered: () => props.setOpenMenu(false),
|
|
44
|
+
triggerKeys: ['Escape'],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Portal node={document.getElementById('body')}>
|
|
49
|
+
<div ref={blockChooserRef}>{`Hello ${props.id}`}</div>
|
|
50
|
+
</Portal>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function TestComponentWithPortal(props) {
|
|
55
|
+
const [isOpenMenu, setOpenMenu] = React.useState(false);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div style={{ display: 'flex', marginBottom: '20px' }}>
|
|
59
|
+
<button
|
|
60
|
+
onClick={() => setOpenMenu(true)}
|
|
61
|
+
>{`Click me ${props.id}`}</button>
|
|
62
|
+
{isOpenMenu && (
|
|
63
|
+
<OpenedChooserWithPortal {...props} setOpenMenu={setOpenMenu} />
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function StoryComponentWithPortal(args) {
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<TestComponentWithPortal id={1} />
|
|
73
|
+
<TestComponentWithPortal id={2} />
|
|
74
|
+
<TestComponentWithPortal id={3} />
|
|
75
|
+
</>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function OpenedChooserWithPortalAndPopper(props) {
|
|
80
|
+
const { showBlockChooser } = props;
|
|
81
|
+
|
|
82
|
+
const blockChooserRef = useDetectClickOutside({
|
|
83
|
+
onTriggered: () => props.setOpenMenu(false),
|
|
84
|
+
triggerKeys: ['Escape'],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return showBlockChooser ? (
|
|
88
|
+
<BlockChooser
|
|
89
|
+
// onMutateBlock={onMutateBlock}
|
|
90
|
+
// currentBlock={block}
|
|
91
|
+
showRestricted
|
|
92
|
+
// blocksConfig={blocksConfig}
|
|
93
|
+
ref={blockChooserRef}
|
|
94
|
+
/>
|
|
95
|
+
) : (
|
|
96
|
+
<div ref={blockChooserRef}>{`Hello ${props.id}`}</div>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function TestComponentWithPortalAndPopper(props) {
|
|
101
|
+
const [isOpenMenu, setOpenMenu] = React.useState(false);
|
|
102
|
+
const [referenceElement, setReferenceElement] = React.useState(null);
|
|
103
|
+
const [popperElement, setPopperElement] = React.useState(null);
|
|
104
|
+
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
|
105
|
+
placement: 'right',
|
|
106
|
+
modifiers: [
|
|
107
|
+
{
|
|
108
|
+
name: 'offset',
|
|
109
|
+
options: {
|
|
110
|
+
offset: [-10, 10],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'flip',
|
|
115
|
+
options: {
|
|
116
|
+
fallbackPlacements: ['top-start'],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
return (
|
|
122
|
+
<div style={{ display: 'flex', marginBottom: '20px' }}>
|
|
123
|
+
<button
|
|
124
|
+
ref={setReferenceElement}
|
|
125
|
+
onClick={() => setOpenMenu(true)}
|
|
126
|
+
>{`Click me ${props.id}`}</button>
|
|
127
|
+
<Portal node={document.getElementById('body')}>
|
|
128
|
+
<div
|
|
129
|
+
ref={setPopperElement}
|
|
130
|
+
style={styles.popper}
|
|
131
|
+
{...attributes.popper}
|
|
132
|
+
>
|
|
133
|
+
{isOpenMenu && (
|
|
134
|
+
<OpenedChooserWithPortalAndPopper
|
|
135
|
+
{...props}
|
|
136
|
+
setOpenMenu={setOpenMenu}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
</Portal>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function StoryComponentWithPortalAndPopper(args) {
|
|
146
|
+
const { showBlockChooser } = args;
|
|
147
|
+
return (
|
|
148
|
+
<>
|
|
149
|
+
<TestComponentWithPortalAndPopper
|
|
150
|
+
id={1}
|
|
151
|
+
showBlockChooser={showBlockChooser}
|
|
152
|
+
/>
|
|
153
|
+
<TestComponentWithPortalAndPopper
|
|
154
|
+
id={2}
|
|
155
|
+
showBlockChooser={showBlockChooser}
|
|
156
|
+
/>
|
|
157
|
+
<TestComponentWithPortalAndPopper
|
|
158
|
+
id={3}
|
|
159
|
+
showBlockChooser={showBlockChooser}
|
|
160
|
+
/>
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export const Default = StoryComponent.bind({});
|
|
166
|
+
Default.args = {};
|
|
167
|
+
|
|
168
|
+
export const WithPortal = StoryComponentWithPortal.bind({});
|
|
169
|
+
WithPortal.args = {};
|
|
170
|
+
|
|
171
|
+
export const WithPortalAndPopper = StoryComponentWithPortalAndPopper.bind({});
|
|
172
|
+
WithPortalAndPopper.args = {};
|
|
173
|
+
|
|
174
|
+
export const WithPortalAndPopperUsingBlockChooser =
|
|
175
|
+
StoryComponentWithPortalAndPopper.bind({});
|
|
176
|
+
WithPortalAndPopperUsingBlockChooser.args = {
|
|
177
|
+
showBlockChooser: true,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export default {
|
|
181
|
+
title: 'Internal Components/useDetectClickOutside',
|
|
182
|
+
component: TestComponent,
|
|
183
|
+
decorators: [
|
|
184
|
+
(Story) => (
|
|
185
|
+
<div style={{ width: '600px' }}>
|
|
186
|
+
<Story />
|
|
187
|
+
</div>
|
|
188
|
+
),
|
|
189
|
+
],
|
|
190
|
+
};
|
|
@@ -284,6 +284,16 @@ export const reorderArray = (array, origin, target) => {
|
|
|
284
284
|
return result;
|
|
285
285
|
};
|
|
286
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Normalize (unicode) string to a normalized plain ascii string
|
|
289
|
+
* @method normalizeString
|
|
290
|
+
* @param {string} str The string to be normalized
|
|
291
|
+
* @returns {string} Normalized plain ascii string
|
|
292
|
+
*/
|
|
293
|
+
export function normalizeString(str) {
|
|
294
|
+
return str.normalize('NFD').replace(/\p{Diacritic}/gu, '');
|
|
295
|
+
}
|
|
296
|
+
|
|
287
297
|
/**
|
|
288
298
|
* Slugify a string: remove whitespaces, special chars and replace with _
|
|
289
299
|
* @param {string} string String to be slugified
|
|
@@ -324,3 +334,28 @@ export const arrayRange = (start, stop, step) =>
|
|
|
324
334
|
{ length: (stop - start) / step + 1 },
|
|
325
335
|
(value, index) => start + index * step,
|
|
326
336
|
);
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Given an event target element returns if it's an interactive element
|
|
340
|
+
* of the one in the list.
|
|
341
|
+
* @param {node} element event.target element type
|
|
342
|
+
* @returns {boolean} If it's an interactive element of the list
|
|
343
|
+
*/
|
|
344
|
+
export function isInteractiveElement(
|
|
345
|
+
element,
|
|
346
|
+
interactiveElements = [
|
|
347
|
+
'button',
|
|
348
|
+
'input',
|
|
349
|
+
'textarea',
|
|
350
|
+
'select',
|
|
351
|
+
'option',
|
|
352
|
+
'svg',
|
|
353
|
+
'path',
|
|
354
|
+
],
|
|
355
|
+
) {
|
|
356
|
+
if (interactiveElements.includes(element.tagName.toLowerCase())) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
safeWrapper,
|
|
15
15
|
slugify,
|
|
16
16
|
cloneDeepSchema,
|
|
17
|
+
normalizeString,
|
|
17
18
|
} from './Utils';
|
|
18
19
|
import moment from 'moment';
|
|
19
20
|
import deepFreeze from 'deep-freeze';
|
|
@@ -386,6 +387,18 @@ describe('Utils tests', () => {
|
|
|
386
387
|
});
|
|
387
388
|
});
|
|
388
389
|
|
|
390
|
+
describe('normalizeString', () => {
|
|
391
|
+
it('normalizeString no diacritics', () => {
|
|
392
|
+
const str = `my string without diacritics`;
|
|
393
|
+
expect(normalizeString(str)).toBe('my string without diacritics');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('normalizeString with diacritics', () => {
|
|
397
|
+
const str = `my Ü Ú é à ñ string with diacritics`;
|
|
398
|
+
expect(normalizeString(str)).toBe('my U U e a n string with diacritics');
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
|
|
389
402
|
describe('slugify', () => {
|
|
390
403
|
it('slugifies a standard string', () => {
|
|
391
404
|
expect(slugify('Content Type')).toBe('content_type');
|
|
@@ -1,25 +1,78 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import React, { useRef, useEffect } from 'react';
|
|
2
|
+
import { useHistory, useLocation } from 'react-router-dom';
|
|
3
|
+
import qs from 'query-string';
|
|
4
|
+
import { useSelector } from 'react-redux';
|
|
5
|
+
import { findBlocks, slugify } from '@plone/volto/helpers';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @function useCreatePageQueryStringKey
|
|
9
|
+
* @description A hook that creates a key with an id if there are multiple blocks with pagination.
|
|
10
|
+
* @returns {string} Example: page || page_012345678
|
|
11
|
+
*/
|
|
12
|
+
const useCreatePageQueryStringKey = (id) => {
|
|
13
|
+
const blockTypesWithPagination = ['search', 'listing'];
|
|
14
|
+
const blocks = useSelector((state) => state?.content?.data?.blocks) || [];
|
|
15
|
+
const hasMultiplePaginations =
|
|
16
|
+
findBlocks(blocks, blockTypesWithPagination).length > 1;
|
|
17
|
+
|
|
18
|
+
return hasMultiplePaginations ? slugify(`page-${id}`) : 'page';
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const useGetBlockType = (id) => {
|
|
22
|
+
const blocks = useSelector((state) => state?.content?.data?.blocks) || [];
|
|
23
|
+
const block = blocks[id];
|
|
24
|
+
return block ? block?.['@type'] : null;
|
|
25
|
+
};
|
|
5
26
|
|
|
6
27
|
/**
|
|
7
28
|
* A pagination helper that tracks the query and resets pagination in case the
|
|
8
29
|
* query changes.
|
|
9
30
|
*/
|
|
10
|
-
export const usePagination = (
|
|
11
|
-
const
|
|
12
|
-
const
|
|
31
|
+
export const usePagination = (id = null, defaultPage = 1) => {
|
|
32
|
+
const location = useLocation();
|
|
33
|
+
const history = useHistory();
|
|
34
|
+
const pageQueryStringKey = useCreatePageQueryStringKey(id);
|
|
35
|
+
const block_type = useGetBlockType(id);
|
|
36
|
+
const pageQueryParam =
|
|
37
|
+
qs.parse(location.search)[pageQueryStringKey] || defaultPage;
|
|
38
|
+
const [currentPage, setCurrentPageState] = React.useState(
|
|
39
|
+
parseInt(pageQueryParam),
|
|
40
|
+
);
|
|
41
|
+
const setCurrentPage = (page) => {
|
|
42
|
+
setCurrentPageState(page);
|
|
43
|
+
const newParams = {
|
|
44
|
+
...qs.parse(location.search),
|
|
45
|
+
[pageQueryStringKey]: page,
|
|
46
|
+
};
|
|
47
|
+
history.push({ search: qs.stringify(newParams) });
|
|
48
|
+
};
|
|
13
49
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
50
|
+
const queryRef = useRef(qs.parse(location.search)?.query);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (
|
|
53
|
+
queryRef.current !== qs.parse(location.search)?.query &&
|
|
54
|
+
block_type === 'search'
|
|
55
|
+
) {
|
|
56
|
+
setCurrentPageState(defaultPage);
|
|
57
|
+
const newParams = {
|
|
58
|
+
...qs.parse(location.search),
|
|
59
|
+
[pageQueryStringKey]: defaultPage,
|
|
60
|
+
};
|
|
61
|
+
delete newParams[pageQueryStringKey];
|
|
62
|
+
history.replace({ search: qs.stringify(newParams) });
|
|
63
|
+
queryRef.current = qs.parse(location.search)?.query;
|
|
64
|
+
} else {
|
|
65
|
+
setCurrentPageState(
|
|
66
|
+
parseInt(
|
|
67
|
+
qs.parse(location.search)?.[pageQueryStringKey] || defaultPage,
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
}, [location.search, block_type]);
|
|
17
73
|
|
|
18
74
|
return {
|
|
19
|
-
currentPage
|
|
20
|
-
previousQuery && !isEqual(previousQuery, query)
|
|
21
|
-
? defaultPage
|
|
22
|
-
: currentPage,
|
|
75
|
+
currentPage,
|
|
23
76
|
setCurrentPage,
|
|
24
77
|
};
|
|
25
78
|
};
|