From f2c3e05955bec324b7e2a011fdde3894aa53ebd5 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Tue, 27 May 2025 12:27:16 +0200 Subject: info-modal: Fetch source copyright and mtime remotely from metadata.json. Source URL and copyright information are now defined tools' config.yml. This change exposes MVT creation time as well as source mtime to the info modal. See 052536f62d2e58f6b9b142e035c49cb033458d7f in tools for the generation logic behind metadata.json. --- main.js | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-) (limited to 'main.js') diff --git a/main.js b/main.js index 6808456..17ca1cc 100644 --- a/main.js +++ b/main.js @@ -483,10 +483,189 @@ if (window.location === window.parent.location) { btn.classList.replace('btn-dark', 'btn-light'); btn.setAttribute('aria-expanded', 'false'); backdrop.classList.remove('modal-backdrop', 'show'); + infoMetadataAccordions.forEach(function(x, idx) { + /* collapse all accordions */ + const body = x.element.parentNode.parentNode; + const name = 'info-accordion-collapse-' + idx; + if (body.id === name) { + body.classList.remove('show'); + } + if (body.parentNode !== null) { + const headers = body.parentNode.getElementsByClassName('accordion-header'); + for (let i = 0; i < headers.length; i++) { + const buttons = headers[i].getElementsByClassName('accordion-button'); + for (let j = 0; j < buttons.length; j++) { + const btn = buttons[j]; + if (btn.getAttribute('data-bs-target') === '#' + name) { + btn.setAttribute('aria-expanded', 'false'); + btn.classList.add('collapsed'); + } + } + } + } + }); }); btn.onclick = function(event) { - modal.toggle(); + infoMetadataAccordions.forEach((x) => x.element.replaceChildren()); + modal.show(); + Promise.allSettled(Object.entries(vectorLayers).map(function([grp,lyr]) { + const url = lyr.getSource().getUrls()[0]; + if (url === undefined || url.length <= 16 || url.substr(url.length - 16) !== '/{z}/{x}/{y}.pbf') { + throw new Error(`Invalid URL ${url}`); + } + return fetch(url.substr(0, url.length - 16) + '/metadata.json') + .then(function(resp0) { + if (resp0.status === 200) { + return resp0.json().then((x) => [grp,x]); + } else { + throw new Error(`${resp0.url} [${resp0.status}]`); + } + }); + })) + .then(function(rs) { + const metadata = Object.fromEntries(rs.filter(function(r) { + if (r.status === 'fulfilled') { + return true; + } else if (r.status === 'rejected') { + console.log(r.reason); + } + return false; + }).map((r) => r.value)); + + infoMetadataAccordions.forEach(function(x) { + const ul = x.element; + const groupnames = new Set(); + const last_updated = []; + x.items.forEach(function([groupname, _]) { + const layer_group = metadata[groupname]; + if (layer_group === undefined) { + return; + } + if (!groupnames.has(groupname)) { + groupnames.add(groupname); + if (layer_group.last_updated !== undefined) { + last_updated.push(layer_group.last_updated); + } + } + }); + if (last_updated.length > 0) { + /* show creation time of the MVT layers */ + const li = document.createElement('li'); + li.classList.add('list-group-item', 'text-muted'); + ul.appendChild(li) + const i = document.createElement('i'); + i.classList.add('bi', 'bi-clock'); + li.appendChild(i); + const t = document.createTextNode( + ' Lokalt skikt (vectiler) genererades ' + + last_updated + .sort() + .map((ts) => new Date(ts).toLocaleDateString('sv-SE')) + .join('; ') + '.' + ); + li.appendChild(t); + } + + const source_files = new Set(); + x.items.forEach(function([groupname, layername]) { + /* for each source file associated with the accordion header, show copyright, license and timing information */ + const layer_group = metadata[groupname]; + if (layer_group === undefined || layer_group.layers === undefined || layer_group.source_files === undefined) { + return; + } + const def = layer_group.layers[layername]; + if (def === undefined || def.source_files === undefined) { + return; + } + def.source_files.forEach(function(source_file) { + if (source_files.has(source_file)) { + return; + } + const x = layer_group.source_files[source_file]; + source_files.add(source_file); + + const li = document.createElement('li'); + li.classList.add('list-group-item'); + ul.appendChild(li) + const h = document.createElement('h6'); + li.appendChild(h) + if (x.description !== undefined && x.description !== null) { + const t = document.createTextNode(x.description); + h.appendChild(t); + } + + if (x.copyright !== undefined && x.copyright !== null) { + let p = document.createElement('p'); + li.appendChild(p) + const t = document.createTextNode(x.copyright); + p.appendChild(t); + } + + if (x.license !== undefined && x.license !== null) { + let p = document.createElement('p'); + li.appendChild(p) + p.appendChild(document.createTextNode('Licensvillkor: ')); + const t = document.createTextNode(x.license.name); + if (x.license.url === undefined || x.license.url === null) { + p.appendChild(t); + } else { + const a = document.createElement('a'); + a.href = x.license.url; + a.target = '_blank'; + a.appendChild(t); + p.appendChild(a); + } + } + + if (x.product_url !== undefined && x.product_url !== null) { + let p = document.createElement('p'); + li.appendChild(p) + const t = document.createTextNode('Produktlänk '); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-box-arrow-up-right'); + const a = document.createElement('a'); + a.href = x.product_url; + a.target = '_blank'; + a.appendChild(t); + a.appendChild(i); + p.appendChild(a); + } + + if (x.last_modified !== undefined && x.last_modified !== null) { + const p = document.createElement('p'); + p.classList.add('small', 'text-muted'); + li.appendChild(p); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-file-earmark-code'); + p.appendChild(i); + p.appendChild(document.createTextNode(' ')); + const t0 = document.createTextNode('Källfil'); + if (x.url === undefined || x.url === null) { + p.appendChild(t0); + } else { + const a = document.createElement('a'); + p.appendChild(a); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-box-arrow-up-right'); + a.appendChild(t0); + a.appendChild(document.createTextNode(' ')); + a.appendChild(i); + a.href = x.url; + a.target = '_blank'; + } + const t1 = document.createTextNode(' ändrades senast '); + p.appendChild(t1); + const d = new Date(x.last_modified); + const td = document.createTextNode(d.toLocaleDateString('sv-SE')); + p.appendChild(td); + const t2 = document.createTextNode('.') + p.appendChild(t2); + } + }); + }); + }); + }); }; })(); @@ -3270,6 +3449,7 @@ const [vectorLayers, featureOverlayLayer] = (function() { /* layer selection panel */ +const infoMetadataAccordions = []; (function() { const modal = document.getElementById('layer-selection-panel'); modal.classList.add('modal'); @@ -3502,6 +3682,53 @@ const [vectorLayers, featureOverlayLayer] = (function() { location.hash = '#' + searchParams.toString(); }; })(); + + (function() { + const accordion = document.getElementById('info-accordion'); + layerHierarchy.forEach(function(x, idx) { + const item = document.createElement('div'); + accordion.appendChild(item); + item.classList.add('accordion-item'); + + const header = document.createElement('div'); + item.appendChild(header); + header.classList.add('accordion-header'); + + const btn = document.createElement('button'); + header.appendChild(btn); + + const collapse = document.createElement('div'); + item.appendChild(collapse); + collapse.id = 'info-accordion-collapse-' + idx; + collapse.classList.add('accordion-collapse', 'collapse'); + + btn.type = 'button'; + btn.setAttribute('data-bs-toggle', 'collapse'); + btn.setAttribute('data-bs-target', '#' + collapse.id); + btn.setAttribute('aria-expanded', 'false'); + btn.setAttribute('aria-controls', collapse.id); + btn.classList.add('accordion-button', 'collapsed'); + + const t = document.createTextNode(x.text); + btn.appendChild(t); + + const body = document.createElement('div'); + body.classList.add('accordion-body'); + collapse.appendChild(body); + + const ul = document.createElement('ul'); + ul.classList.add('list-group', 'list-group-flush'); + body.appendChild(ul); + + infoMetadataAccordions.push({ + element: ul, + items: x._layers.map(function(k) { + const groupname = k.split('_', 1)[0]; + return [ groupname, k.slice(groupname.length + 1) ]; + }), + }); + }); + })(); })(); /* legend panel */ -- cgit v1.2.3