@plone/volto 17.0.0-alpha.2 → 17.0.0-alpha.21
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 +549 -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 +58 -5
- package/cypress/support/e2e.js +1 -2
- package/cypress/support/volto-slate.js +4 -5
- package/docker-compose.yml +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +282 -7
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +301 -26
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +281 -6
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +291 -16
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +282 -7
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +4891 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +282 -7
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +284 -9
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +282 -7
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +937 -650
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +282 -7
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +291 -16
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +282 -7
- package/locales/ro.json +1 -1
- package/locales/volto.pot +282 -7
- package/locales/zh_CN/LC_MESSAGES/volto.po +282 -7
- package/locales/zh_CN.json +1 -1
- package/package.json +8 -6
- 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 +3 -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 +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 +25 -5
- package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
- package/src/components/manage/Blocks/Image/schema.js +12 -9
- 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/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/SummaryTemplate.jsx +1 -1
- 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 +5 -10
- 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 +47 -32
- 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/Sidebar/AlignBlock.jsx +1 -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/Image/Image.jsx +96 -0
- package/src/components/theme/Image/Image.test.jsx +125 -0
- 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 +4 -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/PreviewImage/PreviewImage.jsx +25 -14
- package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
- 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 +20 -16
- 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 +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 -21
- 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/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 +46 -0
- package/src/config/Components.jsx +2 -1
- 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 +49 -7
- package/src/helpers/Url/Url.test.js +67 -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 +11 -1
- package/theme/themes/pastanaga/extras/blocks.less +5 -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 +8 -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/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
- package/towncrier.toml +0 -33
|
@@ -11,19 +11,23 @@ import { addHeadersFactory } from '@plone/volto/helpers/Proxy/Proxy';
|
|
|
11
11
|
|
|
12
12
|
import config from '@plone/volto/registry';
|
|
13
13
|
|
|
14
|
+
export const SITEMAP_BATCH_SIZE = 5000;
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* Generate sitemap
|
|
16
18
|
* @function generateSitemap
|
|
17
19
|
* @param {Object} _req Request object
|
|
18
20
|
* @return {string} Generated sitemap
|
|
19
21
|
*/
|
|
20
|
-
export const generateSitemap = (_req) =>
|
|
22
|
+
export const generateSitemap = (_req, start = 0, size = undefined) =>
|
|
21
23
|
new Promise((resolve) => {
|
|
22
24
|
const { settings } = config;
|
|
23
25
|
const APISUFIX = settings.legacyTraverse ? '' : '/++api++';
|
|
24
26
|
const apiPath = settings.internalApiPath ?? settings.apiPath;
|
|
25
27
|
const request = superagent.get(
|
|
26
|
-
`${apiPath}${APISUFIX}/@search?metadata_fields=modified&b_size
|
|
28
|
+
`${apiPath}${APISUFIX}/@search?metadata_fields=modified&b_start=${start}&b_size=${
|
|
29
|
+
size !== undefined ? size : 100000000
|
|
30
|
+
}&use_site_search_settings=1`,
|
|
27
31
|
);
|
|
28
32
|
request.set('Accept', 'application/json');
|
|
29
33
|
request.use(addHeadersFactory(_req));
|
|
@@ -50,3 +54,41 @@ export const generateSitemap = (_req) =>
|
|
|
50
54
|
}
|
|
51
55
|
});
|
|
52
56
|
});
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Generate sitemap
|
|
60
|
+
* @function generateSitemapIndex
|
|
61
|
+
* @param {Object} _req Request object
|
|
62
|
+
* @return {string} Generated sitemap index
|
|
63
|
+
*/
|
|
64
|
+
export const generateSitemapIndex = (_req) =>
|
|
65
|
+
new Promise((resolve) => {
|
|
66
|
+
const { settings } = config;
|
|
67
|
+
const APISUFIX = settings.legacyTraverse ? '' : '/++api++';
|
|
68
|
+
const apiPath = settings.internalApiPath ?? settings.apiPath;
|
|
69
|
+
const request = superagent.get(
|
|
70
|
+
`${apiPath}${APISUFIX}/@search?metadata_fields=modified&b_size=0&use_site_search_settings=1`,
|
|
71
|
+
);
|
|
72
|
+
request.set('Accept', 'application/json');
|
|
73
|
+
const authToken = _req.universalCookies.get('auth_token');
|
|
74
|
+
if (authToken) {
|
|
75
|
+
request.set('Authorization', `Bearer ${authToken}`);
|
|
76
|
+
}
|
|
77
|
+
request.end((error, { body } = {}) => {
|
|
78
|
+
if (error) {
|
|
79
|
+
resolve(body || error);
|
|
80
|
+
} else {
|
|
81
|
+
const items = Array.from(
|
|
82
|
+
{ length: Math.ceil(body.items_total / SITEMAP_BATCH_SIZE) },
|
|
83
|
+
(_, i) =>
|
|
84
|
+
` <sitemap>
|
|
85
|
+
<loc>${toPublicURL('/sitemap' + (i + 1) + '.xml.gz')}</loc>
|
|
86
|
+
</sitemap>`,
|
|
87
|
+
);
|
|
88
|
+
const result = `<?xml version="1.0" encoding="UTF-8"?>
|
|
89
|
+
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
90
|
+
${items.join('\n')}\n</sitemapindex>`;
|
|
91
|
+
resolve(result);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
package/src/helpers/Url/Url.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
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';
|
|
10
|
+
import { matchPath } from 'react-router';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Get base url.
|
|
@@ -213,7 +214,17 @@ export function expandToBackendURL(path) {
|
|
|
213
214
|
*/
|
|
214
215
|
export function isInternalURL(url) {
|
|
215
216
|
const { settings } = config;
|
|
216
|
-
|
|
217
|
+
|
|
218
|
+
const isMatch = (config.settings.externalRoutes ?? []).find((route) => {
|
|
219
|
+
if (typeof route === 'object') {
|
|
220
|
+
return matchPath(flattenToAppURL(url), route.match);
|
|
221
|
+
}
|
|
222
|
+
return matchPath(flattenToAppURL(url), route);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const isExcluded = isMatch && Object.keys(isMatch)?.length > 0;
|
|
226
|
+
|
|
227
|
+
const internalURL =
|
|
217
228
|
url &&
|
|
218
229
|
(url.indexOf(settings.publicURL) !== -1 ||
|
|
219
230
|
(settings.internalApiPath &&
|
|
@@ -221,8 +232,13 @@ export function isInternalURL(url) {
|
|
|
221
232
|
url.indexOf(settings.apiPath) !== -1 ||
|
|
222
233
|
url.charAt(0) === '/' ||
|
|
223
234
|
url.charAt(0) === '.' ||
|
|
224
|
-
url.startsWith('#'))
|
|
225
|
-
|
|
235
|
+
url.startsWith('#'));
|
|
236
|
+
|
|
237
|
+
if (internalURL && isExcluded) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return internalURL;
|
|
226
242
|
}
|
|
227
243
|
|
|
228
244
|
/**
|
|
@@ -235,6 +251,27 @@ export function isUrl(url) {
|
|
|
235
251
|
return urlRegex().test(url);
|
|
236
252
|
}
|
|
237
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
|
+
|
|
238
275
|
/**
|
|
239
276
|
* Normalize URL, adds protocol (if required eg. user has not entered the protocol)
|
|
240
277
|
* @method normalizeUrl
|
|
@@ -264,14 +301,14 @@ export function isTelephone(text) {
|
|
|
264
301
|
}
|
|
265
302
|
|
|
266
303
|
export function normaliseMail(email) {
|
|
267
|
-
if (email
|
|
304
|
+
if (email?.toLowerCase()?.startsWith('mailto:')) {
|
|
268
305
|
return email;
|
|
269
306
|
}
|
|
270
307
|
return `mailto:${email}`;
|
|
271
308
|
}
|
|
272
309
|
|
|
273
310
|
export function normalizeTelephone(tel) {
|
|
274
|
-
if (tel
|
|
311
|
+
if (tel?.toLowerCase()?.startsWith('tel:')) {
|
|
275
312
|
return tel;
|
|
276
313
|
}
|
|
277
314
|
return `tel:${tel}`;
|
|
@@ -294,12 +331,17 @@ export function checkAndNormalizeUrl(url) {
|
|
|
294
331
|
res.url = URLUtils.normalizeTelephone(url);
|
|
295
332
|
} else {
|
|
296
333
|
//url
|
|
297
|
-
if (
|
|
334
|
+
if (
|
|
335
|
+
res.url?.length >= 0 &&
|
|
336
|
+
!res.url.startsWith('/') &&
|
|
337
|
+
!res.url.startsWith('#')
|
|
338
|
+
) {
|
|
298
339
|
res.url = URLUtils.normalizeUrl(url);
|
|
299
340
|
if (!URLUtils.isUrl(res.url)) {
|
|
300
341
|
res.isValid = false;
|
|
301
342
|
}
|
|
302
343
|
}
|
|
344
|
+
if (res.url === undefined || res.url === null) res.isValid = false;
|
|
303
345
|
}
|
|
304
346
|
return res;
|
|
305
347
|
}
|
|
@@ -10,10 +10,14 @@ import {
|
|
|
10
10
|
isCmsUi,
|
|
11
11
|
isInternalURL,
|
|
12
12
|
isUrl,
|
|
13
|
+
getFieldURL,
|
|
13
14
|
normalizeUrl,
|
|
14
15
|
removeProtocol,
|
|
15
16
|
addAppURL,
|
|
16
17
|
expandToBackendURL,
|
|
18
|
+
checkAndNormalizeUrl,
|
|
19
|
+
normaliseMail,
|
|
20
|
+
normalizeTelephone,
|
|
17
21
|
} from './Url';
|
|
18
22
|
|
|
19
23
|
beforeEach(() => {
|
|
@@ -61,6 +65,17 @@ describe('Url', () => {
|
|
|
61
65
|
it('return empty string if no url is empty string', () => {
|
|
62
66
|
expect(getBaseUrl('')).toBe('');
|
|
63
67
|
});
|
|
68
|
+
it('return a null/undefined mailto adress ', () => {
|
|
69
|
+
expect(normaliseMail(null)).toBe('mailto:null');
|
|
70
|
+
expect(normaliseMail(undefined)).toBe('mailto:undefined');
|
|
71
|
+
});
|
|
72
|
+
it('return a null/undefined telephone number', () => {
|
|
73
|
+
expect(normalizeTelephone(null)).toBe('tel:null');
|
|
74
|
+
expect(normalizeTelephone(undefined)).toBe('tel:undefined');
|
|
75
|
+
});
|
|
76
|
+
it('null returns an invalid link', () => {
|
|
77
|
+
expect(checkAndNormalizeUrl(null).isValid).toBe(false);
|
|
78
|
+
});
|
|
64
79
|
});
|
|
65
80
|
|
|
66
81
|
describe('getView', () => {
|
|
@@ -191,6 +206,7 @@ describe('Url', () => {
|
|
|
191
206
|
expect(isInternalURL(href)).toBe(false);
|
|
192
207
|
settings.internalApiPath = saved;
|
|
193
208
|
});
|
|
209
|
+
|
|
194
210
|
it('tells if an URL is internal if it is an anchor', () => {
|
|
195
211
|
const href = '#anchor';
|
|
196
212
|
expect(isInternalURL(href)).toBe(true);
|
|
@@ -211,6 +227,17 @@ describe('Url', () => {
|
|
|
211
227
|
const href = undefined;
|
|
212
228
|
expect(isInternalURL(href)).toBe(undefined);
|
|
213
229
|
});
|
|
230
|
+
it('tells if an URL is external if settings.externalroutes is persent.', () => {
|
|
231
|
+
const url = `https://localhost:3000/fb/my-page/contents`;
|
|
232
|
+
const blacklistedurl = '/blacklisted';
|
|
233
|
+
settings.externalRoutes = [
|
|
234
|
+
{ title: 'My Page', match: '/fb' },
|
|
235
|
+
'/blacklisted',
|
|
236
|
+
];
|
|
237
|
+
settings.publicURL = 'https://localhost:3000';
|
|
238
|
+
expect(isInternalURL(url)).toBe(false);
|
|
239
|
+
expect(isInternalURL(blacklistedurl)).toBe(false);
|
|
240
|
+
});
|
|
214
241
|
});
|
|
215
242
|
describe('isUrl', () => {
|
|
216
243
|
it('isUrl test', () => {
|
|
@@ -234,6 +261,46 @@ describe('Url', () => {
|
|
|
234
261
|
expect(isUrl(href)).toBe(false);
|
|
235
262
|
});
|
|
236
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
|
+
});
|
|
237
304
|
describe('normalizeUrl', () => {
|
|
238
305
|
it('normalizeUrl test', () => {
|
|
239
306
|
const href = `www.example.com`;
|
|
@@ -0,0 +1,191 @@
|
|
|
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 = StoryComponentWithPortalAndPopper.bind(
|
|
175
|
+
{},
|
|
176
|
+
);
|
|
177
|
+
WithPortalAndPopperUsingBlockChooser.args = {
|
|
178
|
+
showBlockChooser: true,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export default {
|
|
182
|
+
title: 'Internal Components/useDetectClickOutside',
|
|
183
|
+
component: TestComponent,
|
|
184
|
+
decorators: [
|
|
185
|
+
(Story) => (
|
|
186
|
+
<div style={{ width: '600px' }}>
|
|
187
|
+
<Story />
|
|
188
|
+
</div>
|
|
189
|
+
),
|
|
190
|
+
],
|
|
191
|
+
};
|
|
@@ -174,13 +174,13 @@ export const parseDateTime = (locale, value, format, moment) => {
|
|
|
174
174
|
};
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
* Converts a language code to the format `lang_region`
|
|
177
|
+
* Converts a language code like pt-br to the format `pt_BR` (`lang_region`)
|
|
178
178
|
* Useful for passing from Plone's i18n lang names to Xnix locale names
|
|
179
|
-
* eg. LC_MESSAGES/lang_region.po filenames
|
|
179
|
+
* eg. LC_MESSAGES/lang_region.po filenames. Also used in the I18N_LANGUAGE cookie.
|
|
180
180
|
* @param {string} language Language to be converted
|
|
181
181
|
* @returns {string} Language converted
|
|
182
182
|
*/
|
|
183
|
-
export const
|
|
183
|
+
export const toGettextLang = (language) => {
|
|
184
184
|
if (language.includes('-')) {
|
|
185
185
|
let normalizedLang = language.split('-');
|
|
186
186
|
normalizedLang = `${normalizedLang[0]}_${normalizedLang[1].toUpperCase()}`;
|
|
@@ -189,23 +189,35 @@ export const normalizeLanguageName = (language) => {
|
|
|
189
189
|
|
|
190
190
|
return language;
|
|
191
191
|
};
|
|
192
|
+
export const normalizeLanguageName = toGettextLang;
|
|
192
193
|
|
|
193
194
|
/**
|
|
194
|
-
* Converts a language code to the format `
|
|
195
|
-
* `react-intl` only supports this syntax
|
|
196
|
-
*
|
|
195
|
+
* Converts a language code like pt-br or pt_BR to the format `pt-BR`.
|
|
196
|
+
* `react-intl` only supports this syntax. We also use it for the locales
|
|
197
|
+
* in the volto Redux store.
|
|
197
198
|
* @param {string} language Language to be converted
|
|
198
199
|
* @returns {string} Language converted
|
|
199
200
|
*/
|
|
200
|
-
export const
|
|
201
|
-
if (language.includes('_')) {
|
|
202
|
-
let langCode = language.split(
|
|
201
|
+
export const toReactIntlLang = (language) => {
|
|
202
|
+
if (language.includes('_') || language.includes('-')) {
|
|
203
|
+
let langCode = language.split(/[-_]/);
|
|
203
204
|
langCode = `${langCode[0]}-${langCode[1].toUpperCase()}`;
|
|
204
205
|
return langCode;
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
return language;
|
|
208
209
|
};
|
|
210
|
+
export const toLangUnderscoreRegion = toReactIntlLang; // old name for backwards-compat
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Converts a language code like pt_BR or pt-BR to the format `pt-br`.
|
|
214
|
+
* This format is used on the backend and in volto config settings.
|
|
215
|
+
* @param {string} language Language to be converted
|
|
216
|
+
* @returns {string} Language converted
|
|
217
|
+
*/
|
|
218
|
+
export const toBackendLang = (language) => {
|
|
219
|
+
return toReactIntlLang(language).toLowerCase();
|
|
220
|
+
};
|
|
209
221
|
|
|
210
222
|
/**
|
|
211
223
|
* Lookup if a given expander is set in apiExpanders for the given path and action type
|
|
@@ -258,11 +270,11 @@ export const removeFromArray = (array, index) => {
|
|
|
258
270
|
};
|
|
259
271
|
|
|
260
272
|
/**
|
|
261
|
-
*
|
|
273
|
+
* Moves an item from origin to target inside an array in an immutable way
|
|
262
274
|
* @param {Array} array Array with data
|
|
263
|
-
* @param {number} origin Index of item to be
|
|
264
|
-
* @param {number} target Index of item to be
|
|
265
|
-
* @returns {Array}
|
|
275
|
+
* @param {number} origin Index of item to be moved from
|
|
276
|
+
* @param {number} target Index of item to be moved to
|
|
277
|
+
* @returns {Array} Resultant array
|
|
266
278
|
*/
|
|
267
279
|
export const reorderArray = (array, origin, target) => {
|
|
268
280
|
const result = Array.from(array);
|
|
@@ -299,3 +311,41 @@ export const cloneDeepSchema = (object) => {
|
|
|
299
311
|
}
|
|
300
312
|
});
|
|
301
313
|
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Creates an array given a range of numbers
|
|
317
|
+
* @param {number} start start number from
|
|
318
|
+
* @param {number} stop stop number at
|
|
319
|
+
* @param {number} step step every each number in the sequence
|
|
320
|
+
* @returns {array} The result, eg. [0, 1, 2, 3, 4]
|
|
321
|
+
*/
|
|
322
|
+
export const arrayRange = (start, stop, step) =>
|
|
323
|
+
Array.from(
|
|
324
|
+
{ length: (stop - start) / step + 1 },
|
|
325
|
+
(value, index) => start + index * step,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Given an event target element returns if it's an interactive element
|
|
330
|
+
* of the one in the list.
|
|
331
|
+
* @param {node} element event.target element type
|
|
332
|
+
* @returns {boolean} If it's an interactive element of the list
|
|
333
|
+
*/
|
|
334
|
+
export function isInteractiveElement(
|
|
335
|
+
element,
|
|
336
|
+
interactiveElements = [
|
|
337
|
+
'button',
|
|
338
|
+
'input',
|
|
339
|
+
'textarea',
|
|
340
|
+
'select',
|
|
341
|
+
'option',
|
|
342
|
+
'svg',
|
|
343
|
+
'path',
|
|
344
|
+
],
|
|
345
|
+
) {
|
|
346
|
+
if (interactiveElements.includes(element.tagName.toLowerCase())) {
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getColor,
|
|
7
7
|
getInitials,
|
|
8
8
|
hasApiExpander,
|
|
9
|
-
|
|
9
|
+
toGettextLang,
|
|
10
10
|
parseDateTime,
|
|
11
11
|
removeFromArray,
|
|
12
12
|
reorderArray,
|
|
@@ -284,12 +284,12 @@ describe('Utils tests', () => {
|
|
|
284
284
|
});
|
|
285
285
|
});
|
|
286
286
|
|
|
287
|
-
describe('
|
|
287
|
+
describe('toGettextLang', () => {
|
|
288
288
|
it('Normalizes an extended language (pt_BR)', () => {
|
|
289
|
-
expect(
|
|
289
|
+
expect(toGettextLang('pt-br')).toStrictEqual('pt_BR');
|
|
290
290
|
});
|
|
291
291
|
it('Normalizes a simple language (ca)', () => {
|
|
292
|
-
expect(
|
|
292
|
+
expect(toGettextLang('ca')).toStrictEqual('ca');
|
|
293
293
|
});
|
|
294
294
|
});
|
|
295
295
|
|