@eeacms/volto-arcgis-block 0.1.402 → 0.1.404

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 CHANGED
@@ -4,6 +4,10 @@ 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
+ ### [0.1.404](https://github.com/eea/volto-arcgis-block/compare/0.1.403...0.1.404) - 5 November 2025
8
+
9
+ ### [0.1.403](https://github.com/eea/volto-arcgis-block/compare/0.1.402...0.1.403) - 4 November 2025
10
+
7
11
  ### [0.1.402](https://github.com/eea/volto-arcgis-block/compare/0.1.401...0.1.402) - 3 November 2025
8
12
 
9
13
  #### :hammer_and_wrench: Others
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.402",
3
+ "version": "0.1.404",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -247,18 +247,22 @@ class BookmarkWidget extends React.Component {
247
247
  this.sessionBookmarks.push(bookmark);
248
248
  });
249
249
  this.Bookmarks.when(() => {
250
- document
251
- .querySelectorAll('.esri-bookmarks__bookmark')
252
- .forEach((bookmark) => {
253
- let download_button = document.createElement('button');
254
- download_button.className = 'esri-button download-bookmark-button';
255
- download_button.innerText = '⭳';
256
- download_button.bookmarkName = bookmark.innerText;
257
- download_button.addEventListener('click', (e) => {
258
- this.downloadBookmark(e.currentTarget.bookmarkName);
250
+ if (this.userID !== null) {
251
+ document.querySelector('.upload-bookmark-button').style.display =
252
+ 'flex';
253
+ document
254
+ .querySelectorAll('.esri-bookmarks__bookmark')
255
+ .forEach((bookmark) => {
256
+ let download_button = document.createElement('button');
257
+ download_button.className = 'esri-button download-bookmark-button';
258
+ download_button.innerText = '⭳';
259
+ download_button.bookmarkName = bookmark.innerText;
260
+ download_button.addEventListener('click', (e) => {
261
+ this.downloadBookmark(e.currentTarget.bookmarkName);
262
+ });
263
+ bookmark.insertBefore(download_button, bookmark.childNodes[2]);
259
264
  });
260
- bookmark.insertBefore(download_button, bookmark.childNodes[2]);
261
- });
265
+ }
262
266
  this.arcgisEventHandles.push(
263
267
  this.Bookmarks.bookmarks.on('change', (e) => {
264
268
  if (!this._isMounted) return;
@@ -804,20 +808,22 @@ class BookmarkWidget extends React.Component {
804
808
  );
805
809
  });
806
810
  });
807
- document
808
- .querySelectorAll('.esri-bookmarks__bookmark')
809
- .forEach((bookmark) => {
810
- if (bookmark.childNodes.length < 4) {
811
- let download_button = document.createElement('button');
812
- download_button.className = 'esri-button download-bookmark-button';
813
- download_button.innerText = '';
814
- download_button.bookmarkName = bookmark.innerText;
815
- download_button.addEventListener('click', (e) => {
816
- this.downloadBookmark(e.currentTarget.bookmarkName);
817
- });
818
- bookmark.insertBefore(download_button, bookmark.childNodes[2]);
819
- }
820
- });
811
+ if (this.userID !== null) {
812
+ document
813
+ .querySelectorAll('.esri-bookmarks__bookmark')
814
+ .forEach((bookmark) => {
815
+ if (bookmark.childNodes.length < 4) {
816
+ let download_button = document.createElement('button');
817
+ download_button.className = 'esri-button download-bookmark-button';
818
+ download_button.innerText = '⭳';
819
+ download_button.bookmarkName = bookmark.innerText;
820
+ download_button.addEventListener('click', (e) => {
821
+ this.downloadBookmark(e.currentTarget.bookmarkName);
822
+ });
823
+ bookmark.insertBefore(download_button, bookmark.childNodes[2]);
824
+ }
825
+ });
826
+ }
821
827
  }
822
828
  componentWillUnmount() {
823
829
  this._isMounted = false;
@@ -1187,7 +1193,8 @@ class BookmarkWidget extends React.Component {
1187
1193
  }}
1188
1194
  type="submit"
1189
1195
  >
1190
- Upload file
1196
+ <span class="esri-bookmarks__add-bookmark-icon esri-icon-plus"></span>
1197
+ Upload a bookmark
1191
1198
  </button>
1192
1199
  </div>
1193
1200
  </div>
@@ -142,7 +142,24 @@ class InfoWidget extends React.Component {
142
142
  title = this.getLayerTitle(layer);
143
143
  }
144
144
  if (layer?.isTimeSeries) {
145
- if (layer.url.toLowerCase().includes('wms')) {
145
+ if (
146
+ !!layer.ViewService &&
147
+ ['/ogc/', '/cdse/'].some((s) =>
148
+ layer.ViewService.toLowerCase().includes(s),
149
+ )
150
+ ) {
151
+ layerTypes.push({
152
+ isTimeSeries: true,
153
+ type: 'wmts',
154
+ title: title,
155
+ fields: layer.fields,
156
+ });
157
+ promises.push(
158
+ this.cdseCapabilities(layer.ViewService, layer).then((xml) =>
159
+ this.identifyCDSE(xml, layer),
160
+ ),
161
+ );
162
+ } else if (layer.url.toLowerCase().includes('wms')) {
146
163
  layerTypes.push({
147
164
  isTimeSeries: true,
148
165
  type: 'wms',
@@ -293,6 +310,15 @@ class InfoWidget extends React.Component {
293
310
  };
294
311
  break;
295
312
  case 'wmts':
313
+ if (
314
+ layers[index]?.ViewService &&
315
+ layers[index].ViewService.toLowerCase().includes(
316
+ 'cdse',
317
+ )
318
+ ) {
319
+ properties = data;
320
+ }
321
+ properties = data;
296
322
  this.infoData[index] = {
297
323
  title: layer.title,
298
324
  data: properties,
@@ -444,7 +470,9 @@ class InfoWidget extends React.Component {
444
470
 
445
471
  getLayerTitle(layer) {
446
472
  let title;
447
- if (layer.url.toLowerCase().includes('wmts')) {
473
+ if (layer.ViewService && layer.ViewService.toLowerCase().includes('cdse')) {
474
+ title = layer.title;
475
+ } else if (layer.url.toLowerCase().includes('wmts')) {
448
476
  // CLMS-1105
449
477
  title = layer._wmtsTitle;
450
478
  } else if (layer.url.toLowerCase().toLowerCase().endsWith('mapserver')) {
@@ -562,6 +590,109 @@ class InfoWidget extends React.Component {
562
590
  });
563
591
  }
564
592
 
593
+ async cdseCapabilities(url, layer) {
594
+ if (!url) return {};
595
+ try {
596
+ const res = await fetch(url);
597
+ const text = await res.text();
598
+ let parser = new DOMParser();
599
+ let xml = parser.parseFromString(text, 'text/html');
600
+ return xml;
601
+ } catch (e) {
602
+ return {};
603
+ }
604
+ }
605
+
606
+ identifyCDSE(xml, layer) {
607
+ let values = { timeFields: {}, data: {}, variables: {}, tableData: {} };
608
+ if (!xml || !xml.querySelector) {
609
+ values.timeFields['start'] = 'time';
610
+ values.variables = { options: ['value'], selected: 'value' };
611
+ values.tableData['fields'] = ['time', 'value'];
612
+ values.timeFields['values'] = [];
613
+ values.data['outFields'] = 'value';
614
+ values.data['values'] = [];
615
+ values.tableData['values'] = [];
616
+ return values;
617
+ }
618
+ let layerId = this.getLayerName(layer);
619
+ let layers = Array.from(xml.querySelectorAll('Layer'));
620
+ let lyr =
621
+ layers.find((l) => {
622
+ let id =
623
+ l.querySelector('ows\\:Identifier') || l.querySelector('Identifier');
624
+ return id && id.textContent === layerId;
625
+ }) || layers[0];
626
+ let timeValues = [];
627
+ if (lyr) {
628
+ let dimNodes = Array.from(lyr.querySelectorAll('Dimension'));
629
+ let timeDim =
630
+ dimNodes.find((d) => {
631
+ let n = d.getAttribute('name') || d.getAttribute('identifier') || '';
632
+ return n.toLowerCase() === 'time';
633
+ }) ||
634
+ dimNodes.find((d) => {
635
+ let idn =
636
+ d.querySelector('ows\\:Identifier') ||
637
+ d.querySelector('Identifier');
638
+ return idn && idn.textContent.toLowerCase() === 'time';
639
+ });
640
+ if (timeDim) {
641
+ let valNodes = Array.from(timeDim.querySelectorAll('Value'));
642
+ if (valNodes.length) {
643
+ timeValues = valNodes
644
+ .map((v) => v.textContent.trim())
645
+ .filter((t) => t);
646
+ } else {
647
+ let txt = (timeDim.textContent || '').trim();
648
+ if (txt) {
649
+ if (txt.includes(',')) {
650
+ timeValues = txt.split(',').map((s) => s.trim());
651
+ } else if (txt.includes('/')) {
652
+ timeValues = this.expandTimeRange(txt);
653
+ }
654
+ }
655
+ let def = timeDim.getAttribute('default') || '';
656
+ if (!timeValues.length && def) timeValues = [def];
657
+ }
658
+ }
659
+ }
660
+ values.timeFields['start'] = 'time';
661
+ values.variables = { options: ['value'], selected: 'value' };
662
+ values.tableData['fields'] = ['time', 'value'];
663
+ values.timeFields['values'] = timeValues.map((t) => {
664
+ let obj = {};
665
+ obj['time'] = t;
666
+ return obj;
667
+ });
668
+ values.data['outFields'] = 'value';
669
+ values.data['values'] = [];
670
+ values.tableData['values'] = timeValues.map((t) => {
671
+ return [
672
+ ['time', t],
673
+ ['value', ''],
674
+ ];
675
+ });
676
+ return values;
677
+ }
678
+
679
+ expandTimeRange(range) {
680
+ let parts = range.split('/');
681
+ if (parts.length !== 3) return parts.filter((p) => p);
682
+ let start = new Date(parts[0]);
683
+ let end = new Date(parts[1]);
684
+ let step = parts[2];
685
+ let out = [];
686
+ if (step === 'P1D') {
687
+ for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
688
+ out.push(new Date(d).toISOString().split('T')[0]);
689
+ }
690
+ return out;
691
+ } else {
692
+ return [parts[0], parts[1]];
693
+ }
694
+ }
695
+
565
696
  parseCapabilities(xml, tag) {
566
697
  let result = xml.getElementsByTagName(tag);
567
698
 
@@ -289,13 +289,16 @@
289
289
  color: white !important;
290
290
  }
291
291
 
292
- .upload-bookmark-button {
292
+ button.upload-bookmark-button {
293
+ display: none;
293
294
  width: 16rem !important;
294
295
  justify-content: start !important;
296
+ padding-left: 3px;
295
297
  border-color: #a0b128 !important;
296
298
  margin-left: 0.65rem;
297
299
  background-color: white !important;
298
300
  color: #a0b128 !important;
301
+ font-size: 12px !important;
299
302
  }
300
303
 
301
304
  .upload-bookmark-button:hover {