1 Commits

Author SHA1 Message Date
luptmoor
ee79fca487 SSL mode changed to disable 2026-04-21 13:49:10 +02:00
2 changed files with 121 additions and 125 deletions

View File

@@ -54,7 +54,7 @@ if (!$municipality) {
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder@2.4.0/dist/Control.Geocoder.css"> <link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder@2.4.0/dist/Control.Geocoder.css">
<!-- Leaflet Polyline Measurement Tool --> <!-- Leaflet Polyline Measurement Tool -->
<!-- <link rel="stylesheet" href="https://ppete2.github.io/Leaflet.PolylineMeasure/Leaflet.PolylineMeasure.css"> --> <link rel="stylesheet" href="https://ppete2.github.io/Leaflet.PolylineMeasure/Leaflet.PolylineMeasure.css">
<!-- Font Awesome 6 for Icons --> <!-- Font Awesome 6 for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
@@ -321,7 +321,7 @@ if (!$municipality) {
<script src="https://unpkg.com/leaflet-control-geocoder@2.4.0/dist/Control.Geocoder.min.js"></script> <script src="https://unpkg.com/leaflet-control-geocoder@2.4.0/dist/Control.Geocoder.min.js"></script>
<!-- Leaflet PolylineMeasure --> <!-- Leaflet PolylineMeasure -->
<!-- <script src="https://ppete2.github.io/Leaflet.PolylineMeasure/Leaflet.PolylineMeasure.js"></script> --> <script src="https://ppete2.github.io/Leaflet.PolylineMeasure/Leaflet.PolylineMeasure.js"></script>
<!-- SweetAlert2 --> <!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.14.0/dist/sweetalert2.all.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.14.0/dist/sweetalert2.all.min.js"></script>

View File

@@ -14,31 +14,31 @@
// ===================================================================== // =====================================================================
// API Endpoint as relative Path // API Endpoint as relative Path
const API_URL = 'api/contributions.php'; var API_URL = 'api/contributions.php';
// Current User Name, set via Login Modal, stored in sessionStorage // Current User Name, set via Login Modal, stored in sessionStorage
let currentUser = sessionStorage.getItem('webgis_user') || ''; var currentUser = sessionStorage.getItem('webgis_user') || '';
// Category Definitions with Labels, Icons, and Colors // Category Definitions with Labels, Icons, and Colors
const CATEGORIES = { var CATEGORIES = {
consumption: { label: 'Geschäfte', faIcon: 'fa-cart-shopping', color: '#C00000' }, mobility: { label: 'Mobilität', icon: '🚲', color: '#1565C0', faIcon: 'fa-bicycle' },
building: { label: 'Bauen', faIcon: 'fa-building', color: '#E65100' }, building: { label: 'Bauen', icon: '🏗️', color: '#E65100', faIcon: 'fa-helmet-safety' },
energy: { label: 'Energie', faIcon: 'fa-bolt', color: '#FFC000' }, energy: { label: 'Energie', icon: '⚡', color: '#F9A825', faIcon: 'fa-bolt' },
environment: { label: 'Umwelt', faIcon: 'fa-seedling', color: '#92D050' }, environment: { label: 'Umwelt', icon: '🌳', color: '#2E7D32', faIcon: 'fa-tree' },
mobility: { label: 'Mobilität', faIcon: 'fa-bus', color: '#0070C0' }, industry: { label: 'Industrie', icon: '🏭', color: '#6A1B9A', faIcon: 'fa-industry' },
industry: { label: 'Industrie', faIcon: 'fa-industry', color: '#7030A0' }, consumption: { label: 'Konsum', icon: '🛒', color: '#AD1457', faIcon: 'fa-cart-shopping' },
other: { label: 'Sonstiges', faIcon: 'fa-thumbtack', color: '#7F7F7F' } other: { label: 'Sonstiges', icon: '📌', color: '#546E7A', faIcon: 'fa-map-pin' }
}; };
// Application State // Application State
let map; // Leaflet Map Instance var map; // Leaflet Map Instance
let sidebar; // Sidebar Instance var sidebar; // Sidebar Instance
let contributionsLayer; // GeoJSON Layer holding all Contributions var contributionsLayer; // GeoJSON Layer holding all Contributions
let contributionsData = []; // Raw Contribution Data Array var contributionsData = []; // Raw Contribution Data Array
let activeFilters = Object.keys(CATEGORIES); // Active Category Filters var activeFilters = Object.keys(CATEGORIES); // Active Category Filters
let drawnGeometry = null; // Temporary Storage for Geometry drawn with Geoman var drawnGeometry = null; // Temporary Storage for Geometry drawn with Geoman
let drawnGeomType = null; // Temporary Storage for Geometry Type var drawnGeomType = null; // Temporary Storage for Geometry Type
let userVotes = {}; // Tracks User Votes var userVotes = {}; // Tracks User Votes
// ===================================================================== // =====================================================================
// Block 2: Map Initialization // Block 2: Map Initialization
@@ -63,17 +63,17 @@ map = L.map('map', {
// ===================================================================== // =====================================================================
// Basemap Tile Layers // Basemap Tile Layers
const basemapOSM = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { var basemapOSM = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 20 maxZoom: 20
}); });
const basemapCartoDB = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { var basemapCartoDB = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="https://carto.com/">Carto</a>', attribution: '© <a href="https://carto.com/">CARTO</a>',
maxZoom: 20 maxZoom: 20
}); });
const basemapSatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { var basemapSatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: '© <a href="https://www.esri.com/">Esri</a>', attribution: '© <a href="https://www.esri.com/">Esri</a>',
maxZoom: 20 maxZoom: 20
}); });
@@ -82,15 +82,15 @@ const basemapSatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/res
basemapCartoDB.addTo(map); basemapCartoDB.addTo(map);
// Layer Control // Layer Control
const basemaps = { var basemaps = {
'<i class="fa-solid fa-map" style="color:#404040;"></i> Hintergrundkarte (farbe)': basemapOSM, 'OpenStreetMap': basemapOSM,
'<i class="fa-solid fa-map" style="color:#404040;"></i> Hintergrundkarte (grau)': basemapCartoDB, 'CartoDB (hell)': basemapCartoDB,
'<i class="fa-solid fa-satellite" style="color:#404040;"></i> Satellitenbild': basemapSatellite, 'Satellit (Esri)': basemapSatellite,
}; };
const overlays = {}; // Populated later with Contribution Layers var overlays = {}; // Populated later with Contribution Layers
const layerControl = L.control.layers(basemaps, overlays, { var layerControl = L.control.layers(basemaps, overlays, {
position: 'topright', position: 'topright',
collapsed: true collapsed: true
}).addTo(map); }).addTo(map);
@@ -135,39 +135,39 @@ L.Control.geocoder({
}).addTo(map); }).addTo(map);
// Polyline Measure Tool // Polyline Measure Tool
// L.control.polylineMeasure({ L.control.polylineMeasure({
// position: 'topright', position: 'topright',
// unit: 'metres', unit: 'metres',
// showBearings: false, showBearings: false,
// clearMeasurementsOnStop: false, clearMeasurementsOnStop: false,
// showClearControl: true showClearControl: true
// }).addTo(map); }).addTo(map);
// Mouse Position Display // Mouse Position Display
// const MousePositionControl = L.Control.extend({ var MousePositionControl = L.Control.extend({
// options: { position: 'bottomright' }, options: { position: 'bottomright' },
// onAdd: function () { onAdd: function () {
// const container = L.DomUtil.create('div', 'mouse-position-display'); var container = L.DomUtil.create('div', 'mouse-position-display');
// container.innerHTML = 'Lat: , Lng: '; container.innerHTML = 'Lat: , Lng: ';
// map.on('mousemove', function (e) { map.on('mousemove', function (e) {
// container.innerHTML = 'Lat: ' + e.latlng.lat.toFixed(5) + ', Lng: ' + e.latlng.lng.toFixed(5); container.innerHTML = 'Lat: ' + e.latlng.lat.toFixed(5) + ', Lng: ' + e.latlng.lng.toFixed(5);
// }); });
// return container; return container;
// } }
// }); });
// new MousePositionControl().addTo(map); new MousePositionControl().addTo(map);
// GPS Location Button // GPS Location Button
const GpsControl = L.Control.extend({ var GpsControl = L.Control.extend({
options: { position: 'topright' }, options: { position: 'topright' },
onAdd: function () { onAdd: function () {
const container = L.DomUtil.create('div', 'leaflet-bar leaflet-control'); var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
const button = L.DomUtil.create('a', 'gps-control-button', container); var button = L.DomUtil.create('a', 'gps-control-button', container);
button.href = '#'; button.href = '#';
button.title = 'Mein Standort'; button.title = 'Mein Standort';
button.innerHTML = '<i class="fa-solid fa-location-crosshairs"></i>'; button.innerHTML = '<i class="fa-solid fa-location-crosshairs"></i>';
@@ -184,7 +184,7 @@ const GpsControl = L.Control.extend({
new GpsControl().addTo(map); new GpsControl().addTo(map);
// GPS Location Found Handler // GPS Location Found Handler
let gpsMarker = null; var gpsMarker = null;
map.on('locationfound', function (e) { map.on('locationfound', function (e) {
if (gpsMarker) { if (gpsMarker) {
@@ -240,7 +240,7 @@ map.pm.setLang('de');
// Captures drawn Geometry and opens the Create Modal // Captures drawn Geometry and opens the Create Modal
map.on('pm:create', function (e) { map.on('pm:create', function (e) {
const geojson = e.layer.toGeoJSON().geometry; var geojson = e.layer.toGeoJSON().geometry;
// Determines drawn Geometry Type and normalizes to simple Types // Determines drawn Geometry Type and normalizes to simple Types
if (e.shape === 'Marker') { if (e.shape === 'Marker') {
@@ -280,8 +280,8 @@ map.on('pm:create', function (e) {
// Generic API Call Function // Generic API Call Function
function apiCall(data, callback) { function apiCall(data, callback) {
const formData = new FormData(); var formData = new FormData();
for (const key in data) { for (var key in data) {
formData.append(key, data[key]); formData.append(key, data[key]);
} }
@@ -324,7 +324,8 @@ function loadContributions() {
onEachFeature: bindFeaturePopup onEachFeature: bindFeaturePopup
}).addTo(map); }).addTo(map);
layerControl.addOverlay(contributionsLayer, '<i class="fa-solid fa-map-pin" style="color:#C00000;"></i> Beiträge'); layerControl.addOverlay(contributionsLayer, 'Beiträge');
// Update Sidebar List and Statistics // Update Sidebar List and Statistics
updateContributionsList(); updateContributionsList();
updateStatistics(); updateStatistics();
@@ -338,7 +339,7 @@ function loadContributions() {
// Style for Point Features (CircleMarkers) // Style for Point Features (CircleMarkers)
function stylePoint(feature, latlng) { function stylePoint(feature, latlng) {
const cat = CATEGORIES[feature.properties.category] || CATEGORIES.other; var cat = CATEGORIES[feature.properties.category] || CATEGORIES.other;
return L.circleMarker(latlng, { return L.circleMarker(latlng, {
radius: 8, radius: 8,
@@ -351,7 +352,7 @@ function stylePoint(feature, latlng) {
// Style for Line and Polygon Features // Style for Line and Polygon Features
function styleLinePolygon(feature) { function styleLinePolygon(feature) {
const cat = CATEGORIES[feature.properties.category] || CATEGORIES.other; var cat = CATEGORIES[feature.properties.category] || CATEGORIES.other;
return { return {
color: cat.color, color: cat.color,
@@ -368,19 +369,19 @@ function styleLinePolygon(feature) {
// ===================================================================== // =====================================================================
function bindFeaturePopup(feature, layer) { function bindFeaturePopup(feature, layer) {
const props = feature.properties; var props = feature.properties;
const cat = CATEGORIES[props.category] || CATEGORIES.other; var cat = CATEGORIES[props.category] || CATEGORIES.other;
// Formats Date // Formats Date
const date = new Date(props.created_at); var date = new Date(props.created_at);
const dateStr = date.toLocaleDateString('de-DE', { var dateStr = date.toLocaleDateString('de-DE', {
day: '2-digit', month: '2-digit', year: 'numeric' day: '2-digit', month: '2-digit', year: 'numeric'
}); });
// Builds Popup on Click // Builds Popup on Click
const html = '' + var html = '' +
'<div class="popup-detail">' + '<div class="popup-detail">' +
'<span class="popup-detail-category">' + categoryIcon(cat) + ' ' + cat.label + '</span>' + '<span class="popup-detail-category">' + cat.icon + ' ' + cat.label + '</span>' +
'<div class="popup-detail-title">' + escapeHtml(props.title) + '</div>' + '<div class="popup-detail-title">' + escapeHtml(props.title) + '</div>' +
(props.description ? '<div class="popup-detail-description">' + escapeHtml(props.description) + '</div>' : '') + (props.description ? '<div class="popup-detail-description">' + escapeHtml(props.description) + '</div>' : '') +
'<div class="popup-detail-meta">' + '<div class="popup-detail-meta">' +
@@ -405,7 +406,7 @@ function bindFeaturePopup(feature, layer) {
layer.bindPopup(html, { maxWidth: 320, minWidth: 240 }); layer.bindPopup(html, { maxWidth: 320, minWidth: 240 });
// Builds Tooltip on Hover // Builds Tooltip on Hover
layer.bindTooltip(categoryIcon(cat) + ' ' + escapeHtml(props.title), { layer.bindTooltip(cat.icon + ' ' + escapeHtml(props.title), {
direction: 'top', direction: 'top',
offset: [0, -10] offset: [0, -10]
}); });
@@ -418,11 +419,11 @@ function bindFeaturePopup(feature, layer) {
// CREATE: Submits new Contributions from Modal // CREATE: Submits new Contributions from Modal
function submitCreate() { function submitCreate() {
const category = document.getElementById('create-category').value; var category = document.getElementById('create-category').value;
const title = document.getElementById('create-title').value.trim(); var title = document.getElementById('create-title').value.trim();
const description = document.getElementById('create-description').value.trim(); var description = document.getElementById('create-description').value.trim();
const geom = document.getElementById('create-geom').value; var geom = document.getElementById('create-geom').value;
const geomType = document.getElementById('create-geom-type').value; var geomType = document.getElementById('create-geom-type').value;
// Validates // Validates
if (!category) { if (!category) {
@@ -478,13 +479,13 @@ function closeCreateModal() {
// UPDATE: Edits existing Contributions // UPDATE: Edits existing Contributions
function editContribution(contributionId) { function editContribution(contributionId) {
// Finds Contribution in local Data // Finds Contribution in local Data
const contribution = contributionsData.find(function (f) { var contribution = contributionsData.find(function (f) {
return f.properties.contribution_id === contributionId; return f.properties.contribution_id === contributionId;
}); });
if (!contribution) return; if (!contribution) return;
const props = contribution.properties; var props = contribution.properties;
Swal.fire({ Swal.fire({
title: 'Beitrag bearbeiten', title: 'Beitrag bearbeiten',
@@ -570,10 +571,10 @@ function voteContribution(contributionId, voteType) {
} }
// Updates local Vote State // Updates local Vote State
const likeBtn = document.getElementById('vote-like-' + contributionId); var likeBtn = document.getElementById('vote-like-' + contributionId);
const dislikeBtn = document.getElementById('vote-dislike-' + contributionId); var dislikeBtn = document.getElementById('vote-dislike-' + contributionId);
const likesSpan = document.getElementById('likes-' + contributionId); var likesSpan = document.getElementById('likes-' + contributionId);
const dislikesSpan = document.getElementById('dislikes-' + contributionId); var dislikesSpan = document.getElementById('dislikes-' + contributionId);
if (response.action === 'created') { if (response.action === 'created') {
// New Vote — Highlights Button and updates Count // New Vote — Highlights Button and updates Count
@@ -619,16 +620,16 @@ function voteContribution(contributionId, voteType) {
// ===================================================================== // =====================================================================
function updateContributionsList() { function updateContributionsList() {
const container = document.getElementById('contributions-list'); var container = document.getElementById('contributions-list');
const searchInput = document.getElementById('list-search-input'); var searchInput = document.getElementById('list-search-input');
const searchTerm = searchInput ? searchInput.value.toLowerCase() : ''; var searchTerm = searchInput ? searchInput.value.toLowerCase() : '';
// Filters by Categories and Search Term // Filters by Categories and Search Term
const filtered = contributionsData.filter(function (f) { var filtered = contributionsData.filter(function (f) {
const props = f.properties; var props = f.properties;
const matchesCategory = activeFilters.indexOf(props.category) !== -1; var matchesCategory = activeFilters.indexOf(props.category) !== -1;
const cat = CATEGORIES[props.category] || CATEGORIES.other; var cat = CATEGORIES[props.category] || CATEGORIES.other;
const matchesSearch = !searchTerm || var matchesSearch = !searchTerm ||
props.title.toLowerCase().indexOf(searchTerm) !== -1 || props.title.toLowerCase().indexOf(searchTerm) !== -1 ||
(props.description && props.description.toLowerCase().indexOf(searchTerm) !== -1) || (props.description && props.description.toLowerCase().indexOf(searchTerm) !== -1) ||
props.author_name.toLowerCase().indexOf(searchTerm) !== -1 || props.author_name.toLowerCase().indexOf(searchTerm) !== -1 ||
@@ -647,16 +648,16 @@ function updateContributionsList() {
return; return;
} }
let html = ''; var html = '';
filtered.forEach(function (f) { filtered.forEach(function (f) {
const props = f.properties; var props = f.properties;
const cat = CATEGORIES[props.category] || CATEGORIES.other; var cat = CATEGORIES[props.category] || CATEGORIES.other;
const date = new Date(props.created_at).toLocaleDateString('de-DE'); var date = new Date(props.created_at).toLocaleDateString('de-DE');
html += '' + html += '' +
'<div class="contribution-card" onclick="flyToContribution(' + props.contribution_id + ')">' + '<div class="contribution-card" onclick="flyToContribution(' + props.contribution_id + ')">' +
'<div class="contribution-card-header">' + '<div class="contribution-card-header">' +
'<span class="contribution-card-category">' + categoryIcon(cat) + ' ' + cat.label + '</span>' + '<span class="contribution-card-category">' + cat.icon + ' ' + cat.label + '</span>' +
'</div>' + '</div>' +
'<div class="contribution-card-title">' + escapeHtml(props.title) + '</div>' + '<div class="contribution-card-title">' + escapeHtml(props.title) + '</div>' +
'<div class="contribution-card-meta">' + '<div class="contribution-card-meta">' +
@@ -708,17 +709,18 @@ document.getElementById('list-search-input').addEventListener('input', function
// Builds Category Filter Checkboxes // Builds Category Filter Checkboxes
function buildCategoryFilter() { function buildCategoryFilter() {
const container = document.getElementById('category-filter'); var container = document.getElementById('category-filter');
let html = ''; var html = '';
for (const key in CATEGORIES) { for (var key in CATEGORIES) {
const cat = CATEGORIES[key]; var cat = CATEGORIES[key];
const checked = activeFilters.indexOf(key) !== -1 ? 'checked' : ''; var checked = activeFilters.indexOf(key) !== -1 ? 'checked' : '';
html += '' + html += '' +
'<label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;cursor:pointer;">' + '<label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;cursor:pointer;">' +
'<input type="checkbox" value="' + key + '" ' + checked + ' onchange="toggleCategoryFilter(this)">' + '<input type="checkbox" value="' + key + '" ' + checked + ' onchange="toggleCategoryFilter(this)">' +
'<span>' + categoryIcon(cat) + ' ' + cat.label + '</span>' + '<span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:' + cat.color + ';"></span>' +
'<span>' + cat.icon + ' ' + cat.label + '</span>' +
'</label>'; '</label>';
} }
@@ -727,7 +729,7 @@ function buildCategoryFilter() {
// Toggles a Category Filter on or off // Toggles a Category Filter on or off
function toggleCategoryFilter(checkbox) { function toggleCategoryFilter(checkbox) {
const category = checkbox.value; var category = checkbox.value;
if (checkbox.checked) { if (checkbox.checked) {
if (activeFilters.indexOf(category) === -1) { if (activeFilters.indexOf(category) === -1) {
@@ -741,7 +743,7 @@ function toggleCategoryFilter(checkbox) {
if (contributionsLayer) { if (contributionsLayer) {
contributionsLayer.eachLayer(function (layer) { contributionsLayer.eachLayer(function (layer) {
if (layer.feature) { if (layer.feature) {
const cat = layer.feature.properties.category; var cat = layer.feature.properties.category;
if (activeFilters.indexOf(cat) !== -1) { if (activeFilters.indexOf(cat) !== -1) {
layer.setStyle({ opacity: 1, fillOpacity: layer.feature.geometry.type === 'Point' ? 0.9 : 0.25 }); layer.setStyle({ opacity: 1, fillOpacity: layer.feature.geometry.type === 'Point' ? 0.9 : 0.25 });
if (layer.setRadius) layer.setRadius(8); if (layer.setRadius) layer.setRadius(8);
@@ -763,24 +765,24 @@ function toggleCategoryFilter(checkbox) {
// Updates Statistics in Home Tab // Updates Statistics in Home Tab
function updateStatistics() { function updateStatistics() {
const container = document.getElementById('stats-container'); var container = document.getElementById('stats-container');
const total = contributionsData.length; var total = contributionsData.length;
// Counts per Category // Counts per Category
const counts = {}; var counts = {};
contributionsData.forEach(function (f) { contributionsData.forEach(function (f) {
const cat = f.properties.category; var cat = f.properties.category;
counts[cat] = (counts[cat] || 0) + 1; counts[cat] = (counts[cat] || 0) + 1;
}); });
let html = '<p style="font-size:0.9rem;"><strong>' + total + '</strong> Beiträge insgesamt</p>'; var html = '<p style="font-size:0.9rem;"><strong>' + total + '</strong> Beiträge insgesamt</p>';
for (const key in CATEGORIES) { for (var key in CATEGORIES) {
const cat = CATEGORIES[key]; var cat = CATEGORIES[key];
const count = counts[key] || 0; var count = counts[key] || 0;
if (count > 0) { if (count > 0) {
html += '<div style="display:flex;align-items:center;gap:8px;margin:4px 0;font-size:0.85rem;">' + html += '<div style="display:flex;align-items:center;gap:8px;margin:4px 0;font-size:0.85rem;">' +
categoryIcon(cat) + ' ' + '<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + cat.color + ';"></span>' +
cat.label + ': ' + count + cat.label + ': ' + count +
'</div>'; '</div>';
} }
@@ -796,7 +798,7 @@ function updateStatistics() {
// Welcome Modal shows on new Visits // Welcome Modal shows on new Visits
function checkWelcomeModal() { function checkWelcomeModal() {
const hasVisited = localStorage.getItem('webgis_welcomed'); var hasVisited = localStorage.getItem('webgis_welcomed');
if (!hasVisited) { if (!hasVisited) {
document.getElementById('welcome-modal').style.display = 'flex'; document.getElementById('welcome-modal').style.display = 'flex';
} }
@@ -816,7 +818,7 @@ function showLoginModal() {
} }
function submitLogin() { function submitLogin() {
const name = document.getElementById('user-name-input').value.trim(); var name = document.getElementById('user-name-input').value.trim();
if (!name) { if (!name) {
Swal.fire('Name eingeben', 'Bitte geben Sie Ihren Namen ein.', 'warning'); Swal.fire('Name eingeben', 'Bitte geben Sie Ihren Namen ein.', 'warning');
return; return;
@@ -880,14 +882,14 @@ function showImprintModal() {
// ===================================================================== // =====================================================================
function toggleMobileNav() { function toggleMobileNav() {
const nav = document.querySelector('.header-nav'); var nav = document.querySelector('.header-nav');
nav.classList.toggle('open'); nav.classList.toggle('open');
} }
// Closes Mobile Nav when clicking outside // Closes Mobile Nav when clicking outside
document.addEventListener('click', function (e) { document.addEventListener('click', function (e) {
const nav = document.querySelector('.header-nav'); var nav = document.querySelector('.header-nav');
const toggle = document.querySelector('.header-menu-toggle'); var toggle = document.querySelector('.header-menu-toggle');
if (nav.classList.contains('open') && !nav.contains(e.target) && !toggle.contains(e.target)) { if (nav.classList.contains('open') && !nav.contains(e.target) && !toggle.contains(e.target)) {
nav.classList.remove('open'); nav.classList.remove('open');
@@ -911,16 +913,11 @@ document.addEventListener('keydown', function (e) {
// Escapes HTML to prevent Cross-Site Scripting (XSS) in Popups and Lists // Escapes HTML to prevent Cross-Site Scripting (XSS) in Popups and Lists
function escapeHtml(text) { function escapeHtml(text) {
if (!text) return ''; if (!text) return '';
const div = document.createElement('div'); var div = document.createElement('div');
div.appendChild(document.createTextNode(text)); div.appendChild(document.createTextNode(text));
return div.innerHTML; return div.innerHTML;
} }
// Returns a colored Font Awesome Icon HTML String for a Category
function categoryIcon(cat) {
return '<i class="fa-solid ' + cat.faIcon + '" style="color:' + cat.color + ';"></i>';
}
// ===================================================================== // =====================================================================
// Block 16: Application Startup // Block 16: Application Startup
@@ -928,13 +925,12 @@ function categoryIcon(cat) {
// Populates Category Dropdown in Create Modal from Categories Object // Populates Category Dropdown in Create Modal from Categories Object
function buildCategoryDropdown() { function buildCategoryDropdown() {
const select = document.getElementById('create-category'); var select = document.getElementById('create-category');
for (const key in CATEGORIES) { for (var key in CATEGORIES) {
const cat = CATEGORIES[key]; var cat = CATEGORIES[key];
const option = document.createElement('option'); var option = document.createElement('option');
option.value = key; option.value = key;
option.textContent = cat.label; option.textContent = cat.icon + ' ' + cat.label;
option.dataset.icon = cat.faIcon;
select.appendChild(option); select.appendChild(option);
} }
} }