@eeacms/volto-embed 6.0.1 → 7.0.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.
- package/CHANGELOG.md +20 -0
- package/cypress.config.js +3 -3
- package/package.json +4 -4
- package/src/{Iframe/EditIframe.jsx → Blocks/Maps/Edit.jsx} +30 -22
- package/src/Blocks/Maps/Edit.test.jsx +119 -0
- package/src/Blocks/Maps/MapsSidebar.jsx +52 -0
- package/src/{Iframe/ViewIframe.jsx → Blocks/Maps/View.jsx} +7 -11
- package/src/Blocks/Maps/index.js +12 -0
- package/src/Blocks/Maps/schema.js +67 -0
- package/src/Blocks/index.js +5 -0
- package/src/PrivacyProtection/PrivacyProtection.jsx +3 -1
- package/src/PrivacyProtection/styles.less +0 -5
- package/src/Toolbar/Enlarge.jsx +29 -0
- package/src/Toolbar/FigureNote.jsx +45 -0
- package/src/Toolbar/MoreInfo.jsx +20 -0
- package/src/Toolbar/Share.jsx +89 -0
- package/src/Toolbar/Sources.jsx +74 -0
- package/src/Toolbar/index.jsx +5 -0
- package/src/Toolbar/styles.less +209 -0
- package/src/index.js +4 -10
- package/src/Iframe/EditIframe.test.jsx +0 -88
- package/src/Iframe/index.js +0 -4
- package/src/Iframe/schema.js +0 -39
- package/src/PrivacyProtection/PrivacyProtection.test.jsx +0 -340
- package/src/PrivacyProtection/helpers.test.js +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [7.0.0](https://github.com/eea/volto-embed/compare/6.0.1...7.0.0) - 6 November 2023
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: add toolbar + refactor [Miu Razvan - [`d439f87`](https://github.com/eea/volto-embed/commit/d439f87045cfea1554319fe05ec2a9d8b0c141cf)]
|
|
12
|
+
|
|
13
|
+
#### :house: Internal changes
|
|
14
|
+
|
|
15
|
+
- style: Automated code fix [eea-jenkins - [`c34d6f4`](https://github.com/eea/volto-embed/commit/c34d6f47fd33f728d40254a12c05fe385b27f2e9)]
|
|
16
|
+
- chore: husky, lint-staged use fixed versions [valentinab25 - [`31169f7`](https://github.com/eea/volto-embed/commit/31169f73887837463daee76d63b6516046ad49aa)]
|
|
17
|
+
|
|
18
|
+
#### :hammer_and_wrench: Others
|
|
19
|
+
|
|
20
|
+
- update tests [Miu Razvan - [`c906b79`](https://github.com/eea/volto-embed/commit/c906b79149e853f718d924871ce2e633e5e427c8)]
|
|
21
|
+
- update tests [Miu Razvan - [`11625b6`](https://github.com/eea/volto-embed/commit/11625b65846388a846d1bdf7ebb2e1f8bd103c91)]
|
|
22
|
+
- Release 7.0.0 [Alin Voinea - [`cbc5c79`](https://github.com/eea/volto-embed/commit/cbc5c79f1b66daf0d599d9de5a1bc7d137bafed8)]
|
|
23
|
+
- add act in unit tests [Miu Razvan - [`ecf5b2f`](https://github.com/eea/volto-embed/commit/ecf5b2fe553d99ad6a11570d3d34852d557fbe85)]
|
|
24
|
+
- update [Miu Razvan - [`049cc14`](https://github.com/eea/volto-embed/commit/049cc140bb6ffea4eb3f1555e693e9973ef63d0e)]
|
|
25
|
+
- update [Miu Razvan - [`124acea`](https://github.com/eea/volto-embed/commit/124acea1784d25c562d3271cba295927d38de8f8)]
|
|
26
|
+
- update unit tests [Miu Razvan - [`52c3be5`](https://github.com/eea/volto-embed/commit/52c3be5b0b56ba5b17fd88e3ff99949b3636e727)]
|
|
7
27
|
### [6.0.1](https://github.com/eea/volto-embed/compare/6.0.0...6.0.1) - 12 October 2023
|
|
8
28
|
|
|
9
29
|
#### :house: Internal changes
|
package/cypress.config.js
CHANGED
|
@@ -2,12 +2,12 @@ const { defineConfig } = require('cypress');
|
|
|
2
2
|
|
|
3
3
|
module.exports = defineConfig({
|
|
4
4
|
viewportWidth: 1280,
|
|
5
|
-
defaultCommandTimeout:
|
|
5
|
+
defaultCommandTimeout: 8888,
|
|
6
6
|
chromeWebSecurity: false,
|
|
7
7
|
reporter: 'junit',
|
|
8
|
-
video:
|
|
8
|
+
video: false,
|
|
9
9
|
retries: {
|
|
10
|
-
runMode:
|
|
10
|
+
runMode: 2,
|
|
11
11
|
openMode: 0,
|
|
12
12
|
},
|
|
13
13
|
reporterOptions: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-embed",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Embed external content",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"@cypress/code-coverage": "^3.10.0",
|
|
28
28
|
"@plone/scripts": "*",
|
|
29
29
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
|
30
|
-
"husky": "
|
|
31
|
-
"lint-staged": "
|
|
30
|
+
"husky": "^8.0.3",
|
|
31
|
+
"lint-staged": "^14.0.1",
|
|
32
32
|
"md5": "^2.3.0"
|
|
33
33
|
},
|
|
34
34
|
"lint-staged": {
|
|
@@ -72,4 +72,4 @@
|
|
|
72
72
|
"cypress:open": "make cypress-open",
|
|
73
73
|
"prepare": "husky install"
|
|
74
74
|
}
|
|
75
|
-
}
|
|
75
|
+
}
|
|
@@ -9,17 +9,15 @@ import PropTypes from 'prop-types';
|
|
|
9
9
|
import { Button, Input, Message } from 'semantic-ui-react';
|
|
10
10
|
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
|
11
11
|
import cx from 'classnames';
|
|
12
|
-
|
|
12
|
+
import { isEqual } from 'lodash';
|
|
13
|
+
import { withBlockExtensions } from '@plone/volto/helpers';
|
|
14
|
+
import { compose } from 'redux';
|
|
13
15
|
import { Icon, SidebarPortal } from '@plone/volto/components';
|
|
14
|
-
import InlineForm from '@plone/volto/components/manage/Form/InlineForm';
|
|
15
16
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
16
17
|
import aheadSVG from '@plone/volto/icons/ahead.svg';
|
|
17
18
|
import mapsBlockSVG from '@plone/volto/components/manage/Blocks/Maps/block-maps.svg';
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
PrivacyProtection,
|
|
21
|
-
addPrivacyProtectionToSchema,
|
|
22
|
-
} from '../PrivacyProtection';
|
|
19
|
+
import PrivacyProtection from '@eeacms/volto-embed/PrivacyProtection/PrivacyProtection';
|
|
20
|
+
import MapsSidebar from './MapsSidebar';
|
|
23
21
|
|
|
24
22
|
const messages = defineMessages({
|
|
25
23
|
MapsBlockInputPlaceholder: {
|
|
@@ -90,6 +88,19 @@ class Edit extends Component {
|
|
|
90
88
|
this.onKeyDownVariantMenuForm = this.onKeyDownVariantMenuForm.bind(this);
|
|
91
89
|
}
|
|
92
90
|
|
|
91
|
+
/**
|
|
92
|
+
* @param {*} nextProps
|
|
93
|
+
* @returns {boolean}
|
|
94
|
+
* @memberof Edit
|
|
95
|
+
*/
|
|
96
|
+
shouldComponentUpdate(nextProps) {
|
|
97
|
+
return (
|
|
98
|
+
this.props.selected ||
|
|
99
|
+
nextProps.selected ||
|
|
100
|
+
!isEqual(this.props.data, nextProps.data)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
93
104
|
/**
|
|
94
105
|
* Backward compatibility
|
|
95
106
|
* @method componentDidMount
|
|
@@ -196,6 +207,9 @@ class Edit extends Component {
|
|
|
196
207
|
* @returns {string} Markup for the component.
|
|
197
208
|
*/
|
|
198
209
|
render() {
|
|
210
|
+
const placeholder =
|
|
211
|
+
this.props.data.placeholder ||
|
|
212
|
+
this.props.intl.formatMessage(messages.MapsBlockInputPlaceholder);
|
|
199
213
|
return (
|
|
200
214
|
<div
|
|
201
215
|
className={cx(
|
|
@@ -224,6 +238,11 @@ class Edit extends Component {
|
|
|
224
238
|
className="google-map"
|
|
225
239
|
frameBorder="0"
|
|
226
240
|
allowFullScreen
|
|
241
|
+
style={
|
|
242
|
+
this.props.data.height
|
|
243
|
+
? { height: this.props.data.height }
|
|
244
|
+
: {}
|
|
245
|
+
}
|
|
227
246
|
/>
|
|
228
247
|
</PrivacyProtection>
|
|
229
248
|
</div>
|
|
@@ -235,9 +254,7 @@ class Edit extends Component {
|
|
|
235
254
|
<Input
|
|
236
255
|
onKeyDown={this.onKeyDownVariantMenuForm}
|
|
237
256
|
onChange={this.onChangeUrl}
|
|
238
|
-
placeholder={
|
|
239
|
-
messages.MapsBlockInputPlaceholder,
|
|
240
|
-
)}
|
|
257
|
+
placeholder={placeholder}
|
|
241
258
|
value={this.state.url}
|
|
242
259
|
// Prevents propagation to the Dropzone and the opening
|
|
243
260
|
// of the upload browser dialog
|
|
@@ -287,22 +304,13 @@ class Edit extends Component {
|
|
|
287
304
|
</center>
|
|
288
305
|
</Message>
|
|
289
306
|
)}
|
|
307
|
+
{!this.props.selected && <div className="map-overlay" />}
|
|
290
308
|
<SidebarPortal selected={this.props.selected}>
|
|
291
|
-
<
|
|
292
|
-
schema={addPrivacyProtectionToSchema(schema)}
|
|
293
|
-
title={schema.title}
|
|
294
|
-
onChangeField={(id, value) => {
|
|
295
|
-
this.props.onChangeBlock(this.props.block, {
|
|
296
|
-
...this.props.data,
|
|
297
|
-
[id]: value,
|
|
298
|
-
});
|
|
299
|
-
}}
|
|
300
|
-
formData={this.props.data}
|
|
301
|
-
/>
|
|
309
|
+
<MapsSidebar {...this.props} resetSubmitUrl={this.resetSubmitUrl} />
|
|
302
310
|
</SidebarPortal>
|
|
303
311
|
</div>
|
|
304
312
|
);
|
|
305
313
|
}
|
|
306
314
|
}
|
|
307
315
|
|
|
308
|
-
export default injectIntl(Edit);
|
|
316
|
+
export default compose(injectIntl, withBlockExtensions)(Edit);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import config from '@plone/volto/registry';
|
|
4
|
+
import { render, fireEvent, screen } from '@testing-library/react';
|
|
5
|
+
import { Provider } from 'react-intl-redux';
|
|
6
|
+
import configureStore from 'redux-mock-store';
|
|
7
|
+
import Edit from './Edit';
|
|
8
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
9
|
+
|
|
10
|
+
const mockStore = configureStore();
|
|
11
|
+
|
|
12
|
+
const store = mockStore(() => ({
|
|
13
|
+
connected_data_parameters: {},
|
|
14
|
+
router: {
|
|
15
|
+
location: {
|
|
16
|
+
pathname: '',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
intl: {
|
|
20
|
+
locale: 'en',
|
|
21
|
+
messages: {},
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
config.blocks.blocksConfig = {
|
|
26
|
+
...config.blocks.blocksConfig,
|
|
27
|
+
maps: {
|
|
28
|
+
id: 'maps',
|
|
29
|
+
title: 'Maps',
|
|
30
|
+
group: 'media',
|
|
31
|
+
extensions: {},
|
|
32
|
+
variations: [],
|
|
33
|
+
restricted: false,
|
|
34
|
+
mostUsed: true,
|
|
35
|
+
sidebarTab: 1,
|
|
36
|
+
security: {
|
|
37
|
+
addPermission: [],
|
|
38
|
+
view: [],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
jest.mock(
|
|
44
|
+
'@eeacms/volto-embed/PrivacyProtection/PrivacyProtection',
|
|
45
|
+
() => ({ children }) => children,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
describe('Edit', () => {
|
|
49
|
+
it('renders without crashing', () => {
|
|
50
|
+
render(
|
|
51
|
+
<Provider store={store}>
|
|
52
|
+
<Edit
|
|
53
|
+
selected={false}
|
|
54
|
+
block="block"
|
|
55
|
+
index={1}
|
|
56
|
+
data={{
|
|
57
|
+
'@type': 'maps',
|
|
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
|
+
}}
|
|
61
|
+
pathname="/"
|
|
62
|
+
onChangeBlock={() => {}}
|
|
63
|
+
onSelectBlock={() => {}}
|
|
64
|
+
onDeleteBlock={() => {}}
|
|
65
|
+
onFocusPreviousBlock={() => {}}
|
|
66
|
+
onFocusNextBlock={() => {}}
|
|
67
|
+
handleKeyDown={() => {}}
|
|
68
|
+
/>
|
|
69
|
+
</Provider>,
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('submits url when button is clicked', async () => {
|
|
74
|
+
const url =
|
|
75
|
+
'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';
|
|
76
|
+
|
|
77
|
+
const { container, getByPlaceholderText } = render(
|
|
78
|
+
<Provider store={store}>
|
|
79
|
+
<Edit
|
|
80
|
+
selected={false}
|
|
81
|
+
block="block"
|
|
82
|
+
index={1}
|
|
83
|
+
data={{
|
|
84
|
+
'@type': 'maps',
|
|
85
|
+
dataprotection: {
|
|
86
|
+
privacy_statement: 'test',
|
|
87
|
+
},
|
|
88
|
+
}}
|
|
89
|
+
pathname="/"
|
|
90
|
+
onChangeBlock={() => {}}
|
|
91
|
+
onSelectBlock={() => {}}
|
|
92
|
+
onDeleteBlock={() => {}}
|
|
93
|
+
onFocusPreviousBlock={() => {}}
|
|
94
|
+
onFocusNextBlock={() => {}}
|
|
95
|
+
handleKeyDown={() => {}}
|
|
96
|
+
/>
|
|
97
|
+
</Provider>,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const input = getByPlaceholderText('Enter map Embed Code');
|
|
101
|
+
|
|
102
|
+
fireEvent.click(input);
|
|
103
|
+
fireEvent.change(input, { target: { value: url } });
|
|
104
|
+
// screen.debug();
|
|
105
|
+
// expect(input.value).toBe(url);
|
|
106
|
+
|
|
107
|
+
// fireEvent.click(container.querySelector('button.cancel'));
|
|
108
|
+
|
|
109
|
+
// fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
|
|
110
|
+
// fireEvent.keyDown(input, { key: 'Escape', code: 'Escape' });
|
|
111
|
+
// fireEvent.keyDown(input, { key: 'KeyA', code: 'KeyA' });
|
|
112
|
+
|
|
113
|
+
// fireEvent.change(input, { target: { value: '<iframe src="test"/>' } });
|
|
114
|
+
// fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
|
|
115
|
+
|
|
116
|
+
// const button = container.querySelector('button.ui.basic.primary.button');
|
|
117
|
+
// fireEvent.click(button);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BlockDataForm } from '@plone/volto/components';
|
|
3
|
+
import { useIntl, defineMessages } from 'react-intl';
|
|
4
|
+
import globeSVG from '@plone/volto/icons/globe.svg';
|
|
5
|
+
import { Icon } from '@plone/volto/components';
|
|
6
|
+
import { Segment } from 'semantic-ui-react';
|
|
7
|
+
import { addPrivacyProtectionToSchema } from '@eeacms/volto-embed';
|
|
8
|
+
import { MapsSchema } from './schema';
|
|
9
|
+
|
|
10
|
+
const messages = defineMessages({
|
|
11
|
+
Maps: {
|
|
12
|
+
id: 'Maps',
|
|
13
|
+
defaultMessage: 'Maps',
|
|
14
|
+
},
|
|
15
|
+
NoMaps: {
|
|
16
|
+
id: 'No map selected',
|
|
17
|
+
defaultMessage: 'No map selected',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const MapsSidebar = (props) => {
|
|
22
|
+
const { data, block, onChangeBlock } = props;
|
|
23
|
+
const intl = useIntl();
|
|
24
|
+
const schema = addPrivacyProtectionToSchema(MapsSchema({ ...props, intl }));
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
{!data.url ? (
|
|
29
|
+
<Segment className="sidebar-metadata-container" secondary>
|
|
30
|
+
{props.intl.formatMessage(messages.NoMaps)}
|
|
31
|
+
<Icon name={globeSVG} size="100px" color="#b8c6c8" />
|
|
32
|
+
</Segment>
|
|
33
|
+
) : (
|
|
34
|
+
<BlockDataForm
|
|
35
|
+
schema={schema}
|
|
36
|
+
title={intl.formatMessage(messages.Maps)}
|
|
37
|
+
onChangeField={(id, value) => {
|
|
38
|
+
onChangeBlock(block, {
|
|
39
|
+
...data,
|
|
40
|
+
[id]: value,
|
|
41
|
+
});
|
|
42
|
+
}}
|
|
43
|
+
onChangeBlock={onChangeBlock}
|
|
44
|
+
formData={data}
|
|
45
|
+
block={block}
|
|
46
|
+
/>
|
|
47
|
+
)}
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default MapsSidebar;
|
|
@@ -7,7 +7,9 @@ import React from 'react';
|
|
|
7
7
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
9
|
import cx from 'classnames';
|
|
10
|
-
import {
|
|
10
|
+
import { compose } from 'redux';
|
|
11
|
+
import { withBlockExtensions } from '@plone/volto/helpers';
|
|
12
|
+
import PrivacyProtection from '@eeacms/volto-embed/PrivacyProtection/PrivacyProtection';
|
|
11
13
|
|
|
12
14
|
const messages = defineMessages({
|
|
13
15
|
EmbededGoogleMaps: {
|
|
@@ -32,17 +34,11 @@ const View = ({ data, intl, id }) => {
|
|
|
32
34
|
},
|
|
33
35
|
data.align,
|
|
34
36
|
)}
|
|
35
|
-
style={
|
|
36
|
-
data.align === 'full'
|
|
37
|
-
? { position: 'static', height: data.height }
|
|
38
|
-
: { height: data.height }
|
|
39
|
-
}
|
|
40
37
|
>
|
|
41
38
|
<div
|
|
42
|
-
className={cx({
|
|
43
|
-
'full-width
|
|
39
|
+
className={cx('maps-inner', {
|
|
40
|
+
'full-width': data.align === 'full',
|
|
44
41
|
})}
|
|
45
|
-
style={{ height: '100%' }}
|
|
46
42
|
>
|
|
47
43
|
<PrivacyProtection data={data} id={id}>
|
|
48
44
|
<iframe
|
|
@@ -51,7 +47,7 @@ const View = ({ data, intl, id }) => {
|
|
|
51
47
|
className="google-map"
|
|
52
48
|
frameBorder="0"
|
|
53
49
|
allowFullScreen
|
|
54
|
-
style={{ height: data.height }}
|
|
50
|
+
style={data.height ? { height: data.height } : {}}
|
|
55
51
|
/>
|
|
56
52
|
</PrivacyProtection>
|
|
57
53
|
</div>
|
|
@@ -68,4 +64,4 @@ View.propTypes = {
|
|
|
68
64
|
data: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
69
65
|
};
|
|
70
66
|
|
|
71
|
-
export default injectIntl(View);
|
|
67
|
+
export default compose(injectIntl, withBlockExtensions)(View);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
|
|
3
|
+
const messages = defineMessages({
|
|
4
|
+
Maps: {
|
|
5
|
+
id: 'Maps',
|
|
6
|
+
defaultMessage: 'Maps',
|
|
7
|
+
},
|
|
8
|
+
AltText: {
|
|
9
|
+
id: 'Alt text',
|
|
10
|
+
defaultMessage: 'Alt text',
|
|
11
|
+
},
|
|
12
|
+
MapsURL: {
|
|
13
|
+
id: 'Maps URL',
|
|
14
|
+
defaultMessage: 'Maps URL',
|
|
15
|
+
},
|
|
16
|
+
Alignment: {
|
|
17
|
+
id: 'Alignment',
|
|
18
|
+
defaultMessage: 'Alignment',
|
|
19
|
+
},
|
|
20
|
+
CSSHeight: {
|
|
21
|
+
id: 'CSSHeight',
|
|
22
|
+
defineMessages: 'CSS height',
|
|
23
|
+
},
|
|
24
|
+
CSSHeightDescription: {
|
|
25
|
+
id: 'CSSHeightDescription',
|
|
26
|
+
defineMessages: 'Iframe height',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const MapsSchema = (props) => ({
|
|
31
|
+
title: props.intl.formatMessage(messages.Maps),
|
|
32
|
+
block: 'Maps',
|
|
33
|
+
fieldsets: [
|
|
34
|
+
{
|
|
35
|
+
id: 'default',
|
|
36
|
+
title: 'Default',
|
|
37
|
+
fields: ['url', 'title', 'align', 'height'],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
|
|
41
|
+
properties: {
|
|
42
|
+
url: {
|
|
43
|
+
title: props.intl.formatMessage(messages.MapsURL),
|
|
44
|
+
widget: 'url',
|
|
45
|
+
},
|
|
46
|
+
title: {
|
|
47
|
+
title: props.intl.formatMessage(messages.AltText),
|
|
48
|
+
},
|
|
49
|
+
align: {
|
|
50
|
+
title: props.intl.formatMessage(messages.Alignment),
|
|
51
|
+
widget: 'align',
|
|
52
|
+
},
|
|
53
|
+
height: {
|
|
54
|
+
title: (
|
|
55
|
+
<a
|
|
56
|
+
rel="noreferrer"
|
|
57
|
+
target="_blank"
|
|
58
|
+
href="https://developer.mozilla.org/en-US/docs/Web/CSS/height"
|
|
59
|
+
>
|
|
60
|
+
{props.intl.formatMessage(messages.CSSHeight)}
|
|
61
|
+
</a>
|
|
62
|
+
),
|
|
63
|
+
description: props.intl.formatMessage(messages.CSSHeightDescription),
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
required: [],
|
|
67
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
+
import cx from 'classnames';
|
|
2
3
|
import { compose } from 'redux';
|
|
3
4
|
import { useSelector, useDispatch } from 'react-redux';
|
|
4
5
|
import VisibilitySensor from 'react-visibility-sensor';
|
|
@@ -77,6 +78,7 @@ const CookieWatcher = (domain_key, cookies, pollingRate = 250) => {
|
|
|
77
78
|
|
|
78
79
|
const PrivacyProtection = (props) => {
|
|
79
80
|
const {
|
|
81
|
+
className,
|
|
80
82
|
children,
|
|
81
83
|
data = {},
|
|
82
84
|
id,
|
|
@@ -168,7 +170,7 @@ const PrivacyProtection = (props) => {
|
|
|
168
170
|
>
|
|
169
171
|
{visible ? (
|
|
170
172
|
<div
|
|
171
|
-
className=
|
|
173
|
+
className={cx('privacy-protection-wrapper', className)}
|
|
172
174
|
style={{
|
|
173
175
|
position: 'relative',
|
|
174
176
|
height: height && (!enabled || !show) ? `${height}px` : 'auto',
|
|
@@ -17,17 +17,12 @@
|
|
|
17
17
|
text-align: center;
|
|
18
18
|
|
|
19
19
|
.wrapped {
|
|
20
|
-
// position: absolute;
|
|
21
|
-
// top: 50%;
|
|
22
|
-
// left: 50%;
|
|
23
20
|
width: 300px;
|
|
24
21
|
padding: 1.4rem;
|
|
25
22
|
margin: 0 auto;
|
|
26
23
|
background: white;
|
|
27
24
|
border-radius: 5px;
|
|
28
25
|
opacity: 1;
|
|
29
|
-
// -ms-transform: translate(-50%, -50%);
|
|
30
|
-
// transform: translate(-50%, -50%);
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
.discreet,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Modal } from 'semantic-ui-react';
|
|
3
|
+
|
|
4
|
+
const EnlargeWidget = ({ children }) => {
|
|
5
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div className="enlarge">
|
|
9
|
+
<button className="trigger-button" onClick={() => setIsOpen(true)}>
|
|
10
|
+
<i className="ri-fullscreen-line" />
|
|
11
|
+
Enlarge
|
|
12
|
+
</button>
|
|
13
|
+
<Modal
|
|
14
|
+
open={isOpen}
|
|
15
|
+
closeIcon={
|
|
16
|
+
<span className="close icon">
|
|
17
|
+
<i class="ri-close-line" />
|
|
18
|
+
</span>
|
|
19
|
+
}
|
|
20
|
+
onClose={() => setIsOpen(false)}
|
|
21
|
+
className="enlarge-modal"
|
|
22
|
+
>
|
|
23
|
+
<Modal.Content>{children}</Modal.Content>
|
|
24
|
+
</Modal>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default EnlargeWidget;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Popup } from 'semantic-ui-react';
|
|
3
|
+
import { isArray, isString } from 'lodash';
|
|
4
|
+
import cx from 'classnames';
|
|
5
|
+
import {
|
|
6
|
+
serializeNodes,
|
|
7
|
+
serializeNodesToText,
|
|
8
|
+
} from '@plone/volto-slate/editor/render';
|
|
9
|
+
|
|
10
|
+
export const serializeText = (notes) => {
|
|
11
|
+
const content = isArray(notes) ? serializeNodes(notes) : notes;
|
|
12
|
+
const text = isArray(notes)
|
|
13
|
+
? serializeNodesToText(notes)
|
|
14
|
+
: isString(notes)
|
|
15
|
+
? notes
|
|
16
|
+
: '';
|
|
17
|
+
if (!text) return <p>There are no notes set for this visualization</p>;
|
|
18
|
+
return content;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function FigureNote({ notes = [] }) {
|
|
22
|
+
const [open, setOpen] = React.useState(false);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Popup
|
|
26
|
+
popper={{ id: 'vis-toolbar-popup', className: 'figure-note-popup' }}
|
|
27
|
+
position="bottom left"
|
|
28
|
+
on="click"
|
|
29
|
+
open={open}
|
|
30
|
+
onClose={() => {
|
|
31
|
+
setOpen(false);
|
|
32
|
+
}}
|
|
33
|
+
onOpen={() => {
|
|
34
|
+
setOpen(true);
|
|
35
|
+
}}
|
|
36
|
+
trigger={
|
|
37
|
+
<div className="figure-note">
|
|
38
|
+
<button className={cx('trigger-button', { open })}>Note</button>
|
|
39
|
+
</div>
|
|
40
|
+
}
|
|
41
|
+
>
|
|
42
|
+
<Popup.Content>{serializeText(notes)}</Popup.Content>
|
|
43
|
+
</Popup>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { UniversalLink } from '@plone/volto/components';
|
|
3
|
+
|
|
4
|
+
const Link = ({ children, ...props }) => {
|
|
5
|
+
if (props.href) {
|
|
6
|
+
return <UniversalLink {...props}>{children}</UniversalLink>;
|
|
7
|
+
}
|
|
8
|
+
return <span {...props}>{children}</span>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default function MoreInfo({ href }) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="more-info">
|
|
14
|
+
<Link href={href} className="trigger-button">
|
|
15
|
+
<span>More info</span>
|
|
16
|
+
<i class="ri-external-link-line" />
|
|
17
|
+
</Link>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|