@eeacms/volto-eea-map 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.coverage.babel.config.js +9 -0
- package/.project.eslintrc.js +46 -0
- package/.release-it.json +17 -0
- package/CHANGELOG.md +40 -0
- package/DEVELOP.md +51 -0
- package/LICENSE.md +9 -0
- package/README.md +103 -0
- package/RELEASE.md +74 -0
- package/babel.config.js +17 -0
- package/bootstrap +41 -0
- package/cypress.json +17 -0
- package/jest-addon.config.js +36 -0
- package/locales/volto.pot +0 -0
- package/package.json +44 -0
- package/src/components/Blocks/EEAMap/Edit.jsx +37 -0
- package/src/components/Blocks/EEAMap/Schema.js +32 -0
- package/src/components/Blocks/EEAMap/View.jsx +20 -0
- package/src/components/Blocks/EEAMap/components/TextView.jsx +7 -0
- package/src/components/Blocks/EEAMap/components/Webmap.jsx +194 -0
- package/src/components/Blocks/EEAMap/components/widgets/ExtraViews.jsx +53 -0
- package/src/components/Blocks/EEAMap/components/widgets/LayerSelectWidget.jsx +113 -0
- package/src/components/Blocks/EEAMap/components/widgets/LayersPanel.jsx +56 -0
- package/src/components/Blocks/EEAMap/components/widgets/LegendWidget.jsx +63 -0
- package/src/components/Blocks/EEAMap/components/widgets/MapEditorWidget.jsx +81 -0
- package/src/components/Blocks/EEAMap/components/widgets/ObjectTypesWidget.jsx +53 -0
- package/src/components/Blocks/EEAMap/components/widgets/panelsSchema.js +190 -0
- package/src/components/Blocks/EEAMap/constants.js +29 -0
- package/src/components/Blocks/EEAMap/styles/map.css +22 -0
- package/src/components/Blocks/EEAMap/utils.js +17 -0
- package/src/components/index.js +4 -0
- package/src/index.js +41 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { loadModules } from 'esri-loader';
|
|
4
|
+
|
|
5
|
+
const MODULES = [
|
|
6
|
+
'esri/Map',
|
|
7
|
+
'esri/views/MapView',
|
|
8
|
+
'esri/layers/FeatureLayer',
|
|
9
|
+
'esri/layers/MapImageLayer',
|
|
10
|
+
'esri/layers/GroupLayer',
|
|
11
|
+
'esri/widgets/Legend',
|
|
12
|
+
'esri/widgets/Expand',
|
|
13
|
+
'esri/widgets/Print',
|
|
14
|
+
'esri/widgets/Zoom',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const Webmap = (props) => {
|
|
18
|
+
const { data = {}, editMode, height } = props;
|
|
19
|
+
const {
|
|
20
|
+
base = {},
|
|
21
|
+
layers = {},
|
|
22
|
+
id,
|
|
23
|
+
legend = {},
|
|
24
|
+
print = {},
|
|
25
|
+
zoom = {},
|
|
26
|
+
} = data;
|
|
27
|
+
|
|
28
|
+
const { base_layer = '' } = base;
|
|
29
|
+
|
|
30
|
+
const map_layers =
|
|
31
|
+
layers &&
|
|
32
|
+
layers.map_layers &&
|
|
33
|
+
layers.map_layers
|
|
34
|
+
.filter(({ map_layer }) => map_layer)
|
|
35
|
+
.map((l, i) => l.map_layer);
|
|
36
|
+
const options = {
|
|
37
|
+
css: true,
|
|
38
|
+
};
|
|
39
|
+
const mapRef = React.useRef();
|
|
40
|
+
const [modules, setModules] = React.useState({});
|
|
41
|
+
const modules_loaded = React.useRef(false);
|
|
42
|
+
|
|
43
|
+
React.useEffect(() => {
|
|
44
|
+
if (!modules_loaded.current) {
|
|
45
|
+
modules_loaded.current = true;
|
|
46
|
+
loadModules(MODULES, options).then((modules) => {
|
|
47
|
+
const [
|
|
48
|
+
Map,
|
|
49
|
+
MapView,
|
|
50
|
+
FeatureLayer,
|
|
51
|
+
MapImageLayer,
|
|
52
|
+
GroupLayer,
|
|
53
|
+
Legend,
|
|
54
|
+
Expand,
|
|
55
|
+
Print,
|
|
56
|
+
Zoom,
|
|
57
|
+
] = modules;
|
|
58
|
+
setModules({
|
|
59
|
+
Map,
|
|
60
|
+
MapView,
|
|
61
|
+
FeatureLayer,
|
|
62
|
+
MapImageLayer,
|
|
63
|
+
GroupLayer,
|
|
64
|
+
Legend,
|
|
65
|
+
Expand,
|
|
66
|
+
Print,
|
|
67
|
+
Zoom,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}, [setModules, options]);
|
|
72
|
+
|
|
73
|
+
const esri = React.useMemo(() => {
|
|
74
|
+
if (Object.keys(modules).length === 0) return {};
|
|
75
|
+
const {
|
|
76
|
+
Map,
|
|
77
|
+
MapView,
|
|
78
|
+
FeatureLayer,
|
|
79
|
+
MapImageLayer,
|
|
80
|
+
GroupLayer,
|
|
81
|
+
Legend,
|
|
82
|
+
Expand,
|
|
83
|
+
Print,
|
|
84
|
+
Zoom,
|
|
85
|
+
} = modules;
|
|
86
|
+
let layers =
|
|
87
|
+
map_layers &&
|
|
88
|
+
map_layers.length > 0 &&
|
|
89
|
+
map_layers
|
|
90
|
+
.filter(({ map_service_url, layer }) => map_service_url && layer)
|
|
91
|
+
.map(({ map_service_url, layer }) => {
|
|
92
|
+
const url = `${map_service_url}/${layer}`;
|
|
93
|
+
|
|
94
|
+
let mapLayer;
|
|
95
|
+
|
|
96
|
+
//TODO: add more layers and error catch for unrecognized layer
|
|
97
|
+
switch (layer.type) {
|
|
98
|
+
case 'Raster Layer':
|
|
99
|
+
mapLayer = new MapImageLayer({
|
|
100
|
+
url: map_service_url,
|
|
101
|
+
});
|
|
102
|
+
break;
|
|
103
|
+
case 'Feature Layer':
|
|
104
|
+
mapLayer = new FeatureLayer({ url });
|
|
105
|
+
break;
|
|
106
|
+
case 'Group Layer':
|
|
107
|
+
mapLayer = new GroupLayer({ url });
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
return mapLayer;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const map = new Map({
|
|
116
|
+
basemap: base_layer || 'hybrid',
|
|
117
|
+
layers,
|
|
118
|
+
});
|
|
119
|
+
const view = new MapView({
|
|
120
|
+
container: mapRef.current,
|
|
121
|
+
map,
|
|
122
|
+
center: zoom?.long && zoom?.lat ? [zoom.long, zoom.lat] : [0, 40],
|
|
123
|
+
zoom: zoom?.zoom_level ? zoom?.zoom_level : 2,
|
|
124
|
+
ui: {
|
|
125
|
+
components: ['attribution'],
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (zoom?.show_zoom) {
|
|
130
|
+
const zoomPosition = zoom && zoom.position ? zoom.position : 'top-right';
|
|
131
|
+
const zoomWidget = new Zoom({
|
|
132
|
+
view: view,
|
|
133
|
+
});
|
|
134
|
+
view.ui.add(zoomWidget, zoomPosition);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (legend?.legend?.show_legend) {
|
|
138
|
+
const legendPosition =
|
|
139
|
+
legend && legend.legend && legend.legend.position
|
|
140
|
+
? legend.legend.position
|
|
141
|
+
: 'top-right';
|
|
142
|
+
|
|
143
|
+
const legendWidget = new Expand({
|
|
144
|
+
content: new Legend({
|
|
145
|
+
view: view,
|
|
146
|
+
style: 'classic', // other styles include 'classic'
|
|
147
|
+
}),
|
|
148
|
+
view: view,
|
|
149
|
+
expanded: false,
|
|
150
|
+
expandIconClass: 'esri-icon-legend',
|
|
151
|
+
expandTooltip: 'Legend',
|
|
152
|
+
classNames: 'some-cool-expand',
|
|
153
|
+
});
|
|
154
|
+
view.ui.add(legendWidget, legendPosition);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (print?.show_print) {
|
|
158
|
+
const printPosition =
|
|
159
|
+
print && print.position ? print.position : 'top-right';
|
|
160
|
+
const printWidget = new Expand({
|
|
161
|
+
content: new Print({
|
|
162
|
+
view: view,
|
|
163
|
+
}),
|
|
164
|
+
view: view,
|
|
165
|
+
expanded: false,
|
|
166
|
+
expandIconClass: 'esri-icon-printer',
|
|
167
|
+
expandTooltip: 'Print',
|
|
168
|
+
});
|
|
169
|
+
view.ui.add(printWidget, printPosition);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (layers && layers.length > 0) {
|
|
173
|
+
view.whenLayerView(layers[0]).then((layerView) => {
|
|
174
|
+
layerView.watch('updating', (val) => {});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return { view, map };
|
|
178
|
+
}, [modules, base_layer, map_layers]);
|
|
179
|
+
|
|
180
|
+
const currentLayerView = esri.view?.layerViews?.items?.[0];
|
|
181
|
+
return (
|
|
182
|
+
<div>
|
|
183
|
+
<div
|
|
184
|
+
style={{
|
|
185
|
+
height: height && !editMode ? `${height}px` : '500px',
|
|
186
|
+
}}
|
|
187
|
+
ref={mapRef}
|
|
188
|
+
className="esri-map"
|
|
189
|
+
></div>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export default Webmap;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from 'semantic-ui-react';
|
|
3
|
+
import { Icon } from '@plone/volto/components';
|
|
4
|
+
|
|
5
|
+
import TextView from '../TextView';
|
|
6
|
+
import LegendWidget from './LegendWidget';
|
|
7
|
+
|
|
8
|
+
import worldSVG from '@plone/volto/icons/world.svg';
|
|
9
|
+
import downloadSVG from '@plone/volto/icons/download.svg';
|
|
10
|
+
|
|
11
|
+
const ExtraViews = ({ data }) => {
|
|
12
|
+
const { map_data = {}, description, show_description } = data;
|
|
13
|
+
const { general = {} } = map_data;
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
{general.show_legend && <LegendWidget data={map_data} />}
|
|
17
|
+
{show_description && description && <TextView text={description} />}
|
|
18
|
+
{(general.show_download || general.show_viewer) && (
|
|
19
|
+
<div
|
|
20
|
+
style={{ display: 'flex', justifyContent: 'end', margin: '10px 0' }}
|
|
21
|
+
>
|
|
22
|
+
{general.show_download && (
|
|
23
|
+
<a
|
|
24
|
+
target="_blank"
|
|
25
|
+
rel="noreferrer"
|
|
26
|
+
href={`${map_data.layers.map_layers[0].map_layer.map_service_url}?f=lyr&v=9.3`}
|
|
27
|
+
>
|
|
28
|
+
<Button size="tiny">
|
|
29
|
+
<Icon name={downloadSVG} title="Download" size="25px" />
|
|
30
|
+
</Button>
|
|
31
|
+
</a>
|
|
32
|
+
)}
|
|
33
|
+
{general.show_viewer && (
|
|
34
|
+
<a
|
|
35
|
+
target="_blank"
|
|
36
|
+
rel="noreferrer"
|
|
37
|
+
href={
|
|
38
|
+
`https://www.arcgis.com/home/webmap/viewer.html?url=` +
|
|
39
|
+
`${map_data.layers.map_layers[0].map_layer.map_service_url}&source=sd`
|
|
40
|
+
}
|
|
41
|
+
>
|
|
42
|
+
<Button size="tiny">
|
|
43
|
+
<Icon name={worldSVG} title="Check Url" size="25px" />
|
|
44
|
+
</Button>
|
|
45
|
+
</a>
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default ExtraViews;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Icon } from '@plone/volto/components';
|
|
3
|
+
import { Input, Select, Button, Grid } from 'semantic-ui-react';
|
|
4
|
+
|
|
5
|
+
import checkSVG from '@plone/volto/icons/check.svg';
|
|
6
|
+
import closeSVG from '@plone/volto/icons/clear.svg';
|
|
7
|
+
|
|
8
|
+
import { fetchArcgisData } from '../../utils';
|
|
9
|
+
|
|
10
|
+
const LayerSelectWidget = (props) => {
|
|
11
|
+
const { onChange, value = {}, id } = props;
|
|
12
|
+
|
|
13
|
+
const { available_layers, map_data, map_service_url, layer } = value;
|
|
14
|
+
|
|
15
|
+
const [mapData, setMapData] = React.useState(map_data);
|
|
16
|
+
const [checkColor, setCheckColor] = React.useState('');
|
|
17
|
+
const [serviceUrlError, setServiceUrlError] = React.useState('');
|
|
18
|
+
const [serviceUrl, setServiceUrl] = React.useState(map_service_url);
|
|
19
|
+
const [selectedLayer, setSelectedLayer] = React.useState(layer);
|
|
20
|
+
const [availableLayers, setAvailableLayers] = React.useState(
|
|
21
|
+
available_layers,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const handleServiceUrlCheck = async () => {
|
|
25
|
+
// fetch url, save it, populate layers options
|
|
26
|
+
try {
|
|
27
|
+
let mapData = await fetchArcgisData(serviceUrl);
|
|
28
|
+
setCheckColor('green');
|
|
29
|
+
setMapData(mapData);
|
|
30
|
+
setServiceUrlError('');
|
|
31
|
+
if (mapData.layers && mapData.layers.length > 0) {
|
|
32
|
+
setAvailableLayers(
|
|
33
|
+
mapData.layers.map((layer, i) => {
|
|
34
|
+
return { key: layer.id, value: layer, text: layer.name };
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
onChange(id, {
|
|
39
|
+
layer: selectedLayer,
|
|
40
|
+
map_service_url: serviceUrl,
|
|
41
|
+
available_layers: availableLayers,
|
|
42
|
+
map_data: mapData,
|
|
43
|
+
});
|
|
44
|
+
} catch (e) {
|
|
45
|
+
setCheckColor('youtube');
|
|
46
|
+
setServiceUrlError({ error: e.message, status: e.status });
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleSelectLayer = (layer) => {
|
|
51
|
+
setSelectedLayer(layer);
|
|
52
|
+
onChange(id, {
|
|
53
|
+
layer,
|
|
54
|
+
map_service_url: serviceUrl,
|
|
55
|
+
available_layers: availableLayers,
|
|
56
|
+
map_data: mapData,
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
style={{
|
|
63
|
+
padding: '0 5px',
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<Grid>
|
|
67
|
+
<h4>Service URL</h4>
|
|
68
|
+
<Grid.Row>
|
|
69
|
+
<Input
|
|
70
|
+
type="text"
|
|
71
|
+
onChange={(e, { value }) => setServiceUrl(value)}
|
|
72
|
+
style={{ width: '100%' }}
|
|
73
|
+
value={serviceUrl}
|
|
74
|
+
/>
|
|
75
|
+
<Grid.Row>
|
|
76
|
+
<Button
|
|
77
|
+
style={{
|
|
78
|
+
margin: '10px 0',
|
|
79
|
+
display: 'flex',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
}}
|
|
82
|
+
color={checkColor}
|
|
83
|
+
onClick={handleServiceUrlCheck}
|
|
84
|
+
>
|
|
85
|
+
<p style={{ fontSize: '14px', margin: '0', marginRight: '5px' }}>
|
|
86
|
+
Check Url
|
|
87
|
+
</p>
|
|
88
|
+
<Icon
|
|
89
|
+
name={serviceUrlError ? closeSVG : checkSVG}
|
|
90
|
+
style={{ marginLeft: '5px' }}
|
|
91
|
+
title="Check Url"
|
|
92
|
+
size="17px"
|
|
93
|
+
/>
|
|
94
|
+
</Button>
|
|
95
|
+
</Grid.Row>
|
|
96
|
+
</Grid.Row>
|
|
97
|
+
<h4>Layer</h4>
|
|
98
|
+
<Grid.Row>
|
|
99
|
+
<Select
|
|
100
|
+
onChange={(e, { value }) => handleSelectLayer(value)}
|
|
101
|
+
options={availableLayers}
|
|
102
|
+
style={{ width: '100%' }}
|
|
103
|
+
placeholder="Select layer"
|
|
104
|
+
value={selectedLayer}
|
|
105
|
+
/>
|
|
106
|
+
</Grid.Row>
|
|
107
|
+
<Grid.Row stretched></Grid.Row>
|
|
108
|
+
</Grid>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default LayerSelectWidget;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from 'semantic-ui-react';
|
|
3
|
+
import LayerSelectWidget from './LayerSelectWidget';
|
|
4
|
+
|
|
5
|
+
const LayersPanel = ({ data, onChange, block }) => {
|
|
6
|
+
const { map_layers } = data || {};
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
if (!data.map_layers) {
|
|
10
|
+
onChange('map_data', {
|
|
11
|
+
...data,
|
|
12
|
+
map_layers: [
|
|
13
|
+
{
|
|
14
|
+
map_service_url: '',
|
|
15
|
+
layer: '',
|
|
16
|
+
available_layers: [],
|
|
17
|
+
map_data: {},
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}, [data, block, onChange]);
|
|
23
|
+
|
|
24
|
+
const handleAddLayer = () => {
|
|
25
|
+
onChange('map_data', {
|
|
26
|
+
...data,
|
|
27
|
+
map_layers: [
|
|
28
|
+
...data.map_layers,
|
|
29
|
+
{ map_service_url: '', layer: '', available_layers: [], map_data: {} },
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div>
|
|
36
|
+
{map_layers &&
|
|
37
|
+
map_layers.length > 0 &&
|
|
38
|
+
map_layers.map((layer, i) => (
|
|
39
|
+
<LayerSelectWidget
|
|
40
|
+
key={i}
|
|
41
|
+
index={i}
|
|
42
|
+
layer={layer}
|
|
43
|
+
onChange={onChange}
|
|
44
|
+
block={block}
|
|
45
|
+
data={data}
|
|
46
|
+
/>
|
|
47
|
+
))}
|
|
48
|
+
|
|
49
|
+
<Button size="tiny" onClick={handleAddLayer}>
|
|
50
|
+
Add Layer
|
|
51
|
+
</Button>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default LayersPanel;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Grid } from 'semantic-ui-react';
|
|
3
|
+
import { fetchArcgisData } from '../../utils';
|
|
4
|
+
|
|
5
|
+
const LayerLegend = ({ data }) => {
|
|
6
|
+
return (
|
|
7
|
+
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
8
|
+
{data.length > 0 &&
|
|
9
|
+
data.map((item, i) => {
|
|
10
|
+
return (
|
|
11
|
+
<span style={{ display: 'flex', alignItems: 'center' }}>
|
|
12
|
+
<img alt="alt" src={`data:image/png;base64,${item.imageData}`} />
|
|
13
|
+
<span style={{ fontSize: '13px' }}>{item.label}</span>
|
|
14
|
+
</span>
|
|
15
|
+
);
|
|
16
|
+
})}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const LegendWidget = (props) => {
|
|
22
|
+
const { data = {} } = props;
|
|
23
|
+
const { layers = {} } = data;
|
|
24
|
+
const { map_layers = [] } = layers;
|
|
25
|
+
const [legendLayers, setLegendLayers] = React.useState([]);
|
|
26
|
+
|
|
27
|
+
const activeLayer = map_layers.length > 0 ? map_layers[0]?.map_layer : '';
|
|
28
|
+
const fetchLegend = async (url) => {
|
|
29
|
+
let legendData = await fetchArcgisData(url);
|
|
30
|
+
const { layers = [] } = legendData;
|
|
31
|
+
|
|
32
|
+
setLegendLayers(layers);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
fetchLegend(activeLayer.map_service_url + '/legend');
|
|
37
|
+
}, [data, activeLayer.map_service_url]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<div style={{ margin: '10px 0' }}>
|
|
42
|
+
<Grid>
|
|
43
|
+
<Grid.Row>
|
|
44
|
+
<Grid.Column>
|
|
45
|
+
<h3>Legend:</h3>
|
|
46
|
+
{legendLayers.length > 0 &&
|
|
47
|
+
legendLayers.map((layer, index) => {
|
|
48
|
+
return (
|
|
49
|
+
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
50
|
+
<h5>{layer?.layerName}</h5>
|
|
51
|
+
<LayerLegend data={layer.legend} />
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
})}
|
|
55
|
+
</Grid.Column>
|
|
56
|
+
</Grid.Row>
|
|
57
|
+
</Grid>
|
|
58
|
+
</div>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default LegendWidget;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal, Button, Grid } from 'semantic-ui-react';
|
|
3
|
+
import Webmap from '../Webmap';
|
|
4
|
+
import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
|
|
5
|
+
|
|
6
|
+
import { panelsSchema } from './panelsSchema';
|
|
7
|
+
|
|
8
|
+
const MapEditorWidget = (props) => {
|
|
9
|
+
const [open, setOpen] = React.useState(false);
|
|
10
|
+
const { onChange = {}, block = {}, value = {}, id } = props;
|
|
11
|
+
const [intValue, setIntValue] = React.useState(value);
|
|
12
|
+
|
|
13
|
+
const dataForm = { map_data: intValue };
|
|
14
|
+
|
|
15
|
+
const handleApplyChanges = () => {
|
|
16
|
+
onChange(id, intValue);
|
|
17
|
+
setOpen(false);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const handleClose = () => {
|
|
21
|
+
setIntValue(value);
|
|
22
|
+
setOpen(false);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const handleChangeField = (id, fieldVal) => {
|
|
26
|
+
setIntValue(fieldVal);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<FormFieldWrapper {...props}>
|
|
31
|
+
<Modal
|
|
32
|
+
id="map-editor-modal"
|
|
33
|
+
style={{ width: '95% !important' }}
|
|
34
|
+
onClose={handleClose}
|
|
35
|
+
onOpen={() => setOpen(true)}
|
|
36
|
+
open={open}
|
|
37
|
+
trigger={
|
|
38
|
+
<Button size="tiny" className="map-modal-trigger-button">
|
|
39
|
+
Open Map Editor
|
|
40
|
+
</Button>
|
|
41
|
+
}
|
|
42
|
+
>
|
|
43
|
+
<Modal.Content scrolling>
|
|
44
|
+
<Grid>
|
|
45
|
+
<Grid.Row>
|
|
46
|
+
<Grid.Column width={4}>
|
|
47
|
+
<InlineForm
|
|
48
|
+
block={block}
|
|
49
|
+
title={panelsSchema.title}
|
|
50
|
+
schema={panelsSchema}
|
|
51
|
+
onChangeField={(id, value) => {
|
|
52
|
+
handleChangeField(id, value);
|
|
53
|
+
}}
|
|
54
|
+
formData={dataForm}
|
|
55
|
+
/>
|
|
56
|
+
</Grid.Column>
|
|
57
|
+
<Grid.Column width={8}>
|
|
58
|
+
<Webmap data={intValue} editMode={true} />
|
|
59
|
+
</Grid.Column>
|
|
60
|
+
</Grid.Row>
|
|
61
|
+
</Grid>
|
|
62
|
+
</Modal.Content>
|
|
63
|
+
<Modal.Actions>
|
|
64
|
+
<Grid>
|
|
65
|
+
<Grid.Row>
|
|
66
|
+
<Grid.Column width={8}></Grid.Column>
|
|
67
|
+
<Grid.Column width={4}>
|
|
68
|
+
<Button onClick={handleClose}>Close</Button>
|
|
69
|
+
<Button color="green" onClick={handleApplyChanges}>
|
|
70
|
+
Apply changes
|
|
71
|
+
</Button>
|
|
72
|
+
</Grid.Column>
|
|
73
|
+
</Grid.Row>
|
|
74
|
+
</Grid>
|
|
75
|
+
</Modal.Actions>
|
|
76
|
+
</Modal>
|
|
77
|
+
</FormFieldWrapper>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default MapEditorWidget;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Menu, Tab } from 'semantic-ui-react';
|
|
3
|
+
import { ObjectWidget } from '@plone/volto/components';
|
|
4
|
+
|
|
5
|
+
export const ObjectTypesWidget = (props) => {
|
|
6
|
+
const { schemas, value = {}, onChange, errors = {}, id } = props;
|
|
7
|
+
const objectId = id;
|
|
8
|
+
|
|
9
|
+
const defaultActiveTab = 0;
|
|
10
|
+
|
|
11
|
+
const [activeTab, setActiveTab] = React.useState(
|
|
12
|
+
defaultActiveTab > -1 ? defaultActiveTab : 0,
|
|
13
|
+
);
|
|
14
|
+
const createTab = ({ schema, id, icon }, index) => {
|
|
15
|
+
return {
|
|
16
|
+
menuItem: () => (
|
|
17
|
+
<Menu.Item
|
|
18
|
+
onClick={() => setActiveTab(index)}
|
|
19
|
+
active={activeTab === index}
|
|
20
|
+
key={id}
|
|
21
|
+
>
|
|
22
|
+
<p style={{ fontSize: '14px', fontWeight: 'bold' }}>{schema.title}</p>
|
|
23
|
+
</Menu.Item>
|
|
24
|
+
),
|
|
25
|
+
render: () => {
|
|
26
|
+
return (
|
|
27
|
+
<Tab.Pane>
|
|
28
|
+
<ObjectWidget
|
|
29
|
+
schema={schema}
|
|
30
|
+
id={id}
|
|
31
|
+
errors={errors}
|
|
32
|
+
value={value[id] || {}}
|
|
33
|
+
onChange={(schemaId, v) => {
|
|
34
|
+
onChange(objectId, { ...value, [schemaId]: v });
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
</Tab.Pane>
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Tab
|
|
45
|
+
menu={{ fluid: true, vertical: true, tabular: true }}
|
|
46
|
+
panes={schemas.map(createTab)}
|
|
47
|
+
activeIndex={activeTab}
|
|
48
|
+
grid={{ paneWidth: 8, tabWidth: 4 }}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default ObjectTypesWidget;
|