@plone/volto 15.5.0 → 15.7.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/assets.json +1 -1
  3. package/dist/chunks.json +22 -22
  4. package/dist/loadable-stats.json +58 -58
  5. package/dist/public/static/css/{client.d1eef743.chunk.css → client.cc159f67.chunk.css} +2 -2
  6. package/dist/public/static/css/{plone-volto-components-manage-Widgets-DatetimeWidget.c6a47163.chunk.css → plone-volto-components-manage-Widgets-DatetimeWidget.843e0db1.chunk.css} +1 -1
  7. package/dist/public/static/js/client.cc159f67.chunk.js +2 -0
  8. package/dist/public/static/js/{plone-volto-components-manage-Widgets-DatetimeWidget.c6a47163.chunk.js → plone-volto-components-manage-Widgets-DatetimeWidget.843e0db1.chunk.js} +2 -2
  9. package/dist/public/static/js/{plone-volto-components-theme-View-EventView.d0a7e38a.chunk.js → plone-volto-components-theme-View-EventView.8826e9d6.chunk.js} +2 -2
  10. package/dist/public/static/js/{react-select.6ac1d612.chunk.js → react-select.c8927c3b.chunk.js} +2 -2
  11. package/dist/public/static/js/{runtime~client.99af7cc8.js → runtime~client.21bd3824.js} +2 -2
  12. package/dist/server.js +1 -1
  13. package/package.json +1 -1
  14. package/src/actions/language/language.js +5 -8
  15. package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +5 -13
  16. package/src/components/manage/Blocks/Image/View.jsx +9 -20
  17. package/src/components/manage/Blocks/Image/View.test.jsx +27 -7
  18. package/src/components/manage/Blocks/LeadImage/View.jsx +9 -24
  19. package/src/components/manage/Sidebar/Sidebar.jsx +2 -9
  20. package/src/components/manage/Toolbar/Toolbar.jsx +2 -7
  21. package/src/components/manage/UniversalLink/UniversalLink.jsx +9 -1
  22. package/src/components/manage/Widgets/ArrayWidget.jsx +32 -0
  23. package/src/components/manage/Widgets/UrlWidget.jsx +4 -9
  24. package/src/components/theme/Footer/Footer.jsx +11 -10
  25. package/src/components/theme/Logo/Logo.jsx +4 -5
  26. package/src/components/theme/Search/Search.jsx +6 -6
  27. package/src/components/theme/View/AlbumView.jsx +19 -17
  28. package/src/components/theme/View/LinkView.jsx +5 -38
  29. package/src/components/theme/View/LinkView.test.jsx +26 -10
  30. package/src/components/theme/View/ListingView.jsx +9 -8
  31. package/src/components/theme/View/SummaryView.jsx +13 -12
  32. package/src/components/theme/View/TabularView.jsx +4 -4
  33. package/src/helpers/AuthToken/AuthToken.js +8 -4
  34. package/src/helpers/AuthToken/AuthToken.test.js +1 -0
  35. package/src/helpers/Cookies/cookies.js +24 -0
  36. package/src/helpers/Url/Url.js +28 -0
  37. package/src/helpers/index.js +1 -0
  38. package/src/middleware/api.js +8 -5
  39. package/theme/themes/pastanaga/extras/main.less +1 -0
  40. package/theme/themes/pastanaga/extras/views.less +5 -0
  41. package/dist/public/static/js/client.d1eef743.chunk.js +0 -2
@@ -1,20 +1,36 @@
1
1
  import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
+ import { Provider } from 'react-intl-redux';
4
+ import configureStore from 'redux-mock-store';
3
5
  import { MemoryRouter } from 'react-router-dom';
4
6
  import LinkView from './LinkView';
5
7
 
