Compare commits
	
		
			28 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fcb52a289e | |||
| 6adb83b12b | |||
| 796960bdaf | |||
| 1093b41260 | |||
| 8631452475 | |||
| 1e37b4c2a3 | |||
| 959c78b62d | |||
| 0a84ef4614 | |||
| d8aa1544e8 | |||
| 1ac73eda82 | |||
| 3cc7dbe797 | |||
| 7b2445f704 | |||
| bf5c508db6 | |||
| 82700c4689 | |||
| 3e5c8d26a8 | |||
| 7658a12669 | |||
| fd3df826bc | |||
| da2c3c631d | |||
| b01adad0e0 | |||
| 53100c1f2a | |||
| 6e376b4f13 | |||
| 3c94a65913 | |||
| 8697d32d7b | |||
| 8e936c3fb8 | |||
| 0716ca3d9f | |||
| 69ce35e03e | |||
| d974cf4abe | |||
| 6c5cc0d57b | 
							
								
								
									
										15
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "type": "chrome", | ||||||
|  |             "request": "launch", | ||||||
|  |             "name": "Launch Chrome against localhost", | ||||||
|  |             "url": "http://localhost:8080", | ||||||
|  |             "webRoot": "${workspaceFolder}" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
|  | @ -10,8 +10,7 @@ | ||||||
|     html,body,#map {height:100%;margin:0} |     html,body,#map {height:100%;margin:0} | ||||||
|     .coords{position:absolute;left:6px;bottom:6px;z-index:1000;background:rgba(255,255,255,.85); |     .coords{position:absolute;left:6px;bottom:6px;z-index:1000;background:rgba(255,255,255,.85); | ||||||
|       padding:3px 6px;font-size:12px;border-radius:4px;font-family:system-ui,Segoe UI,Arial} |       padding:3px 6px;font-size:12px;border-radius:4px;font-family:system-ui,Segoe UI,Arial} | ||||||
|       .center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 6px rgba(0,0,0,.35);pointer-events:none;z-index:1001} |       .center-dot{position:absolute;top:50%;left:50%;width:5px;height:5px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 2px rgba(0,0,0,.35);pointer-events:none;z-index:1001} | ||||||
|       .center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 6px rgba(0,0,0,.35);pointer-events:none;z-index:1001} |  | ||||||
|     .copy-btn{position:absolute;left:6px;bottom:36px;z-index:1000;background:#ef4444;color:#fff;border:0;border-radius:6px;padding:6px 10px;font:600 12px/1 system-ui,Segoe UI,Arial;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.25)} |     .copy-btn{position:absolute;left:6px;bottom:36px;z-index:1000;background:#ef4444;color:#fff;border:0;border-radius:6px;padding:6px 10px;font:600 12px/1 system-ui,Segoe UI,Arial;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.25)} | ||||||
|     .copy-btn:active{transform:translateY(1px)} |     .copy-btn:active{transform:translateY(1px)} | ||||||
|   </style> |   </style> | ||||||
|  | @ -180,7 +179,8 @@ if (hash.length >= 2) { | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   </script> |   </script> | ||||||
| 
 |   <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | ||||||
|   <script src="markers.js"></script> |   <script src="markers.js"></script> | ||||||
|  | 
 | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
							
								
								
									
										117
									
								
								markers.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								markers.js
									
									
									
									
									
								
							|  | @ -1,91 +1,40 @@ | ||||||
| // === CONFIG ===
 | let Data_api = "/webhook/data"; | ||||||
| const WIKI_API = 'https://wiki.arenos.danielnagel.at/api.php'; // dein Wiki-Host (mit index.php)
 | let freight = null; | ||||||
| const CATEGORY_TITLE = 'Kategorie:Orte';                          // Hauptkategorie
 | let testing = true; | ||||||
| const MAX_PAGES = 500;                                            // genug Luft
 |  | ||||||
| 
 | 
 | ||||||
| // Hilfsfunktion: MediaWiki API-URL bauen
 | let ReqData = { Places: "Stadte"} | ||||||
| function apiURL(params) { |  | ||||||
|   const u = new URL(WIKI_API); |  | ||||||
|   u.search = new URLSearchParams({ ...params, format: 'json', origin: '*' }).toString(); |  | ||||||
|   return u.toString(); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // 1) Alle Mitglieder einer Kategorie holen
 | // Post to n8n Server to get Data from Grist in JSON format.
 | ||||||
| async function fetchCategoryMembers(categoryTitle) { | async function GetMarkerData() { | ||||||
|   const url = apiURL({ |    | ||||||
|     action: 'query', |  | ||||||
|     list: 'categorymembers', |  | ||||||
|     cmtitle: categoryTitle, |  | ||||||
|     cmlimit: String(MAX_PAGES) |  | ||||||
|   }); |  | ||||||
|   const res = await fetch(url); |  | ||||||
|   if (!res.ok) throw new Error(`categorymembers failed: ${res.status}`); |  | ||||||
|   const data = await res.json(); |  | ||||||
|   return data?.query?.categorymembers || []; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 2) Gerendertes HTML einer Seite holen (damit <div class="place-data"> drin ist)
 |  | ||||||
| async function fetchPageHTML(title) { |  | ||||||
|   const url = apiURL({ |  | ||||||
|     action: 'parse', |  | ||||||
|     page: title, |  | ||||||
|     prop: 'text' |  | ||||||
|   }); |  | ||||||
|   const res = await fetch(url); |  | ||||||
|   if (!res.ok) throw new Error(`parse failed for ${title}: ${res.status}`); |  | ||||||
|   const data = await res.json(); |  | ||||||
|   const html = data?.parse?.text?.['*'] || ''; |  | ||||||
|   const div = document.createElement('div'); |  | ||||||
|   div.innerHTML = html; |  | ||||||
|   return div; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 3) Daten aus dem versteckten Div extrahieren
 |  | ||||||
| function extractPlaceData(container) { |  | ||||||
|   const node = container.querySelector('.place-data'); |  | ||||||
|   if (!node) return null; |  | ||||||
|   const name = node.getAttribute('data-name') || ''; |  | ||||||
|   const xStr = node.getAttribute('data-x') || ''; |  | ||||||
|   const yStr = node.getAttribute('data-y') || ''; |  | ||||||
|   const desc = node.getAttribute('data-description') || ''; |  | ||||||
|   const link = node.getAttribute('data-link') || ''; |  | ||||||
|   const x = parseFloat(xStr); |  | ||||||
|   const y = parseFloat(yStr); |  | ||||||
|   if (Number.isNaN(x) || Number.isNaN(y)) return null; |  | ||||||
|   return { name, x, y, desc, link }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 4) Marker laden + hinzufügen
 |  | ||||||
| async function loadWikiMarkers(map) { |  | ||||||
|   try { |   try { | ||||||
|     const pages = await fetchCategoryMembers(CATEGORY_TITLE); |     const res = await axios.post(Data_api, ReqData); | ||||||
|  |     console.log (res.data); | ||||||
|  |     RenderMarkers(res.data); | ||||||
| 
 | 
 | ||||||
|     // Optionales Bounding, falls du später auto-fit willst
 |   } catch (err) { | ||||||
|     const layers = []; |     console.error (err); | ||||||
|     for (const p of pages) { |  | ||||||
|       try { |  | ||||||
|         const html = await fetchPageHTML(p.title); |  | ||||||
|         const d = extractPlaceData(html); |  | ||||||
|         if (!d) continue; |  | ||||||
| 
 |  | ||||||
|         // Leaflet: Bei CRS.Simple = [y, x]
 |  | ||||||
|         const m = L.marker([d.y, d.x]).addTo(map); |  | ||||||
|         const wikiLink = d.link || `https://wiki.arenos.danielnagel.at/index.php/${encodeURIComponent(p.title)}`; |  | ||||||
|         const popup = ` |  | ||||||
|           <b>${d.name || p.title}</b><br> |  | ||||||
|           ${d.desc ? `${d.desc}<br>` : ''} |  | ||||||
|           <a href="${wikiLink}" target="_blank" rel="noopener">Open in Wiki</a> |  | ||||||
|         `;
 |  | ||||||
|         m.bindPopup(popup); |  | ||||||
|         layers.push(m); |  | ||||||
| 
 |  | ||||||
|       } catch (e) { |  | ||||||
|         console.warn('skip page due to parse error:', p.title, e); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   } catch (e) { |  | ||||||
|     console.error('Failed to load wiki markers:', e); |  | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | //Render Map Markers with the Position from Grist Database
 | ||||||
|  | function RenderMarkers(rows){ | ||||||
|  |   if (!Array.isArray(rows)) { | ||||||
|  |     console.error('Erwarte ein Array, bekam:', rows); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   rows.forEach((row) => { | ||||||
|  |     const x = Number(row.X); | ||||||
|  |     const y = Number(row.Y); | ||||||
|  |     if (!Number.isFinite(x) || !Number.isFinite(y)) return; | ||||||
|  | 
 | ||||||
|  |     L.marker([y, x])        // [lat, lng] -> [Y, X]
 | ||||||
|  |       .addTo(map) | ||||||
|  |       .bindPopup(`<b>${row.Name ?? ''}</b>`); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | GetMarkerData(); | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user