/** * KundenKarte Module JavaScript * Copyright (C) 2026 Alles Watt lauft */ (function() { 'use strict'; // Namespace window.KundenKarte = window.KundenKarte || {}; // Get base URL for AJAX calls var baseUrl = (typeof DOL_URL_ROOT !== 'undefined') ? DOL_URL_ROOT : ''; if (!baseUrl) { // Try to detect from script src var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { var src = scripts[i].src; if (src && src.indexOf('/kundenkarte/js/kundenkarte.js') > -1) { baseUrl = src.replace('/custom/kundenkarte/js/kundenkarte.js', '').replace(/\?.*$/, ''); break; } } } /** * Tree Component */ KundenKarte.Tree = { tooltipTimeout: null, hideTimeout: null, currentTooltip: null, currentItem: null, init: function() { this.bindEvents(); }, bindEvents: function() { var self = this; // Toggle tree nodes - MUST use stopImmediatePropagation for delegated handlers on same element $(document).on('click', '.kundenkarte-tree-toggle', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); var $toggle = $(this); var $node = $toggle.closest('.kundenkarte-tree-node'); var $children = $node.children('.kundenkarte-tree-children'); $toggle.toggleClass('collapsed'); $children.toggleClass('collapsed'); }); // Expand all nodes $(document).on('click', '#btn-expand-all', function(e) { e.preventDefault(); self.expandAll(); }); // Collapse all nodes $(document).on('click', '#btn-collapse-all', function(e) { e.preventDefault(); self.collapseAll(); }); // Hover tooltip on ICON only - show after delay $(document).on('mouseenter', '.kundenkarte-tooltip-trigger', function(e) { var $trigger = $(this); var anlageId = $trigger.data('anlage-id'); if (!anlageId) return; // Cancel any pending hide clearTimeout(self.hideTimeout); self.hideTimeout = null; self.currentItem = $trigger; self.tooltipTimeout = setTimeout(function() { self.showTooltip($trigger, anlageId); }, 300); }); // Hide tooltip when leaving icon $(document).on('mouseleave', '.kundenkarte-tooltip-trigger', function() { clearTimeout(self.tooltipTimeout); self.tooltipTimeout = null; self.currentItem = null; // Hide after short delay (allows moving to tooltip) self.hideTimeout = setTimeout(function() { self.hideTooltip(); }, 100); }); // Images tooltip on hover $(document).on('mouseenter', '.kundenkarte-images-trigger', function(e) { var $trigger = $(this); var anlageId = $trigger.data('anlage-id'); if (!anlageId) return; clearTimeout(self.hideTimeout); self.hideTimeout = null; self.tooltipTimeout = setTimeout(function() { self.showImagesPopup($trigger, anlageId); }, 300); }); $(document).on('mouseleave', '.kundenkarte-images-trigger', function() { clearTimeout(self.tooltipTimeout); self.tooltipTimeout = null; self.hideTimeout = setTimeout(function() { self.hideTooltip(); }, 100); }); // Documents tooltip on hover $(document).on('mouseenter', '.kundenkarte-docs-trigger', function(e) { var $trigger = $(this); var anlageId = $trigger.data('anlage-id'); if (!anlageId) return; clearTimeout(self.hideTimeout); self.hideTimeout = null; self.tooltipTimeout = setTimeout(function() { self.showDocsPopup($trigger, anlageId); }, 300); }); $(document).on('mouseleave', '.kundenkarte-docs-trigger', function() { clearTimeout(self.tooltipTimeout); self.tooltipTimeout = null; self.hideTimeout = setTimeout(function() { self.hideTooltip(); }, 100); }); // Keep tooltip visible when hovering over it $(document).on('mouseenter', '#kundenkarte-tooltip', function() { clearTimeout(self.hideTimeout); self.hideTimeout = null; }); // Hide when leaving tooltip $(document).on('mouseleave', '#kundenkarte-tooltip', function() { self.hideTooltip(); }); // Select item $(document).on('click', '.kundenkarte-tree-item', function(e) { if ($(e.target).closest('.kundenkarte-tree-toggle, .kundenkarte-tree-actions, .kundenkarte-tree-files').length) { return; } $('.kundenkarte-tree-item').removeClass('selected'); $(this).addClass('selected'); var anlageId = $(this).data('anlage-id'); if (anlageId) { $(document).trigger('kundenkarte:element:selected', [anlageId]); } }); }, showTooltip: function($item, anlageId) { var self = this; // Get tooltip data from data attribute (faster than AJAX) var tooltipDataStr = $item.attr('data-tooltip'); if (!tooltipDataStr) { console.log('No tooltip data for anlage', anlageId); return; } var data; try { data = JSON.parse(tooltipDataStr); } catch(e) { console.error('Failed to parse tooltip JSON:', e, tooltipDataStr); return; } var html = self.buildTooltipHtml(data); var $tooltip = $('#kundenkarte-tooltip'); if (!$tooltip.length) { $tooltip = $('
'); $('body').append($tooltip); } $tooltip.html(html); // Position tooltip var offset = $item.offset(); var itemWidth = $item.outerWidth(); var windowWidth = $(window).width(); var scrollTop = $(window).scrollTop(); // First show to calculate width $tooltip.css({ visibility: 'hidden', display: 'block' }); var tooltipWidth = $tooltip.outerWidth(); var tooltipHeight = $tooltip.outerHeight(); $tooltip.css({ visibility: '', display: '' }); var left = offset.left + itemWidth + 10; if (left + tooltipWidth > windowWidth - 20) { left = offset.left - tooltipWidth - 10; } if (left < 10) { left = 10; } var top = offset.top; // Prevent tooltip from going below viewport if (top + tooltipHeight > scrollTop + $(window).height() - 20) { top = scrollTop + $(window).height() - tooltipHeight - 20; } $tooltip.css({ top: top, left: left }).addClass('visible').show(); self.currentTooltip = $tooltip; }, hideTooltip: function() { clearTimeout(this.hideTimeout); this.hideTimeout = null; var $tooltip = $('#kundenkarte-tooltip'); if ($tooltip.length) { $tooltip.removeClass('visible').hide(); } this.currentTooltip = null; }, showImagesPopup: function($trigger, anlageId) { var self = this; // Load images via AJAX - use absolute path $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/anlage_images.php', data: { anlage_id: anlageId }, dataType: 'json', success: function(response) { if (!response.images || response.images.length === 0) { return; } var html = '
'; html += '
'; for (var i = 0; i < response.images.length; i++) { var img = response.images[i]; html += ''; html += '' + self.escapeHtml(img.name) + ''; html += ''; } html += '
'; html += '
'; var $tooltip = $('#kundenkarte-tooltip'); if (!$tooltip.length) { $tooltip = $('
'); $('body').append($tooltip); } $tooltip.html(html); // Position tooltip var offset = $trigger.offset(); var windowWidth = $(window).width(); var scrollTop = $(window).scrollTop(); $tooltip.css({ visibility: 'hidden', display: 'block' }); var tooltipWidth = $tooltip.outerWidth(); var tooltipHeight = $tooltip.outerHeight(); $tooltip.css({ visibility: '', display: '' }); var left = offset.left + $trigger.outerWidth() + 10; if (left + tooltipWidth > windowWidth - 20) { left = offset.left - tooltipWidth - 10; } if (left < 10) left = 10; var top = offset.top; if (top + tooltipHeight > scrollTop + $(window).height() - 20) { top = scrollTop + $(window).height() - tooltipHeight - 20; } $tooltip.css({ top: top, left: left }).addClass('visible').show(); self.currentTooltip = $tooltip; } }); }, showDocsPopup: function($trigger, anlageId) { var self = this; // Load documents via AJAX $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/anlage_docs.php', data: { anlage_id: anlageId }, dataType: 'json', success: function(response) { if (!response.docs || response.docs.length === 0) { return; } // Visual document cards with icons var html = '
'; html += '
'; for (var i = 0; i < response.docs.length; i++) { var doc = response.docs[i]; var iconClass = doc.type === 'pdf' ? 'fa-file-pdf-o' : 'fa-file-text-o'; var iconColor = doc.type === 'pdf' ? '#e74c3c' : '#f39c12'; html += ''; html += '
'; html += ''; html += '
'; html += '
' + self.escapeHtml(doc.name) + '
'; html += '
'; } html += '
'; html += '
'; var $tooltip = $('#kundenkarte-tooltip'); if (!$tooltip.length) { $tooltip = $('
'); $('body').append($tooltip); } $tooltip.html(html); // Position tooltip var offset = $trigger.offset(); var windowWidth = $(window).width(); var scrollTop = $(window).scrollTop(); $tooltip.css({ visibility: 'hidden', display: 'block' }); var tooltipWidth = $tooltip.outerWidth(); var tooltipHeight = $tooltip.outerHeight(); $tooltip.css({ visibility: '', display: '' }); var left = offset.left + $trigger.outerWidth() + 10; if (left + tooltipWidth > windowWidth - 20) { left = offset.left - tooltipWidth - 10; } if (left < 10) left = 10; var top = offset.top; if (top + tooltipHeight > scrollTop + $(window).height() - 20) { top = scrollTop + $(window).height() - tooltipHeight - 20; } $tooltip.css({ top: top, left: left }).addClass('visible').show(); self.currentTooltip = $tooltip; } }); }, buildTooltipHtml: function(data) { var html = '
'; html += ''; html += '
'; html += '
' + this.escapeHtml(data.label || '') + '
'; html += '
' + this.escapeHtml(data.type || data.type_label || '') + '
'; html += '
'; html += '
'; if (data.location) { html += ' Standort:'; html += '' + this.escapeHtml(data.location) + ''; } if (data.manufacturer) { html += 'Hersteller:'; html += '' + this.escapeHtml(data.manufacturer) + ''; } if (data.model) { html += 'Modell:'; html += '' + this.escapeHtml(data.model) + ''; } if (data.serial_number) { html += 'Seriennummer:'; html += '' + this.escapeHtml(data.serial_number) + ''; } if (data.power_rating) { html += 'Leistung:'; html += '' + this.escapeHtml(data.power_rating) + ''; } if (data.installation_date) { html += 'Installiert:'; html += '' + this.escapeHtml(data.installation_date) + ''; } // Dynamic fields (from AJAX) if (data.fields) { for (var key in data.fields) { if (data.fields.hasOwnProperty(key) && data.fields[key].show_in_hover) { html += '' + this.escapeHtml(data.fields[key].label) + ':'; html += '' + this.escapeHtml(data.fields[key].value) + ''; } } } html += '
'; // Notes if (data.note) { html += '
'; html += ' ' + this.escapeHtml(data.note); html += '
'; } // Images (from AJAX) if (data.images && data.images.length > 0) { html += '
'; for (var i = 0; i < Math.min(data.images.length, 4); i++) { html += ''; } html += '
'; } return html; }, escapeHtml: function(text) { if (!text) return ''; var div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, refresh: function(socId, systemId) { var $container = $('.kundenkarte-tree[data-system="' + systemId + '"]'); if (!$container.length) return; $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/anlage_tree.php', data: { socid: socId, system: systemId }, success: function(html) { $container.html(html); } }); }, expandAll: function() { $('.kundenkarte-tree-toggle').removeClass('collapsed'); $('.kundenkarte-tree-children').removeClass('collapsed'); }, collapseAll: function() { $('.kundenkarte-tree-toggle').addClass('collapsed'); $('.kundenkarte-tree-children').addClass('collapsed'); } }; /** * Favorite Products Component */ KundenKarte.Favorites = { init: function() { this.bindEvents(); }, bindEvents: function() { // Select all checkbox $(document).on('change', '#kundenkarte-select-all', function() { var checked = $(this).prop('checked'); $('.kundenkarte-favorites-table input[type="checkbox"][name="selected_products[]"]').prop('checked', checked); KundenKarte.Favorites.updateGenerateButton(); }); // Individual checkbox $(document).on('change', '.kundenkarte-favorites-table input[type="checkbox"][name="selected_products[]"]', function() { KundenKarte.Favorites.updateGenerateButton(); }); // Save button click $(document).on('click', '.kundenkarte-qty-save', function(e) { e.preventDefault(); var $btn = $(this); var favId = $btn.data('fav-id'); var $input = $('input.kundenkarte-favorites-qty[data-fav-id="' + favId + '"]'); var qtyStr = $input.val().replace(',', '.'); var qty = parseFloat(qtyStr); if (!isNaN(qty) && qty > 0) { // Limit to 2 decimal places qty = Math.round(qty * 100) / 100; // Format nicely var display = (qty % 1 === 0) ? qty.toString() : qty.toFixed(2).replace(/\.?0+$/, ''); $input.val(display); // Visual feedback $btn.prop('disabled', true); $btn.find('i').removeClass('fa-save').addClass('fa-spinner fa-spin'); $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/favorite_update.php', method: 'POST', data: { id: favId, qty: qty, token: $('input[name="token"]').val() }, success: function() { $btn.find('i').removeClass('fa-spinner fa-spin').addClass('fa-check').css('color', '#0a0'); setTimeout(function() { $btn.find('i').removeClass('fa-check').addClass('fa-save').css('color', ''); $btn.prop('disabled', false); }, 1500); }, error: function() { $btn.find('i').removeClass('fa-spinner fa-spin').addClass('fa-exclamation-triangle').css('color', '#c00'); setTimeout(function() { $btn.find('i').removeClass('fa-exclamation-triangle').addClass('fa-save').css('color', ''); $btn.prop('disabled', false); }, 2000); } }); } }); }, updateGenerateButton: function() { var count = $('.kundenkarte-favorites-table input[type="checkbox"][name="selected_products[]"]:checked').length; var $btn = $('#btn-generate-order'); if (count > 0) { $btn.prop('disabled', false).text($btn.data('text').replace('%d', count)); } else { $btn.prop('disabled', true).text($btn.data('text-none')); } } }; /** * System Tabs Component */ KundenKarte.SystemTabs = { init: function() { this.bindEvents(); }, bindEvents: function() { $(document).on('click', '.kundenkarte-system-tab:not(.active):not(.kundenkarte-system-tab-add)', function() { var systemId = $(this).data('system'); KundenKarte.SystemTabs.switchTo(systemId); }); }, switchTo: function(systemId) { $('.kundenkarte-system-tab').removeClass('active'); $('.kundenkarte-system-tab[data-system="' + systemId + '"]').addClass('active'); $('.kundenkarte-system-content').hide(); $('.kundenkarte-system-content[data-system="' + systemId + '"]').show(); // Update URL without reload var url = new URL(window.location.href); url.searchParams.set('system', systemId); window.history.replaceState({}, '', url); } }; /** * Icon Picker Component with Custom Icon Upload */ KundenKarte.IconPicker = { // Common FontAwesome icons for installations/technical use icons: [ // Electrical 'fa-bolt', 'fa-plug', 'fa-power-off', 'fa-charging-station', 'fa-battery-full', 'fa-battery-half', 'fa-car-battery', 'fa-solar-panel', 'fa-sun', 'fa-lightbulb', 'fa-toggle-on', 'fa-toggle-off', // Network/Internet 'fa-wifi', 'fa-network-wired', 'fa-server', 'fa-database', 'fa-hdd', 'fa-ethernet', 'fa-broadcast-tower', 'fa-satellite-dish', 'fa-satellite', 'fa-signal', 'fa-rss', // TV/Media 'fa-tv', 'fa-play-circle', 'fa-video', 'fa-film', 'fa-podcast', 'fa-music', // Temperature/Climate 'fa-thermometer-half', 'fa-temperature-high', 'fa-temperature-low', 'fa-fire', 'fa-fire-alt', 'fa-snowflake', 'fa-wind', 'fa-fan', 'fa-air-freshener', // Building/Structure 'fa-home', 'fa-building', 'fa-warehouse', 'fa-door-open', 'fa-door-closed', 'fa-archway', // Devices/Hardware 'fa-microchip', 'fa-memory', 'fa-sim-card', 'fa-sd-card', 'fa-usb', 'fa-desktop', 'fa-laptop', 'fa-mobile-alt', 'fa-tablet-alt', 'fa-keyboard', 'fa-print', 'fa-fax', // Security 'fa-shield-alt', 'fa-lock', 'fa-unlock', 'fa-key', 'fa-fingerprint', 'fa-eye', 'fa-video', 'fa-bell', 'fa-exclamation-triangle', 'fa-user-shield', // Objects 'fa-cube', 'fa-cubes', 'fa-box', 'fa-boxes', 'fa-archive', 'fa-toolbox', 'fa-tools', 'fa-wrench', 'fa-cog', 'fa-cogs', 'fa-sliders-h', // Layout 'fa-th', 'fa-th-large', 'fa-th-list', 'fa-grip-horizontal', 'fa-grip-vertical', 'fa-bars', 'fa-stream', 'fa-layer-group', 'fa-project-diagram', 'fa-share-alt', 'fa-sitemap', // Arrows/Direction 'fa-exchange-alt', 'fa-arrows-alt', 'fa-expand', 'fa-compress', 'fa-random', // Misc 'fa-tachometer-alt', 'fa-chart-line', 'fa-chart-bar', 'fa-chart-pie', 'fa-chart-area', 'fa-clock', 'fa-calendar', 'fa-tag', 'fa-tags', 'fa-bookmark', 'fa-star', 'fa-heart', 'fa-check', 'fa-times', 'fa-plus', 'fa-minus', 'fa-info-circle', 'fa-question-circle', 'fa-dot-circle', 'fa-circle', 'fa-square', 'fa-adjust' ], customIcons: [], currentInput: null, currentTab: 'fontawesome', init: function() { this.createModal(); this.bindEvents(); }, createModal: function() { if ($('#kundenkarte-icon-picker-modal').length) return; var self = this; var html = '
'; html += '
'; html += '
'; html += '

Icon auswählen

'; html += '×'; html += '
'; html += '
'; // Tabs html += '
'; html += ''; html += ''; html += '
'; // Font Awesome Tab Content html += '
'; html += ''; html += '
'; for (var i = 0; i < this.icons.length; i++) { html += '
'; html += ''; html += '
'; } html += '
'; html += '
'; // Custom Icons Tab Content html += ''; html += '
'; html += '
'; html += '
'; $('body').append(html); }, bindEvents: function() { var self = this; // Open picker $(document).on('click', '.kundenkarte-icon-picker-btn', function(e) { e.preventDefault(); var inputName = $(this).data('input'); self.currentInput = $('input[name="' + inputName + '"]'); self.open(); }); // Close modal $(document).on('click', '.kundenkarte-modal-close, #kundenkarte-icon-picker-modal', function(e) { if (e.target === this || $(e.target).hasClass('kundenkarte-modal-close')) { self.close(); } }); // Tab switching $(document).on('click', '.kundenkarte-icon-tab', function() { var tab = $(this).data('tab'); self.switchTab(tab); }); // Select FA icon $(document).on('click', '.kundenkarte-icon-item[data-type="fa"]', function() { var icon = $(this).data('icon'); self.selectIcon(icon, 'fa'); }); // Select custom icon $(document).on('click', '.kundenkarte-icon-item[data-type="custom"]', function() { var iconUrl = $(this).data('icon'); self.selectIcon(iconUrl, 'custom'); }); // Search filter (FA only) $(document).on('input', '#kundenkarte-icon-search', function() { var search = $(this).val().toLowerCase(); $('#kundenkarte-fa-icons .kundenkarte-icon-item').each(function() { var icon = $(this).data('icon').toLowerCase(); $(this).toggle(icon.indexOf(search) > -1); }); }); // Upload button click $(document).on('click', '#kundenkarte-icon-upload-btn', function() { $('#kundenkarte-icon-upload').click(); }); // File selected $(document).on('change', '#kundenkarte-icon-upload', function() { var file = this.files[0]; if (file) { self.uploadIcon(file); } }); // Delete custom icon $(document).on('click', '.kundenkarte-icon-delete', function(e) { e.stopPropagation(); var filename = $(this).data('filename'); self.showDeleteConfirm(filename); }); // ESC key to close $(document).on('keydown', function(e) { if (e.key === 'Escape') { self.close(); } }); }, switchTab: function(tab) { this.currentTab = tab; $('.kundenkarte-icon-tab').removeClass('active'); $('.kundenkarte-icon-tab[data-tab="' + tab + '"]').addClass('active'); $('.kundenkarte-icon-tab-content').hide(); $('.kundenkarte-icon-tab-content[data-tab="' + tab + '"]').show(); if (tab === 'custom') { this.loadCustomIcons(); } }, loadCustomIcons: function() { var self = this; var $grid = $('#kundenkarte-custom-icons'); $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/icon_upload.php', data: { action: 'list' }, dataType: 'json', success: function(response) { $grid.empty(); if (response.icons && response.icons.length > 0) { self.customIcons = response.icons; for (var i = 0; i < response.icons.length; i++) { var icon = response.icons[i]; var html = '
'; html += '' + icon.name + ''; html += ''; html += '
'; $grid.append(html); } } else { $grid.html('

Noch keine eigenen Icons hochgeladen.

'); } }, error: function() { $grid.html('

Fehler beim Laden der Icons.

'); } }); }, uploadIcon: function(file) { var self = this; var formData = new FormData(); formData.append('action', 'upload'); formData.append('icon', file); $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/icon_upload.php', method: 'POST', data: formData, processData: false, contentType: false, dataType: 'json', success: function(response) { if (response.success) { self.loadCustomIcons(); // Auto-select uploaded icon setTimeout(function() { self.selectIcon(response.icon.url, 'custom'); }, 500); } else { alert('Fehler: ' + (response.error || 'Unbekannter Fehler')); } }, error: function(xhr) { var msg = 'Upload fehlgeschlagen'; try { var resp = JSON.parse(xhr.responseText); msg = resp.error || msg; } catch(e) {} alert(msg); } }); // Reset input $('#kundenkarte-icon-upload').val(''); }, deleteIcon: function(filename) { var self = this; $.ajax({ url: baseUrl + '/custom/kundenkarte/ajax/icon_upload.php', method: 'POST', data: { action: 'delete', filename: filename }, dataType: 'json', success: function(response) { if (response.success) { self.loadCustomIcons(); } else { alert('Fehler: ' + (response.error || 'Löschen fehlgeschlagen')); } } }); }, showDeleteConfirm: function(filename) { var self = this; // Remove any existing confirm dialog $('#kundenkarte-delete-confirm').remove(); // Create Dolibarr-style confirmation dialog var html = '
'; html += '
'; // Header (Dolibarr style) html += '
'; html += 'Bestätigung'; html += '
'; // Body html += '
'; html += '

Möchten Sie dieses Icon wirklich löschen?

'; html += '

' + this.escapeHtml(filename) + '

'; html += '
'; // Footer with buttons (Dolibarr style) html += ''; html += '
'; html += '
'; $('body').append(html); // Bind events $('#kundenkarte-confirm-yes').on('click', function() { $('#kundenkarte-delete-confirm').remove(); self.deleteIcon(filename); }); $('#kundenkarte-confirm-no, #kundenkarte-delete-confirm').on('click', function(e) { if (e.target === this) { $('#kundenkarte-delete-confirm').remove(); } }); // ESC to close $(document).one('keydown.confirmDialog', function(e) { if (e.key === 'Escape') { $('#kundenkarte-delete-confirm').remove(); } }); }, escapeHtml: function(text) { if (!text) return ''; var div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, selectIcon: function(icon, type) { if (this.currentInput) { // For custom icons, store the URL with a prefix to distinguish var value = (type === 'custom') ? 'img:' + icon : icon; this.currentInput.val(value); // Update preview var $wrapper = this.currentInput.closest('.kundenkarte-icon-picker-wrapper'); var $preview = $wrapper.find('.kundenkarte-icon-preview'); if ($preview.length) { if (type === 'custom') { $preview.html(''); } else { $preview.html(''); } } } this.close(); }, open: function() { $('#kundenkarte-icon-search').val(''); $('#kundenkarte-fa-icons .kundenkarte-icon-item').show(); this.switchTab('fontawesome'); $('#kundenkarte-icon-picker-modal').addClass('visible'); }, close: function() { $('#kundenkarte-icon-picker-modal').removeClass('visible'); this.currentInput = null; } }; // Initialize on DOM ready $(document).ready(function() { KundenKarte.Tree.init(); KundenKarte.Favorites.init(); KundenKarte.SystemTabs.init(); KundenKarte.IconPicker.init(); }); })();