8
+ const mockStore = configureStore();
9
+
10
+ const store = mockStore({
11
+ userSession: {
12
+ token: null,
13
+ },
14
+ intl: {
15
+ locale: 'en',
16
+ messages: {},
17
+ },
18
+ });
19
+
6
20
  test('renders a link view component', () => {
7
21
  const component = renderer.create(
8
- <MemoryRouter>
9
- <LinkView
10
- token="1234"
11
- content={{
12
- title: 'Hello World!',
13
- description: 'Hi',
14
- remoteUrl: '/news',
15
- }}
16
- />
17
- </MemoryRouter>,
22
+ <Provider store={store}>
23
+ <MemoryRouter>
24
+ <LinkView
25
+ token="1234"
26
+ content={{
27
+ title: 'Hello World!',
28
+ description: 'Hi',
29
+ remoteUrl: '/news',
30
+ }}
31
+ />
32
+ </MemoryRouter>
33
+ </Provider>,
18
34
  );
19
35
  const json = component.toJSON();
20
36
  expect(json).toMatchSnapshot();
@@ -5,8 +5,8 @@
5
5
 
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { Link } from 'react-router-dom';
9
- import { Segment, Container, Image } from 'semantic-ui-react';
8
+ import { Segment, Container } from 'semantic-ui-react';
9
+ import { UniversalLink, PreviewImage } from '@plone/volto/components';
10
10
 
11
11
  /**
12
12
  * List view component class.
@@ -21,17 +21,18 @@ const ListingView = ({ content }) => (
21
21
  <Segment key={item.url} className="listing-item">
22
22
  <Container>
23
23
  <h2>
24
- <Link to={item.url} title={item['@type']}>
24
+ <UniversalLink item={item} title={item['@type']}>
25
25
  {item.title}
26
- </Link>
26
+ </UniversalLink>
27
27
  </h2>
28
28
  {item.description && <p>{item.description}</p>}
29
29
  </Container>
30
- {item.image && (
31
- <Image
32
- size="small"
30
+ {item.image_field && (
31
+ <PreviewImage
32
+ item={item}
33
+ size="thumb"
33
34
  alt={item.image_caption ? item.image_caption : item.title}
34
- src={item.image.scales.thumb.download}
35
+ className="ui image"
35
36
  />
36
37
  )}
37
38
  </Segment>
@@ -5,9 +5,10 @@
5
5
 
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { Link } from 'react-router-dom';
9
- import { Container, Image } from 'semantic-ui-react';
8
+ import { UniversalLink } from '@plone/volto/components';
9
+ import { Container } from 'semantic-ui-react';
10
10
  import { FormattedMessage } from 'react-intl';
11
+ import PreviewImage from '../PreviewImage/PreviewImage';
11
12
 
12
13
  /**
13
14
  * Summary view component class.
@@ -16,7 +17,7 @@ import { FormattedMessage } from 'react-intl';
16
17
  * @returns {string} Markup of the component.
17
18
  */
18
19
  const SummaryView = ({ content }) => (
19
- <Container className="view-wrapper">
20
+ <Container className="view-wrapper summary-view">
20
21
  <article id="content">
21
22
  <header>
22
23
  <h1 className="documentFirstHeading">{content.title}</h1>
@@ -28,23 +29,23 @@ const SummaryView = ({ content }) => (
28
29
  {content.items.map((item) => (
29
30
  <article key={item.url}>
30
31
  <h2>
31
- <Link to={item.url} title={item['@type']}>
32
+ <UniversalLink item={item} title={item['@type']}>
32
33
  {item.title}
33
- </Link>
34
+ </UniversalLink>
34
35
  </h2>
35
- {item.image && (
36
- <Image
37
- clearing
38
- floated="right"
36
+ {item.image_field && (
37
+ <PreviewImage
38
+ item={item}
39
39
  alt={item.image_caption ? item.image_caption : item.title}
40
- src={item.image.scales.thumb.download}
40
+ size="thumb"
41
+ className="ui image floated right clear"
41
42
  />
42
43
  )}
43
44
  {item.description && <p>{item.description}</p>}
44
45
  <p>
45
- <Link to={item.url}>
46
+ <UniversalLink item={item}>
46
47
  <FormattedMessage id="Read More…" defaultMessage="Read More…" />
47
- </Link>
48
+ </UniversalLink>
48
49
  </p>
49
50
  </article>
50
51
  ))}
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { Link } from 'react-router-dom';
8
+ import { UniversalLink } from '@plone/volto/components';
9
9
  import { Container, Table } from 'semantic-ui-react';
10
10
  import { FormattedMessage } from 'react-intl';
11
11
 
@@ -49,13 +49,13 @@ const TabularView = ({ content }) => (
49
49
  {content.items.map((item) => (
50
50
  <Table.Row key={item.url}>
51
51
  <Table.Cell>
52
- <Link
53
- to={item.url}
52
+ <UniversalLink
53
+ item={item}
54
54
  className="summary url"
55
55
  title={item['@type']}
56
56
  >
57
57
  {item.title}
58
- </Link>
58
+ </UniversalLink>
59
59
  </Table.Cell>
60
60
  <Table.Cell>{item.description}</Table.Cell>
61
61
  <Table.Cell>{item['@type']}</Table.Cell>
@@ -7,6 +7,7 @@ import Cookies from 'universal-cookie';
7
7
  import jwtDecode from 'jwt-decode';
8
8
 
9
9
  import { loginRenew } from '@plone/volto/actions';
10
+ import { getCookieOptions } from '@plone/volto/helpers';
10
11
  import { push } from 'connected-react-router';
11
12
 
12
13
  /**
@@ -62,10 +63,13 @@ export function persistAuthToken(store, req) {
62
63
  }
63
64
  } else {
64
65
  if (previousValue !== currentValue) {
65
- cookies.set('auth_token', currentValue, {
66
- path: '/',
67
- expires: new Date(jwtDecode(currentValue).exp * 1000),
68
- });
66
+ cookies.set(
67
+ 'auth_token',
68
+ currentValue,
69
+ getCookieOptions({
70
+ expires: new Date(jwtDecode(currentValue).exp * 1000),
71
+ }),
72
+ );
69
73
  }
70
74
  const exp =
71
75
  (jwtDecode(store.getState().userSession.token).exp * 1000 -
@@ -57,6 +57,7 @@ describe('AuthToken', () => {
57
57
  expect(cookies.set).toBeCalledWith('auth_token', token, {
58
58
  path: '/',
59
59
  expires: new Date(jwtDecode(token).exp * 1000),
60
+ secure: false,
60
61
  });
61
62
  });
62
63
 
@@ -0,0 +1,24 @@
1
+ import config from '@plone/volto/registry';
2
+
3
+ export const getCookieOptions = (options = {}) => {
4
+ const { path = '/', secure = false, ...otherOptions } = options;
5
+ let secureOption = secure;
6
+
7
+ try {
8
+ if (secureOption === undefined || secureOption === null) {
9
+ const protocol = window?.location?.protocol ?? 'http';
10
+ secureOption = protocol.startsWith('https') ? true : false;
11
+ }
12
+ } catch (e) {
13
+ //window is not defined. It's ssr and we use 'secure' option passed from param
14
+ }
15
+
16
+ return {
17
+ path: path,
18
+ expires: new Date(
19
+ new Date().getTime() + config.settings.cookieExpires * 1000,
20
+ ),
21
+ secure: secureOption,
22
+ ...otherOptions,
23
+ };
24
+ };
@@ -246,6 +246,33 @@ export function normalizeTelephone(tel) {
246
246
  return `tel:${tel}`;
247
247
  }
248
248
 
249
+ export function checkAndNormalizeUrl(url) {
250
+ let res = {
251
+ isMail: false,
252
+ isTelephone: false,
253
+ url: url,
254
+ isValid: true,
255
+ };
256
+ if (URLUtils.isMail(URLUtils.normaliseMail(url))) {
257
+ //Mail
258
+ res.isMail = true;
259
+ res.url = URLUtils.normaliseMail(url);
260
+ } else if (URLUtils.isTelephone(url)) {
261
+ //Phone
262
+ res.isTelephone = true;
263
+ res.url = URLUtils.normalizeTelephone(url);
264
+ } else {
265
+ //url
266
+ if (!res.url.startsWith('/') && !res.url.startsWith('#')) {
267
+ res.url = URLUtils.normalizeUrl(url);
268
+ if (!URLUtils.isUrl(res.url)) {
269
+ res.isValid = false;
270
+ }
271
+ }
272
+ }
273
+ return res;
274
+ }
275
+
249
276
  export const URLUtils = {
250
277
  normalizeTelephone,
251
278
  normaliseMail,
@@ -253,4 +280,5 @@ export const URLUtils = {
253
280
  isTelephone,
254
281
  isMail,
255
282
  isUrl,
283
+ checkAndNormalizeUrl,
256
284
  };
@@ -96,3 +96,4 @@ export { useDetectClickOutside } from './Utils/useDetectClickOutside';
96
96
  export { usePrevious } from './Utils/usePrevious';
97
97
  export { usePagination } from './Utils/usePagination';
98
98
  export useUndoManager from './UndoManager/useUndoManager';
99
+ export { getCookieOptions } from './Cookies/cookies';
@@ -18,7 +18,7 @@ import {
18
18
  SET_APIERROR,
19
19
  } from '@plone/volto/constants/ActionTypes';
20
20
  import { changeLanguage } from '@plone/volto/actions';
21
- import { normalizeLanguageName } from '@plone/volto/helpers';
21
+ import { normalizeLanguageName, getCookieOptions } from '@plone/volto/helpers';
22
22
  let socket = null;
23
23
 
24
24
  /**
@@ -197,10 +197,13 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
197
197
  }
198
198
  if (type === LOGIN && settings.websockets) {
199
199
  const cookies = new Cookies();
200
- cookies.set('auth_token', result.token, {
201
- path: '/',
202
- expires: new Date(jwtDecode(result.token).exp * 1000),
203
- });
200
+ cookies.set(
201
+ 'auth_token',
202
+ result.token,
203
+ getCookieOptions({
204
+ expires: new Date(jwtDecode(result.token).exp * 1000),
205
+ }),
206
+ );
204
207
  api.get('/@wstoken').then((res) => {
205
208
  socket = new WebSocket(
206
209
  `${settings.apiPath.replace('http', 'ws')}/@ws?ws_token=${
@@ -574,4 +574,5 @@ body.has-toolbar-collapsed .mobile-menu {
574
574
  @import 'widgets';
575
575
  @import 'login';
576
576
  @import 'language-selector';
577
+ @import 'views';
577
578
  .loadUIOverrides();
@@ -0,0 +1,5 @@
1
+ .summary-view {
2
+ article {
3
+ margin: 2.5rem 0;
4
+ }
5
+ }