diff --git a/COPYING b/COPYING
old mode 100755
new mode 100644
diff --git a/ChangeLog.md b/ChangeLog.md
index 4b5ddd2..425c3b7 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,39 @@
# CHANGELOG MODULE KUNDENKARTE FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
+## 11.0 (2026-03)
+
+### Neue Features
+
+- **Terminal-Farben nach Verbindung**: Terminals zeigen die Farbe der angeschlossenen Leitung
+ - Grau = keine Verbindung, farbig = Leitung angeschlossen
+ - Farbe entspricht dem Leitungstyp (L1=braun, L2=schwarz, L3=grau, N=blau, PE=gruen)
+ - Neue Hilfsfunktion `getTerminalConnectionColor()`
+
+- **Leitungen hinter Bloecken**: Wires werden nun hinter den Equipment-Bloecken gerendert
+ - Layer-Reihenfolge geaendert: connections-layer vor blocks-layer
+ - Leitungen "verschwinden" hinter Bloecken und kommen auf der anderen Seite wieder raus
+ - Professionelleres Erscheinungsbild wie in echten Schaltplan-Editoren
+
+### Verbesserungen
+
+- **Zeichenmodus-Verhalten**: Konsistentes Verhalten im manuellen Zeichenmodus
+ - Rechtsklick bricht nur aktuelle Linie ab, nicht den Zeichenmodus
+ - Escape-Taste verhaelt sich identisch (Linie abbrechen, Modus bleibt aktiv)
+ - Crosshair-Cursor ueberall im SVG waehrend Zeichenmodus (nicht nur auf Terminals)
+ - Keine Unterbrechung mehr beim Klicken auf leere Flaechen
+
+- **Terminal Hit-Area**: Verbesserte Klickbarkeit der Terminals
+ - 30px Radius fuer einfacheres Anklicken
+ - `pointer-events:all` fuer zuverlaessige Event-Erfassung
+
+### Bugfixes
+
+- Cursor zeigte nicht ueberall Crosshair im Zeichenmodus
+- Zeichenmodus wurde bei Rechtsklick/Escape komplett beendet statt nur Linie abzubrechen
+- Junction-Verbindungen (Terminal zu Leitung) werden korrekt gerendert
+
+---
+
## 8.6 (2026-03)
### Neue Features
diff --git a/README.md b/README.md
old mode 100755
new mode 100644
diff --git a/admin/about.php b/admin/about.php
old mode 100755
new mode 100644
diff --git a/admin/anlage_systems.php b/admin/anlage_systems.php
old mode 100755
new mode 100644
diff --git a/admin/backup.php b/admin/backup.php
old mode 100755
new mode 100644
diff --git a/admin/busbar_types.php b/admin/busbar_types.php
old mode 100755
new mode 100644
diff --git a/admin/medium_types.php b/admin/medium_types.php
old mode 100755
new mode 100644
diff --git a/ajax/anlage.php b/ajax/anlage.php
old mode 100755
new mode 100644
diff --git a/ajax/anlage_connection.php b/ajax/anlage_connection.php
old mode 100755
new mode 100644
diff --git a/ajax/anlage_docs.php b/ajax/anlage_docs.php
old mode 100755
new mode 100644
diff --git a/ajax/anlage_images.php b/ajax/anlage_images.php
old mode 100755
new mode 100644
diff --git a/ajax/anlage_tooltip.php b/ajax/anlage_tooltip.php
old mode 100755
new mode 100644
diff --git a/ajax/audit_log.php b/ajax/audit_log.php
old mode 100755
new mode 100644
diff --git a/ajax/bom_generator.php b/ajax/bom_generator.php
old mode 100755
new mode 100644
diff --git a/ajax/building_types.php b/ajax/building_types.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment.php b/ajax/equipment.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment_carrier.php b/ajax/equipment_carrier.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment_connection.php b/ajax/equipment_connection.php
old mode 100755
new mode 100644
index 4b4332f..fbeb776
--- a/ajax/equipment_connection.php
+++ b/ajax/equipment_connection.php
@@ -44,8 +44,11 @@ switch ($action) {
'id' => $connection->id,
'fk_source' => $connection->fk_source,
'source_terminal' => $connection->source_terminal,
+ 'source_terminal_id' => $connection->source_terminal_id,
+ 'bundled_terminals' => $connection->bundled_terminals,
'fk_target' => $connection->fk_target,
'target_terminal' => $connection->target_terminal,
+ 'target_terminal_id' => $connection->target_terminal_id,
'connection_type' => $connection->connection_type,
'color' => $connection->color,
'output_label' => $connection->output_label,
@@ -77,11 +80,14 @@ switch ($action) {
'id' => $c->id,
'fk_source' => $c->fk_source,
'source_terminal' => $c->source_terminal,
+ 'source_terminal_id' => $c->source_terminal_id,
+ 'bundled_terminals' => $c->bundled_terminals,
'source_label' => $c->source_label,
'source_pos' => $c->source_pos,
'source_width' => $c->source_width,
'fk_target' => $c->fk_target,
'target_terminal' => $c->target_terminal,
+ 'target_terminal_id' => $c->target_terminal_id,
'target_label' => $c->target_label,
'target_pos' => $c->target_pos,
'connection_type' => $c->connection_type,
@@ -154,6 +160,7 @@ switch ($action) {
$connection->fk_carrier = $carrierId;
$connection->position_y = GETPOSTINT('position_y');
$connection->path_data = GETPOST('path_data', 'nohtml');
+ $connection->bundled_terminals = GETPOST('bundled_terminals', 'alphanohtml');
$result = $connection->create($user);
if ($result > 0) {
@@ -188,6 +195,7 @@ switch ($action) {
if (GETPOSTISSET('excluded_te')) $connection->excluded_te = GETPOST('excluded_te', 'alphanohtml');
if (GETPOSTISSET('position_y')) $connection->position_y = GETPOSTINT('position_y');
if (GETPOSTISSET('path_data')) $connection->path_data = GETPOST('path_data', 'nohtml');
+ if (GETPOSTISSET('bundled_terminals')) $connection->bundled_terminals = GETPOST('bundled_terminals', 'alphanohtml');
$result = $connection->update($user);
if ($result > 0) {
@@ -341,6 +349,7 @@ switch ($action) {
'fk_source' => $obj->fk_source,
'source_terminal' => $obj->source_terminal,
'source_terminal_id' => $obj->source_terminal_id,
+ 'bundled_terminals' => isset($obj->bundled_terminals) ? $obj->bundled_terminals : null,
'source_label' => $obj->source_label,
'source_pos' => $obj->source_pos,
'source_width' => $obj->source_width,
diff --git a/ajax/equipment_panel.php b/ajax/equipment_panel.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment_type_block_image.php b/ajax/equipment_type_block_image.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment_type_fields.php b/ajax/equipment_type_fields.php
old mode 100755
new mode 100644
diff --git a/ajax/equipment_type_icon.php b/ajax/equipment_type_icon.php
old mode 100755
new mode 100644
diff --git a/ajax/export_schematic_pdf.php b/ajax/export_schematic_pdf.php
old mode 100755
new mode 100644
diff --git a/ajax/export_tree_pdf.php b/ajax/export_tree_pdf.php
old mode 100755
new mode 100644
diff --git a/ajax/favorite_update.php b/ajax/favorite_update.php
old mode 100755
new mode 100644
diff --git a/ajax/field_autocomplete.php b/ajax/field_autocomplete.php
old mode 100755
new mode 100644
diff --git a/ajax/file_preview.php b/ajax/file_preview.php
old mode 100755
new mode 100644
diff --git a/ajax/graph_data.php b/ajax/graph_data.php
old mode 100755
new mode 100644
diff --git a/ajax/graph_save_positions.php b/ajax/graph_save_positions.php
old mode 100755
new mode 100644
diff --git a/ajax/icon_upload.php b/ajax/icon_upload.php
old mode 100755
new mode 100644
diff --git a/ajax/medium_types.php b/ajax/medium_types.php
old mode 100755
new mode 100644
diff --git a/ajax/pwa_api.php b/ajax/pwa_api.php
old mode 100755
new mode 100644
diff --git a/ajax/tree_config.php b/ajax/tree_config.php
old mode 100755
new mode 100644
diff --git a/ajax/type_fields.php b/ajax/type_fields.php
old mode 100755
new mode 100644
diff --git a/anlage_connection.php b/anlage_connection.php
old mode 100755
new mode 100644
diff --git a/build/buildzip.php b/build/buildzip.php
old mode 100755
new mode 100644
diff --git a/build/makepack-kundenkarte.conf b/build/makepack-kundenkarte.conf
old mode 100755
new mode 100644
diff --git a/class/anlage.class.php b/class/anlage.class.php
old mode 100755
new mode 100644
diff --git a/class/anlagebackup.class.php b/class/anlagebackup.class.php
old mode 100755
new mode 100644
diff --git a/class/anlageconnection.class.php b/class/anlageconnection.class.php
old mode 100755
new mode 100644
diff --git a/class/anlagefile.class.php b/class/anlagefile.class.php
old mode 100755
new mode 100644
diff --git a/class/auditlog.class.php b/class/auditlog.class.php
old mode 100755
new mode 100644
diff --git a/class/busbartype.class.php b/class/busbartype.class.php
old mode 100755
new mode 100644
diff --git a/class/equipment.class.php b/class/equipment.class.php
old mode 100755
new mode 100644
diff --git a/class/equipmentcarrier.class.php b/class/equipmentcarrier.class.php
old mode 100755
new mode 100644
diff --git a/class/equipmentconnection.class.php b/class/equipmentconnection.class.php
old mode 100755
new mode 100644
diff --git a/class/equipmentpanel.class.php b/class/equipmentpanel.class.php
old mode 100755
new mode 100644
diff --git a/class/equipmenttype.class.php b/class/equipmenttype.class.php
old mode 100755
new mode 100644
diff --git a/class/favoriteproduct.class.php b/class/favoriteproduct.class.php
old mode 100755
new mode 100644
diff --git a/class/mediumtype.class.php b/class/mediumtype.class.php
old mode 100755
new mode 100644
diff --git a/class/terminalbridge.class.php b/class/terminalbridge.class.php
old mode 100755
new mode 100644
diff --git a/core/modules/modKundenKarte.class.php b/core/modules/modKundenKarte.class.php
old mode 100755
new mode 100644
index 6bba0c7..101ca14
--- a/core/modules/modKundenKarte.class.php
+++ b/core/modules/modKundenKarte.class.php
@@ -76,7 +76,7 @@ class modKundenKarte extends DolibarrModules
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@kundenkarte'
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
- $this->version = '8.6';
+ $this->version = '9.6';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
diff --git a/css/kundenkarte.css b/css/kundenkarte.css
old mode 100755
new mode 100644
index 48389fb..f4c4fca
--- a/css/kundenkarte.css
+++ b/css/kundenkarte.css
@@ -2119,6 +2119,13 @@ body.kundenkarte-drag-active * {
margin-top: 20px !important;
max-width: 100% !important;
overflow-x: auto !important;
+ display: flex !important;
+ flex-direction: column !important;
+}
+
+/* Prevent gap between header and message */
+.schematic-editor-wrapper > * {
+ flex-shrink: 0 !important;
}
/* Prevent Schematic Editor from breaking Dolibarr layout */
@@ -2135,6 +2142,17 @@ body.kundenkarte-drag-active * {
background: #252525 !important;
border: 1px solid #333 !important;
border-radius: 4px 4px 0 0 !important;
+ margin: 0 !important;
+ box-sizing: border-box !important;
+ min-height: 50px !important;
+ flex-wrap: wrap !important;
+}
+
+.schematic-editor-actions {
+ display: flex !important;
+ flex-wrap: wrap !important;
+ gap: 10px !important;
+ align-items: center !important;
}
.schematic-editor-toggle {
@@ -2163,6 +2181,7 @@ body.kundenkarte-drag-active * {
min-height: 300px !important;
max-width: 100% !important;
box-sizing: border-box !important;
+ margin: 0 !important;
}
.schematic-editor-canvas.expanded {
@@ -2214,13 +2233,19 @@ body.kundenkarte-drag-active * {
transition: filter 0.2s ease !important;
}
-/* Terminals */
+/* Terminals - hitarea captures all events */
.schematic-terminal {
+ pointer-events: none !important;
+}
+
+.schematic-terminal-hitarea {
cursor: crosshair !important;
+ pointer-events: all !important;
}
.schematic-terminal-circle {
transition: all 0.2s ease !important;
+ pointer-events: none !important;
}
.schematic-terminal:hover .schematic-terminal-circle {
@@ -2260,7 +2285,7 @@ body.kundenkarte-drag-active * {
/* Messages - Fixed height status bar */
.schematic-message {
padding: 6px 15px !important;
- margin-bottom: 0 !important;
+ margin: 0 !important;
border-radius: 0 !important;
font-size: 12px !important;
height: 28px !important;
@@ -2275,6 +2300,7 @@ body.kundenkarte-drag-active * {
border: 1px solid #3498db !important;
border-top: none !important;
border-bottom: none !important;
+ display: block !important;
}
.schematic-message.info {
diff --git a/css/kundenkarte_cytoscape.css b/css/kundenkarte_cytoscape.css
old mode 100755
new mode 100644
diff --git a/css/pwa.css b/css/pwa.css
old mode 100755
new mode 100644
index 5803b71..441e20c
--- a/css/pwa.css
+++ b/css/pwa.css
@@ -1144,6 +1144,21 @@ body {
stroke-linejoin: round;
}
+/* Wire Toggle Button */
+#btn-toggle-wires {
+ opacity: 0.5;
+ transition: opacity 0.2s, background 0.2s;
+}
+
+#btn-toggle-wires.active {
+ opacity: 1;
+ background: rgba(173, 140, 79, 0.3);
+}
+
+#btn-toggle-wires svg {
+ fill: currentColor;
+}
+
/* Grid-Rows: 1=Labels oben, 2=Terminals oben, 3=Equipment, 4=Terminals unten, 5=Labels unten */
/* Add Button in Carrier (letzte Spalte, Zeile 2) */
.btn-add-equipment {
diff --git a/img/README.md b/img/README.md
old mode 100755
new mode 100644
diff --git a/js/cose-base.js b/js/cose-base.js
old mode 100755
new mode 100644
diff --git a/js/cytoscape-cose-bilkent.js b/js/cytoscape-cose-bilkent.js
old mode 100755
new mode 100644
diff --git a/js/cytoscape-dagre.js b/js/cytoscape-dagre.js
old mode 100755
new mode 100644
diff --git a/js/cytoscape.min.js b/js/cytoscape.min.js
old mode 100755
new mode 100644
diff --git a/js/dagre.min.js b/js/dagre.min.js
old mode 100755
new mode 100644
diff --git a/js/kundenkarte.js b/js/kundenkarte.js
index dcc383c..0e0f32d 100644
--- a/js/kundenkarte.js
+++ b/js/kundenkarte.js
@@ -5276,12 +5276,39 @@
return '#f1c40f'; // Default yellow
},
+ // Get connection color for a specific terminal (if connected)
+ getTerminalConnectionColor: function(equipmentId, terminalId) {
+ var eqId = String(equipmentId);
+ var termId = String(terminalId);
+
+ if (!this.connections || this.connections.length === 0) {
+ return null;
+ }
+
+ // Find connection where this terminal is source or target
+ var conn = this.connections.find(function(c) {
+ var isSource = String(c.fk_source) === eqId && String(c.source_terminal_id) === termId;
+ var isTarget = String(c.fk_target) === eqId && String(c.target_terminal_id) === termId;
+ return isSource || isTarget;
+ });
+
+ if (conn) {
+ // Return explicit color or derive from connection_type
+ if (conn.color) return conn.color;
+ if (conn.connection_type) return this.getWireColor(conn.connection_type);
+ // Fallback: return a default wire color
+ return '#f1c40f'; // Yellow as default connected color
+ }
+
+ return null; // No connection found
+ },
+
// Get terminal shape SVG based on style setting
getTerminalShape: function(radius, fillColor) {
var style = this.displaySettings.terminalStyle || 'circle';
// Add invisible hit area (larger than visible terminal) for easier clicking
- var hitAreaRadius = radius * 1.4; // 11px hit area - prevents overlap on dense terminals
- var hitArea = '';
+ var hitAreaRadius = 30; // 30px hit area for easy clicking
+ var hitArea = '';
switch (style) {
case 'ring':
@@ -5473,6 +5500,8 @@
// Block drag - track if dragged to distinguish from click
$(document).off('mousedown.blockDrag').on('mousedown.blockDrag', '.schematic-block', function(e) {
+ // Im Zeichenmodus kein Block-Drag
+ if (self.wireDrawMode) return;
if ($(e.target).hasClass('schematic-terminal')) return;
e.preventDefault();
self.blockDragStartPos = { x: e.clientX, y: e.clientY };
@@ -5621,15 +5650,16 @@
return;
}
- // Escape - Close all popups, cancel wire draw mode
+ // Escape - Close all popups, cancel current wire (NOT exit draw mode)
if (e.key === 'Escape') {
e.preventDefault();
// Close all popups
$('.schematic-equipment-popup, .schematic-carrier-popup, .schematic-connection-popup, .schematic-busbar-popup, .schematic-bridge-popup').remove();
- // Cancel wire draw mode
- if (self.wireDrawMode) {
- self.cancelWireDraw();
+ // Cancel current wire drawing only (keep draw mode active)
+ if (self.wireDrawMode && (self.wireDrawSourceEq || self.wireDrawFromJunction)) {
+ self.cleanupWireDrawState(true);
+ self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
}
return;
}
@@ -5859,10 +5889,19 @@
}
});
- // Terminal right-click - show output/cable dialog
+ // Terminal right-click - show output/cable dialog (not in wire draw mode)
$(document).off('contextmenu.terminal').on('contextmenu.terminal', '.schematic-terminal', function(e) {
e.preventDefault();
e.stopPropagation();
+ // Im Zeichenmodus: Rechtsklick bricht nur aktuelle Leitung ab, Modus bleibt
+ if (self.wireDrawMode) {
+ if (self.wireDrawSourceEq) {
+ // Aktuelle Zeichnung abbrechen, Modus bleibt
+ self.cleanupWireDrawState(true);
+ self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
+ }
+ return;
+ }
var $terminal = $(this);
var eqId = $terminal.data('equipment-id');
var termId = $terminal.data('terminal-id');
@@ -5920,20 +5959,24 @@
self.updateWirePreviewCursor(snapped.x, snapped.y);
});
- // Right-click to cancel wire drawing completely
+ // Right-click to cancel current wire drawing (NOT exit draw mode)
$(document).off('contextmenu.wireDraw').on('contextmenu.wireDraw', '.schematic-editor-canvas svg', function(e) {
if (!self.wireDrawMode) return;
+ // Skip if click was on terminal (handled by terminal handler)
+ if ($(e.target).closest('.schematic-terminal').length) return;
e.preventDefault();
if (self.wireDrawSourceEq || self.wireDrawFromJunction) {
- // Cancel entire drawing (from terminal or junction)
- self.cancelWireDrawing();
+ // Cancel current line, keep draw mode active
+ self.cleanupWireDrawState(true);
+ self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
}
});
- // Escape to cancel wire drawing
+ // Escape to cancel current wire (NOT exit draw mode)
$(document).off('keydown.wireDraw').on('keydown.wireDraw', function(e) {
if (e.key === 'Escape' && self.wireDrawMode && (self.wireDrawSourceEq || self.wireDrawFromJunction)) {
- self.cancelWireDrawing();
+ self.cleanupWireDrawState(true);
+ self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
}
});
},
@@ -6699,10 +6742,11 @@
svg += '';
// Layers (order matters: back to front)
+ // Connections BEHIND blocks so wires "go through" blocks visually
svg += '';
+ svg += ''; // Wires behind blocks
svg += '';
svg += ''; // Distribution busbars (Phasenschienen)
- svg += '';
svg += '';
// Connection preview line
@@ -7064,7 +7108,7 @@
// Top terminals - im TE-Raster platziert (hide if busbar covers this equipment or terminal_position)
// Now supports stacked terminals with 'row' property (for Reihenklemmen)
- var terminalColor = '#666'; // Grau wie die Hutschienen
+ var defaultTerminalColor = '#666'; // Grau wie die Hutschienen (wenn keine Verbindung)
var terminalSpacing = 14; // Vertical spacing between stacked terminals
if (showTopTerminals) {
@@ -7085,6 +7129,9 @@
var row = term.row !== undefined ? term.row : rowIdx;
var ty = y - 7 - (row * terminalSpacing);
+ // Get connection color for this terminal (or default gray)
+ var terminalColor = self.getTerminalConnectionColor(eq.id, term.id) || defaultTerminalColor;
+
terminalHtml += '';
@@ -7097,12 +7144,12 @@
if (colTerminals.length > 1) {
// Stacked: place label to the left of the terminal
- terminalHtml += '';
- terminalHtml += '' + labelText + '';
+ terminalHtml += '';
+ terminalHtml += '' + labelText + '';
} else {
// Single: place label below in block
- terminalHtml += '';
- terminalHtml += '' + labelText + '';
+ terminalHtml += '';
+ terminalHtml += '' + labelText + '';
}
terminalHtml += '';
});
@@ -7129,6 +7176,9 @@
var row = term.row !== undefined ? term.row : rowIdx;
var ty = y + blockHeight + 7 + (row * terminalSpacing);
+ // Get connection color for this terminal (or default gray)
+ var terminalColor = self.getTerminalConnectionColor(eq.id, term.id) || defaultTerminalColor;
+
terminalHtml += '';
@@ -7141,12 +7191,12 @@
if (colTerminals.length > 1) {
// Stacked: place label to the right of the terminal
- terminalHtml += '';
- terminalHtml += '' + labelText + '';
+ terminalHtml += '';
+ terminalHtml += '' + labelText + '';
} else {
// Single: place label above in block
- terminalHtml += '';
- terminalHtml += '' + labelText + '';
+ terminalHtml += '';
+ terminalHtml += '' + labelText + '';
}
terminalHtml += '';
});
@@ -9827,10 +9877,10 @@
$btn.addClass('active').css('background', '#27ae60');
this.showMessage('Manueller Zeichenmodus: Klicke Terminal oder Leitung für Startpunkt', 'info');
this.showWireGrid();
- // Highlight all terminals to show they are clickable
- $(this.svgElement).find('.schematic-terminal').css('cursor', 'crosshair');
- // Also highlight connections as clickable for junction
- $(this.svgElement).find('.schematic-connection-hitarea').css('cursor', 'crosshair');
+ // Set crosshair on ENTIRE SVG in draw mode
+ $(this.svgElement).css('cursor', 'crosshair');
+ // Also on all child elements to prevent override
+ $(this.svgElement).find('*').css('cursor', 'inherit');
} else {
$btn.removeClass('active').css('background', '');
this.cancelWireDrawing();
@@ -10608,8 +10658,9 @@
var $btn = $('.schematic-wire-draw-toggle');
$btn.removeClass('active').css('background', '');
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
- $(this.svgElement).find('.schematic-terminal').css('cursor', '');
- $(this.svgElement).find('.schematic-connection-hitarea').css('cursor', '');
+ // Reset SVG and all child cursors
+ $(this.svgElement).css('cursor', '');
+ $(this.svgElement).find('*').css('cursor', '');
} else {
// Keep draw mode active - just reset terminal highlights
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
@@ -11635,8 +11686,9 @@
// Activate wire draw UI
var $btn = $('.schematic-wire-draw-toggle');
$btn.addClass('active').css('background', '#f39c12'); // Orange for extend mode
- $(this.svgElement).find('.schematic-terminal').css('cursor', 'crosshair');
- $(this.svgElement).find('.schematic-connection-hitarea').css('cursor', 'crosshair');
+ // Set crosshair on entire SVG in extend mode
+ $(this.svgElement).css('cursor', 'crosshair');
+ $(this.svgElement).find('*').css('cursor', 'inherit');
// Show start marker at end point
this.showExtendStartMarker(endPoint);
diff --git a/js/kundenkarte_cytoscape.js b/js/kundenkarte_cytoscape.js
old mode 100755
new mode 100644
diff --git a/js/layout-base.js b/js/layout-base.js
old mode 100755
new mode 100644
diff --git a/js/pathfinding.min.js b/js/pathfinding.min.js
old mode 100755
new mode 100644
diff --git a/js/pwa.js b/js/pwa.js
old mode 100755
new mode 100644
index c499cc4..1083fd1
--- a/js/pwa.js
+++ b/js/pwa.js
@@ -36,6 +36,9 @@
offlineQueue: [],
isOnline: navigator.onLine,
+ // Display settings
+ showConnectionLines: false, // Leitungen standardmäßig ausgeblendet
+
// Current modal state
currentCarrierId: null,
editCarrierId: null, // null = Add-Modus, ID = Edit-Modus (Hutschiene)
@@ -186,6 +189,7 @@
// Editor actions
$('#btn-add-panel').on('click', () => openModal('add-panel'));
$('#btn-save-panel').on('click', handleSavePanel);
+ $('#btn-toggle-wires').on('click', handleToggleWires);
$('#editor-content').on('click', '.btn-add-carrier', handleAddCarrier);
$('#editor-content').on('click', '.carrier-header', handleCarrierClick);
@@ -1152,14 +1156,25 @@
}
/**
- * Render SVG connection lines from path_data
- * Only shows connections that were manually drawn on the website
+ * Render SVG connection lines between equipment
+ * PWA uses different layout than desktop, so we calculate positions dynamically
*/
function renderConnectionLines() {
+ // Remove existing SVG overlays first
+ $('.connection-lines-svg').remove();
+
+ // Only render if setting is enabled
+ if (!App.showConnectionLines) {
+ return;
+ }
+
if (!App.connections || App.connections.length === 0) {
return;
}
+ // Desktop reference dimensions
+ const DESKTOP_TE_WIDTH = 56;
+
// Für jede Hutschiene ein SVG-Overlay erstellen
$('.carrier-card').each(function() {
const $carrier = $(this);
@@ -1172,6 +1187,18 @@
const carrierEquipment = App.equipment.filter(e => e.fk_carrier == carrierId);
const equipmentIds = carrierEquipment.map(e => e.id);
+ // Carrier-Daten für Total-TE
+ const carrier = App.carriers.find(c => c.id == carrierId);
+ const totalTe = carrier ? (parseInt(carrier.total_te) || 12) : 12;
+
+ // PWA TE-Breite berechnen
+ const carrierWidth = $content.width();
+ const pwaTeWidth = carrierWidth / (totalTe + 1); // +1 für den Add-Button
+
+ // Scale factor: PWA-Breite / Desktop-Breite
+ const scaleX = pwaTeWidth / DESKTOP_TE_WIDTH;
+ const scaleY = scaleX * 0.8; // Y etwas weniger skalieren (PWA ist kompakter)
+
// Verbindungen filtern die zu dieser Hutschiene gehören
const carrierConnections = App.connections.filter(c =>
equipmentIds.includes(parseInt(c.fk_source)) ||
@@ -1195,16 +1222,88 @@
const color = conn.color || getPhaseColor(conn.connection_type);
+ // Transform path_data coordinates to PWA scale
+ const scaledPath = transformPathData(conn.path_data, scaleX, scaleY);
+
// Schatten-Pfad für bessere Sichtbarkeit
- svgContent += ``;
+ svgContent += ``;
// Hauptpfad
- svgContent += ``;
+ svgContent += ``;
+
+ // Label falls vorhanden
+ if (conn.output_label) {
+ const labelPos = getPathMidpoint(scaledPath);
+ if (labelPos) {
+ const labelWidth = Math.min(conn.output_label.length * 6 + 10, 80);
+ svgContent += ``;
+ svgContent += `${escapeHtml(conn.output_label)}`;
+ }
+ }
});
$svg.html(svgContent);
});
}
+ /**
+ * Transform path data coordinates by scale factors
+ */
+ function transformPathData(pathData, scaleX, scaleY) {
+ if (!pathData) return '';
+
+ // Parse and transform coordinates
+ return pathData.replace(/([ML])\s*([\d.-]+)\s+([\d.-]+)/gi, function(match, cmd, x, y) {
+ const newX = (parseFloat(x) * scaleX).toFixed(1);
+ const newY = (parseFloat(y) * scaleY).toFixed(1);
+ return `${cmd} ${newX} ${newY}`;
+ });
+ }
+
+ /**
+ * Get midpoint of a path for label positioning
+ */
+ function getPathMidpoint(pathData) {
+ if (!pathData) return null;
+
+ const points = [];
+ const regex = /[ML]\s*([\d.-]+)\s+([\d.-]+)/gi;
+ let match;
+
+ while ((match = regex.exec(pathData)) !== null) {
+ points.push({ x: parseFloat(match[1]), y: parseFloat(match[2]) });
+ }
+
+ if (points.length < 2) return null;
+
+ // Calculate midpoint along path
+ let totalLength = 0;
+ const segments = [];
+
+ for (let i = 1; i < points.length; i++) {
+ const dx = points[i].x - points[i-1].x;
+ const dy = points[i].y - points[i-1].y;
+ const len = Math.sqrt(dx*dx + dy*dy);
+ segments.push({ start: points[i-1], end: points[i], length: len });
+ totalLength += len;
+ }
+
+ const halfLength = totalLength / 2;
+ let accumulated = 0;
+
+ for (const seg of segments) {
+ if (accumulated + seg.length >= halfLength) {
+ const t = (halfLength - accumulated) / seg.length;
+ return {
+ x: seg.start.x + t * (seg.end.x - seg.start.x),
+ y: seg.start.y + t * (seg.end.y - seg.start.y)
+ };
+ }
+ accumulated += seg.length;
+ }
+
+ return { x: (points[0].x + points[points.length-1].x) / 2, y: (points[0].y + points[points.length-1].y) / 2 };
+ }
+
function renderTypeGrid() {
const categoryLabels = {
'automat': 'Leitungsschutz',
@@ -1238,6 +1337,27 @@
$('#type-grid').html(html);
}
+ // ============================================
+ // WIRE DISPLAY TOGGLE
+ // ============================================
+
+ function handleToggleWires() {
+ App.showConnectionLines = !App.showConnectionLines;
+
+ // Update button appearance
+ const $btn = $('#btn-toggle-wires');
+ if (App.showConnectionLines) {
+ $btn.addClass('active');
+ $btn.attr('title', 'Leitungen ausblenden');
+ } else {
+ $btn.removeClass('active');
+ $btn.attr('title', 'Leitungen einblenden');
+ }
+
+ // Re-render connection lines
+ renderConnectionLines();
+ }
+
// ============================================
// PANEL (FELD) ACTIONS
// ============================================
diff --git a/kundenkarteindex.php b/kundenkarteindex.php
old mode 100755
new mode 100644
diff --git a/langs/de_DE/kundenkarte.lang b/langs/de_DE/kundenkarte.lang
old mode 100755
new mode 100644
diff --git a/langs/en_US/kundenkarte.lang b/langs/en_US/kundenkarte.lang
old mode 100755
new mode 100644
diff --git a/lib/graph_view.lib.php b/lib/graph_view.lib.php
old mode 100755
new mode 100644
diff --git a/lib/kundenkarte.lib.php b/lib/kundenkarte.lib.php
old mode 100755
new mode 100644
diff --git a/manifest.json b/manifest.json
old mode 100755
new mode 100644
diff --git a/modulebuilder.txt b/modulebuilder.txt
old mode 100755
new mode 100644
diff --git a/pwa.php b/pwa.php
old mode 100755
new mode 100644
index 3686a93..2fa7862
--- a/pwa.php
+++ b/pwa.php
@@ -133,6 +133,9 @@ $themeColor = getDolGlobalString('THEME_ELDY_TOPMENU_BACK1', '#3498db');
0
+
diff --git a/pwa_auth.php b/pwa_auth.php
old mode 100755
new mode 100644
diff --git a/sql/data.sql b/sql/data.sql
old mode 100755
new mode 100644
diff --git a/sql/data_building_types.sql b/sql/data_building_types.sql
old mode 100755
new mode 100644
diff --git a/sql/data_busbar_types.sql b/sql/data_busbar_types.sql
old mode 100755
new mode 100644
diff --git a/sql/data_medium_types.sql b/sql/data_medium_types.sql
old mode 100755
new mode 100644
diff --git a/sql/data_terminal_types.sql b/sql/data_terminal_types.sql
old mode 100755
new mode 100644
diff --git a/sql/dolibarr_allversions.sql b/sql/dolibarr_allversions.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_c_kundenkarte_anlage_system.key.sql b/sql/llx_c_kundenkarte_anlage_system.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_c_kundenkarte_anlage_system.sql b/sql/llx_c_kundenkarte_anlage_system.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage.key.sql b/sql/llx_kundenkarte_anlage.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage.sql b/sql/llx_kundenkarte_anlage.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_connection.key.sql b/sql/llx_kundenkarte_anlage_connection.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_connection.sql b/sql/llx_kundenkarte_anlage_connection.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_contact.sql b/sql/llx_kundenkarte_anlage_contact.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_files.key.sql b/sql/llx_kundenkarte_anlage_files.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_files.sql b/sql/llx_kundenkarte_anlage_files.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_type.key.sql b/sql/llx_kundenkarte_anlage_type.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_type.sql b/sql/llx_kundenkarte_anlage_type.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_type_field.key.sql b/sql/llx_kundenkarte_anlage_type_field.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_anlage_type_field.sql b/sql/llx_kundenkarte_anlage_type_field.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_audit_log.key.sql b/sql/llx_kundenkarte_audit_log.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_audit_log.sql b/sql/llx_kundenkarte_audit_log.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_building_type.key.sql b/sql/llx_kundenkarte_building_type.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_building_type.sql b/sql/llx_kundenkarte_building_type.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_busbar_type.key.sql b/sql/llx_kundenkarte_busbar_type.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_busbar_type.sql b/sql/llx_kundenkarte_busbar_type.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment.key.sql b/sql/llx_kundenkarte_equipment.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment.sql b/sql/llx_kundenkarte_equipment.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_carrier.key.sql b/sql/llx_kundenkarte_equipment_carrier.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_carrier.sql b/sql/llx_kundenkarte_equipment_carrier.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_connection.key.sql b/sql/llx_kundenkarte_equipment_connection.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_connection.sql b/sql/llx_kundenkarte_equipment_connection.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_panel.sql b/sql/llx_kundenkarte_equipment_panel.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_type.key.sql b/sql/llx_kundenkarte_equipment_type.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_type.sql b/sql/llx_kundenkarte_equipment_type.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_type_field.key.sql b/sql/llx_kundenkarte_equipment_type_field.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_equipment_type_field.sql b/sql/llx_kundenkarte_equipment_type_field.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_favorite_products.key.sql b/sql/llx_kundenkarte_favorite_products.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_favorite_products.sql b/sql/llx_kundenkarte_favorite_products.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_favorite_products_contact.sql b/sql/llx_kundenkarte_favorite_products_contact.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_medium_type.key.sql b/sql/llx_kundenkarte_medium_type.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_medium_type.sql b/sql/llx_kundenkarte_medium_type.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_societe_system.key.sql b/sql/llx_kundenkarte_societe_system.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_societe_system.sql b/sql/llx_kundenkarte_societe_system.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_societe_system_contact.sql b/sql/llx_kundenkarte_societe_system_contact.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_terminal_bridge.key.sql b/sql/llx_kundenkarte_terminal_bridge.key.sql
old mode 100755
new mode 100644
diff --git a/sql/llx_kundenkarte_terminal_bridge.sql b/sql/llx_kundenkarte_terminal_bridge.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.0.0.sql b/sql/update_3.0.0.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.1.0.sql b/sql/update_3.1.0.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.2.0.sql b/sql/update_3.2.0.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.3.0.sql b/sql/update_3.3.0.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.3.2.sql b/sql/update_3.3.2.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.4.1.sql b/sql/update_3.4.1.sql
old mode 100755
new mode 100644
diff --git a/sql/update_3.6.0.sql b/sql/update_3.6.0.sql
old mode 100755
new mode 100644
diff --git a/sw.js b/sw.js
index eebc162..e7999bf 100644
--- a/sw.js
+++ b/sw.js
@@ -3,8 +3,8 @@
* Offline-First für Schaltschrank-Dokumentation
*/
-const CACHE_NAME = 'kundenkarte-pwa-v10.0';
-const OFFLINE_CACHE = 'kundenkarte-offline-v10.0';
+const CACHE_NAME = 'kundenkarte-pwa-v11.1';
+const OFFLINE_CACHE = 'kundenkarte-offline-v11.1';
// Statische Assets die immer gecached werden (ohne Query-String)
const STATIC_ASSETS = [
diff --git a/tabs/anlagen.php b/tabs/anlagen.php
old mode 100755
new mode 100644
index 2bee797..cdf005d
--- a/tabs/anlagen.php
+++ b/tabs/anlagen.php
@@ -781,6 +781,9 @@ if (empty($customerSystems)) {
print '
';
+ print '
';
print '
';
@@ -792,6 +795,10 @@ if (empty($customerSystems)) {
print '
';
+ // Display Settings button
+ print '
';
// PDF Export button
$pdfExportUrl = dol_buildpath('/kundenkarte/ajax/export_schematic_pdf.php', 1).'?anlage_id='.$anlageId.'&format=A4&orientation=L';
print '
';
diff --git a/tabs/contact_anlagen.php b/tabs/contact_anlagen.php
old mode 100755
new mode 100644
index 630f70a..fdbabd2
--- a/tabs/contact_anlagen.php
+++ b/tabs/contact_anlagen.php
@@ -779,6 +779,9 @@ if (empty($customerSystems)) {
print '';
+ print '';
print '';
@@ -790,6 +793,10 @@ if (empty($customerSystems)) {
print '';
+ // Display Settings button
+ print '';
// PDF Export button
$pdfExportUrl = dol_buildpath('/kundenkarte/ajax/export_schematic_pdf.php', 1).'?anlage_id='.$anlageId.'&format=A4&orientation=L';
print '';
diff --git a/tabs/contact_favoriteproducts.php b/tabs/contact_favoriteproducts.php
old mode 100755
new mode 100644
diff --git a/tabs/favoriteproducts.php b/tabs/favoriteproducts.php
old mode 100755
new mode 100644