@eeacms/volto-embed 8.0.0 → 9.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.
@@ -1,14 +1,24 @@
1
1
  import React, { useEffect, useMemo } from 'react';
2
2
  import { connect } from 'react-redux';
3
3
  import { Message } from 'semantic-ui-react';
4
+ import { getContent } from '@plone/volto/actions';
4
5
  import { flattenToAppURL } from '@plone/volto/helpers';
5
- import Map from '@eeacms/volto-embed/Map/Map';
6
+ import EmbedMap from '@eeacms/volto-embed/EmbedMap/EmbedMap';
7
+ import { pickMetadata } from '@eeacms/volto-embed/helpers';
6
8
 
7
- import { getContent } from '@plone/volto/actions';
9
+ function getMaps(props) {
10
+ const content = props.mapsContent || {};
11
+ const maps = content.maps || props.data?.maps || {};
12
+ return {
13
+ ...pickMetadata(content),
14
+ ...maps,
15
+ };
16
+ }
8
17
 
9
18
  function View(props) {
19
+ const { id, getContent, mode } = props;
10
20
  const {
11
- url,
21
+ useVisibilitySensor = true,
12
22
  with_notes = true,
13
23
  with_sources = true,
14
24
  with_more_info = true,
@@ -16,32 +26,16 @@ function View(props) {
16
26
  with_enlarge = true,
17
27
  } = props.data;
18
28
 
19
- const maps = useMemo(() => {
20
- if (props.data.maps) {
21
- return props.data.maps;
22
- }
23
- if (props.mapsContent?.maps) {
24
- return {
25
- ...props.mapsContent.maps,
26
- '@id': props.mapsContent['@id'],
27
- title: props.mapsContent['title'],
28
- publisher: props.mapsContent['publisher'],
29
- geo_coverage: props.mapsContent['geo_coverage'],
30
- temporal_coverage: props.mapsContent['temporal_coverage'],
31
- other_organisations: props.mapsContent['other_organisations'],
32
- data_provenance: props.mapsContent['data_provenance'],
33
- figure_note: props.mapsContent['figure_note'],
34
- };
35
- }
36
- return undefined;
37
- }, [props.data.maps, props.mapsContent]);
29
+ const url = flattenToAppURL(props.data.url || '');
30
+
31
+ const maps = useMemo(() => getMaps(props), [props]);
38
32
 
39
33
  useEffect(() => {
40
- if (props.data.url && !props.data.maps) {
41
- props.getContent(flattenToAppURL(props.data.url), null, props.id);
34
+ const mapsId = maps['@id'] ? flattenToAppURL(maps['@id']) : undefined;
35
+ if (mode === 'edit' && url && url !== mapsId) {
36
+ getContent(url, null, id);
42
37
  }
43
- /* eslint-disable-next-line */
44
- }, [props.data.url]);
38
+ }, [id, getContent, mode, url, maps]);
45
39
 
46
40
  if (props.mode === 'edit' && !url) {
47
41
  return <Message>Please select a map from block editor.</Message>;
@@ -53,9 +47,10 @@ function View(props) {
53
47
 
54
48
  return (
55
49
  <div className="embed-map">
56
- <Map
50
+ <EmbedMap
57
51
  data={{
58
52
  ...maps,
53
+ useVisibilitySensor,
59
54
  with_notes,
60
55
  with_sources,
61
56
  with_more_info,
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import View from './View';
8
+ import installEmbedMaps from '.';
9
+
10
+ installEmbedMaps(config);
11
+
12
+ const mockStore = configureStore();
13
+
14
+ jest.mock('@plone/volto/components', () => ({
15
+ __esModule: true,
16
+ UniversalLink: ({ children, href }) => {
17
+ return <a href={href}>{children}</a>;
18
+ },
19
+ }));
20
+
21
+ test('renders a view embed map block component', () => {
22
+ const store = mockStore({
23
+ intl: {
24
+ locale: 'en',
25
+ messages: {},
26
+ },
27
+ content: {
28
+ create: {},
29
+ },
30
+ connected_data_parameters: {},
31
+ });
32
+ const component = renderer.create(
33
+ <Provider store={store}>
34
+ <View
35
+ id="my-map"
36
+ data={{
37
+ '@type': 'embed_maps',
38
+ with_notes: false,
39
+ with_sources: false,
40
+ with_more_info: true,
41
+ with_share: true,
42
+ with_enlarge: true,
43
+ url: '/path/to/map',
44
+ maps: {
45
+ '@id': '/path/to/map',
46
+ title: 'My map',
47
+ url:
48
+ 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3027.7835278268726!2d14.38842915203974!3d40.634655679238854!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x133b994881d943cb%3A0x6ab93db57d3272f0!2sHotel+Mediterraneo+Sorrento!5e0!3m2!1sen!2ses!4v1550168740166',
49
+ },
50
+ dataprotection: {
51
+ enabled: false,
52
+ },
53
+ useVisibilitySensor: false,
54
+ }}
55
+ />
56
+ </Provider>,
57
+ );
58
+ const json = component.toJSON();
59
+ expect(json).toMatchSnapshot();
60
+ });
@@ -3,10 +3,10 @@ import EmbedView from './View';
3
3
 
4
4
  import sliderSVG from '@plone/volto/icons/slider.svg';
5
5
 
6
- const embedConfig = (config) => {
6
+ const applyConfig = (config) => {
7
7
  config.blocks.blocksConfig.embed_maps = {
8
8
  id: 'embed_maps',
9
- title: 'Embed Map',
9
+ title: 'Embed interactive Map',
10
10
  icon: sliderSVG,
11
11
  group: 'common',
12
12
  edit: EmbedMap,
@@ -19,4 +19,4 @@ const embedConfig = (config) => {
19
19
  return config;
20
20
  };
21
21
 
22
- export default embedConfig;
22
+ export default applyConfig;
@@ -229,6 +229,7 @@ class Edit extends Component {
229
229
  <PrivacyProtection
230
230
  data={this.props.data}
231
231
  editable={this.props.editable}
232
+ useVisibilitySensor={this.props.data.useVisibilitySensor ?? true}
232
233
  >
233
234
  <iframe
234
235
  title={this.props.intl.formatMessage(
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import Edit from './Edit';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ jest.mock('@plone/volto/components', () => ({
12
+ __esModule: true,
13
+ SidebarPortal: jest.requireActual(
14
+ '@plone/volto/components/manage/Sidebar/SidebarPortal',
15
+ ).default,
16
+ UniversalLink: ({ children, href }) => {
17
+ return <a href={href}>{children}</a>;
18
+ },
19
+ }));
20
+
21
+ const store = mockStore({
22
+ intl: {
23
+ locale: 'en',
24
+ messages: {},
25
+ },
26
+ content: {
27
+ create: {},
28
+ },
29
+ connected_data_parameters: {},
30
+ });
31
+
32
+ config.blocks.blocksConfig = {
33
+ ...config.blocks.blocksConfig,
34
+ maps: {
35
+ id: 'maps',
36
+ title: 'Maps',
37
+ group: 'media',
38
+ extensions: {},
39
+ variations: [],
40
+ restricted: false,
41
+ mostUsed: true,
42
+ sidebarTab: 1,
43
+ security: {
44
+ addPermission: [],
45
+ view: [],
46
+ },
47
+ },
48
+ };
49
+
50
+ test('renders an edit map block component', () => {
51
+ const component = renderer.create(
52
+ <Provider store={store}>
53
+ <Edit
54
+ data={{
55
+ '@type': 'maps',
56
+ url:
57
+ 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3027.7835278268726!2d14.38842915203974!3d40.634655679238854!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x133b994881d943cb%3A0x6ab93db57d3272f0!2sHotel+Mediterraneo+Sorrento!5e0!3m2!1sen!2ses!4v1550168740166',
58
+ dataprotection: {
59
+ enabled: false,
60
+ },
61
+ useVisibilitySensor: false,
62
+ }}
63
+ pathname="/news"
64
+ selected={false}
65
+ block="1234"
66
+ index={1}
67
+ onChangeBlock={() => {}}
68
+ onSelectBlock={() => {}}
69
+ onDeleteBlock={() => {}}
70
+ onFocusPreviousBlock={() => {}}
71
+ onFocusNextBlock={() => {}}
72
+ handleKeyDown={() => {}}
73
+ content={{}}
74
+ />
75
+ </Provider>,
76
+ );
77
+ const json = component.toJSON();
78
+ expect(json).toMatchSnapshot();
79
+ });
@@ -40,7 +40,11 @@ const View = ({ data, intl, id }) => {
40
40
  'full-width': data.align === 'full',
41
41
  })}
42
42
  >
43
- <PrivacyProtection data={data} id={id}>
43
+ <PrivacyProtection
44
+ data={data}
45
+ id={id}
46
+ useVisibilitySensor={data.useVisibilitySensor}
47
+ >
44
48
  <iframe
45
49
  title={intl.formatMessage(messages.EmbededGoogleMaps)}
46
50
  src={data.url}
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import View from './View';
8
+ import installEmbedMaps from '.';
9
+
10
+ installEmbedMaps(config);
11
+
12
+ const mockStore = configureStore();
13
+
14
+ jest.mock('@plone/volto/components', () => ({
15
+ __esModule: true,
16
+ UniversalLink: ({ children, href }) => {
17
+ return <a href={href}>{children}</a>;
18
+ },
19
+ }));
20
+
21
+ config.blocks.blocksConfig = {
22
+ ...config.blocks.blocksConfig,
23
+ maps: {
24
+ id: 'maps',
25
+ title: 'Maps',
26
+ group: 'media',
27
+ extensions: {},
28
+ variations: [],
29
+ restricted: false,
30
+ mostUsed: true,
31
+ sidebarTab: 1,
32
+ security: {
33
+ addPermission: [],
34
+ view: [],
35
+ },
36
+ },
37
+ };
38
+
39
+ test('renders a view map block component', () => {
40
+ const store = mockStore({
41
+ intl: {
42
+ locale: 'en',
43
+ messages: {},
44
+ },
45
+ content: {
46
+ create: {},
47
+ },
48
+ connected_data_parameters: {},
49
+ });
50
+ const component = renderer.create(
51
+ <Provider store={store}>
52
+ <View
53
+ data={{
54
+ '@type': 'maps',
55
+ url:
56
+ 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3027.7835278268726!2d14.38842915203974!3d40.634655679238854!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x133b994881d943cb%3A0x6ab93db57d3272f0!2sHotel+Mediterraneo+Sorrento!5e0!3m2!1sen!2ses!4v1550168740166',
57
+ useVisibilitySensor: false,
58
+ dataprotection: {
59
+ enabled: false,
60
+ },
61
+ }}
62
+ />
63
+ </Provider>,
64
+ );
65
+ const json = component.toJSON();
66
+ expect(json).toMatchSnapshot();
67
+ });
@@ -21,7 +21,7 @@ const messages = defineMessages({
21
21
  },
22
22
  });
23
23
 
24
- function Map({ data, intl, id, screen }) {
24
+ function EmbedMap({ data, intl, id, screen }) {
25
25
  const el = useRef();
26
26
  const [mobile, setMobile] = useState(false);
27
27
 
@@ -37,6 +37,8 @@ function Map({ data, intl, id, screen }) {
37
37
  }
38
38
  }, [screen, mobile]);
39
39
 
40
+ if (!data.url) return null;
41
+
40
42
  return (
41
43
  <div
42
44
  ref={el}
@@ -53,7 +55,12 @@ function Map({ data, intl, id, screen }) {
53
55
  'full-width': data.align === 'full',
54
56
  })}
55
57
  >
56
- <PrivacyProtection data={data} id={id} height={data.height}>
58
+ <PrivacyProtection
59
+ data={data}
60
+ id={id}
61
+ height={data.height}
62
+ useVisibilitySensor={data.useVisibilitySensor ?? true}
63
+ >
57
64
  <iframe
58
65
  title={intl.formatMessage(messages.EmbededGoogleMaps)}
59
66
  src={data.url}
@@ -66,14 +73,16 @@ function Map({ data, intl, id, screen }) {
66
73
  </div>
67
74
  <div className={cx('visualization-toolbar', { mobile })}>
68
75
  <div className="left-col">
69
- {data.with_notes && <FigureNote note={data.figure_note || []} />}
70
- {data.with_sources && <Sources sources={data.sources} />}
76
+ {data.with_notes && <FigureNote notes={data.figure_note || []} />}
77
+ {data.with_sources && (
78
+ <Sources sources={data.data_provenance?.data} />
79
+ )}
71
80
  {data.with_more_info && <MoreInfo href={data['@id']} />}
72
81
  </div>
73
82
  <div className="right-col">
74
83
  {data.with_enlarge && (
75
84
  <Enlarge className="enlarge-embed-maps">
76
- <Map
85
+ <EmbedMap
77
86
  data={{
78
87
  ...data,
79
88
  height: '100%',
@@ -98,4 +107,4 @@ function Map({ data, intl, id, screen }) {
98
107
  export default compose(
99
108
  injectIntl,
100
109
  connect((state) => ({ screen: state.screen })),
101
- )(Map);
110
+ )(EmbedMap);
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import EmbedMap from './EmbedMap';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ jest.mock('@plone/volto/components', () => ({
12
+ __esModule: true,
13
+ UniversalLink: ({ children, href }) => {
14
+ return <a href={href}>{children}</a>;
15
+ },
16
+ }));
17
+
18
+ config.blocks.blocksConfig = {
19
+ ...config.blocks.blocksConfig,
20
+ maps: {
21
+ id: 'maps',
22
+ title: 'Maps',
23
+ group: 'media',
24
+ extensions: {},
25
+ variations: [],
26
+ restricted: false,
27
+ mostUsed: true,
28
+ sidebarTab: 1,
29
+ security: {
30
+ addPermission: [],
31
+ view: [],
32
+ },
33
+ },
34
+ };
35
+
36
+ test('renders map component', () => {
37
+ const store = mockStore({
38
+ intl: {
39
+ locale: 'en',
40
+ messages: {},
41
+ },
42
+ content: {
43
+ create: {},
44
+ },
45
+ connected_data_parameters: {},
46
+ });
47
+ const component = renderer.create(
48
+ <Provider store={store}>
49
+ <EmbedMap
50
+ id="my-map"
51
+ data={{
52
+ with_notes: false,
53
+ with_sources: false,
54
+ with_more_info: true,
55
+ with_share: true,
56
+ with_enlarge: true,
57
+ url:
58
+ 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3027.7835278268726!2d14.38842915203974!3d40.634655679238854!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x133b994881d943cb%3A0x6ab93db57d3272f0!2sHotel+Mediterraneo+Sorrento!5e0!3m2!1sen!2ses!4v1550168740166',
59
+ useVisibilitySensor: false,
60
+ }}
61
+ />
62
+ </Provider>,
63
+ );
64
+ const json = component.toJSON();
65
+ expect(json).toMatchSnapshot();
66
+ });
@@ -87,6 +87,7 @@ const PrivacyProtection = (props) => {
87
87
  intl,
88
88
  path,
89
89
  cookies,
90
+ useVisibilitySensor = true,
90
91
  } = props;
91
92
  const {
92
93
  enabled = false,
@@ -173,6 +174,7 @@ const PrivacyProtection = (props) => {
173
174
  <Placeholder.Image rectangular />
174
175
  </Placeholder>
175
176
  )}
177
+ useVisibilitySensor={useVisibilitySensor}
176
178
  >
177
179
  <div
178
180
  className={cx('privacy-protection-wrapper', className)}
@@ -38,8 +38,7 @@ export default function FigureNote({ notes = [] }) {
38
38
  <button className={cx('trigger-button', { open })}>Note</button>
39
39
  </div>
40
40
  }
41
- >
42
- <Popup.Content>{serializeText(notes)}</Popup.Content>
43
- </Popup>
41
+ content={serializeText(notes)}
42
+ />
44
43
  );
45
44
  }
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import { Enlarge, FigureNote, MoreInfo, Share, Sources } from '.';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ jest.mock('@plone/volto/components', () => ({
12
+ __esModule: true,
13
+ UniversalLink: ({ children, href }) => {
14
+ return <a href={href}>{children}</a>;
15
+ },
16
+ }));
17
+
18
+ jest.mock('@plone/volto-slate/editor/render', () => ({
19
+ __esModule: true,
20
+ serializeNodes: (nodes) => {
21
+ return nodes.map((node, index) => {
22
+ const Tag = node.type;
23
+ return (
24
+ <Tag key={`node-${index}`}>
25
+ {node.children.map((item, index) => (
26
+ <span key={`item-${index}`}>{item.text}</span>
27
+ ))}
28
+ </Tag>
29
+ );
30
+ });
31
+ },
32
+ serializeNodesToText: (nodes) => {
33
+ return nodes
34
+ .reduce((texts, node) => {
35
+ if (node.children) {
36
+ node.children.forEach((item) => {
37
+ texts.push(item.text);
38
+ });
39
+ }
40
+ return texts;
41
+ }, [])
42
+ .join('');
43
+ },
44
+ }));
45
+
46
+ config.blocks.blocksConfig = {
47
+ ...config.blocks.blocksConfig,
48
+ maps: {
49
+ id: 'maps',
50
+ title: 'Maps',
51
+ group: 'media',
52
+ extensions: {},
53
+ variations: [],
54
+ restricted: false,
55
+ mostUsed: true,
56
+ sidebarTab: 1,
57
+ security: {
58
+ addPermission: [],
59
+ view: [],
60
+ },
61
+ },
62
+ };
63
+
64
+ test('renders toolbar components', () => {
65
+ const store = mockStore({
66
+ intl: {
67
+ locale: 'en',
68
+ messages: {},
69
+ },
70
+ content: {
71
+ create: {},
72
+ },
73
+ connected_data_parameters: {},
74
+ });
75
+ const component = renderer.create(
76
+ <Provider store={store}>
77
+ <div className="visualization-toolbar">
78
+ <div className="left-col">
79
+ <FigureNote
80
+ notes={[{ type: 'p', children: [{ text: 'This is a note' }] }]}
81
+ />
82
+ <Sources sources={[]} />
83
+ <MoreInfo href={'/path/to/embeded/content'} />
84
+ </div>
85
+ <div className="right-col">
86
+ <Enlarge className="enlarge-embed-maps">
87
+ <div>Some enlarged content</div>
88
+ </Enlarge>
89
+ <Share href="/path/to/embeded/content" />
90
+ </div>
91
+ </div>
92
+ </Provider>,
93
+ );
94
+ const json = component.toJSON();
95
+ expect(json).toMatchSnapshot();
96
+ });
@@ -1,11 +1,25 @@
1
1
  import React from 'react';
2
2
  import { Container } from 'semantic-ui-react';
3
- import Map from '@eeacms/volto-embed/Map/Map';
3
+ import { hasBlocksData } from '@plone/volto/helpers';
4
+ import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
5
+ import EmbedMap from '@eeacms/volto-embed/EmbedMap/EmbedMap';
6
+ import { pickMetadata } from '@eeacms/volto-embed/helpers';
4
7
 
5
8
  const MapView = (props) => {
6
9
  return (
7
- <Container>
8
- <Map data={props.content.maps} id={props.content['@id']} />
10
+ <Container id="page-document" className="view-wrapper visualization-view">
11
+ {hasBlocksData(props.content) ? (
12
+ <RenderBlocks {...props} />
13
+ ) : (
14
+ <EmbedMap
15
+ data={{
16
+ ...(props.content.maps || {}),
17
+ ...pickMetadata(props.content),
18
+ with_share: true,
19
+ }}
20
+ id="map-view"
21
+ />
22
+ )}
9
23
  </Container>
10
24
  );
11
25
  };
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import config from '@plone/volto/registry';
6
+
7
+ import MapView from './MapView';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ jest.mock('@plone/volto/components', () => ({
12
+ __esModule: true,
13
+ UniversalLink: ({ children, href }) => {
14
+ return <a href={href}>{children}</a>;
15
+ },
16
+ }));
17
+
18
+ config.blocks.blocksConfig = {
19
+ ...config.blocks.blocksConfig,
20
+ maps: {
21
+ id: 'maps',
22
+ title: 'Maps',
23
+ group: 'media',
24
+ extensions: {},
25
+ variations: [],
26
+ restricted: false,
27
+ mostUsed: true,
28
+ sidebarTab: 1,
29
+ security: {
30
+ addPermission: [],
31
+ view: [],
32
+ },
33
+ },
34
+ };
35
+
36
+ test('renders map component', () => {
37
+ const store = mockStore({
38
+ intl: {
39
+ locale: 'en',
40
+ messages: {},
41
+ },
42
+ content: {
43
+ create: {},
44
+ },
45
+ connected_data_parameters: {},
46
+ });
47
+ const component = renderer.create(
48
+ <Provider store={store}>
49
+ <MapView
50
+ content={{
51
+ maps: {
52
+ '@id': '/path/to/map',
53
+ with_notes: false,
54
+ with_sources: false,
55
+ with_more_info: true,
56
+ with_share: true,
57
+ with_enlarge: true,
58
+ url:
59
+ 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3027.7835278268726!2d14.38842915203974!3d40.634655679238854!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x133b994881d943cb%3A0x6ab93db57d3272f0!2sHotel+Mediterraneo+Sorrento!5e0!3m2!1sen!2ses!4v1550168740166',
60
+ useVisibilitySensor: false,
61
+ },
62
+ }}
63
+ />
64
+ </Provider>,
65
+ );
66
+ const json = component.toJSON();
67
+ expect(json).toMatchSnapshot();
68
+ });