Tutorial: Modals sauber schliessen bei Zurueck-Navigation und Abbruch

- _stepTimeout() ersetzt setTimeout in onEnter-Callbacks: Wird beim
  Step-Wechsel automatisch gecancelt, kein verspaetetes Modal-Oeffnen mehr
- _exitStep() raeumt alle Step-Timer auf bevor onExit laeuft
- stop() schliesst alle Modals (modal-new, modal-sources) und setzt
  Formular-Inputs zurueck
- Sources-Button-Step hat jetzt onExit zum Modal-Schliessen
- Behebt: Modal bleibt offen bei Zurueck-Klick, Modal erscheint erneut
  nach Zurueck-Navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Dev
2026-03-16 15:22:57 +01:00
Ursprung be43b0ffcf
Commit 1ea62ba901
2 geänderte Dateien mit 44 neuen und 3 gelöschten Zeilen

Datei anzeigen

@@ -764,7 +764,7 @@
<script src="/static/js/api_network.js?v=20260316a"></script> <script src="/static/js/api_network.js?v=20260316a"></script>
<script src="/static/js/network-graph.js?v=20260316a"></script> <script src="/static/js/network-graph.js?v=20260316a"></script>
<script src="/static/js/app_network.js?v=20260316a"></script> <script src="/static/js/app_network.js?v=20260316a"></script>
<script src="/static/js/tutorial.js?v=20260316e"></script> <script src="/static/js/tutorial.js?v=20260316f"></script>
<script src="/static/js/chat.js?v=20260316f"></script> <script src="/static/js/chat.js?v=20260316f"></script>
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script> <script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>

Datei anzeigen

@@ -11,6 +11,7 @@ const Tutorial = {
_keyHandler: null, _keyHandler: null,
_resizeHandler: null, _resizeHandler: null,
_demoRunning: false, _demoRunning: false,
_stepTimers: [], // setTimeout-IDs fuer den aktuellen Step
_savedState: null, // Dashboard-Zustand vor dem Tutorial _savedState: null, // Dashboard-Zustand vor dem Tutorial
// DOM-Referenzen // DOM-Referenzen
@@ -397,6 +398,18 @@ const Tutorial = {
_cleanupFns: [], _cleanupFns: [],
// Timer-Helfer: Timeouts die beim Step-Wechsel automatisch gecancelt werden
_stepTimeout(fn, ms) {
var id = setTimeout(fn, ms);
this._stepTimers.push(id);
return id;
},
_clearStepTimers() {
this._stepTimers.forEach(function(id) { clearTimeout(id); });
this._stepTimers = [];
},
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Scroll-Helfer: Element in den sichtbaren Bereich scrollen // Scroll-Helfer: Element in den sichtbaren Bereich scrollen
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@@ -450,7 +463,7 @@ const Tutorial = {
text: 'Hier starten Sie die Erstellung einer neuen Lage. Im nächsten Schritt zeigen wir Ihnen das Formular dazu.', text: 'Hier starten Sie die Erstellung einer neuen Lage. Im nächsten Schritt zeigen wir Ihnen das Formular dazu.',
position: 'right', position: 'right',
onEnter: function() { onEnter: function() {
setTimeout(function() { Tutorial._stepTimeout(function() {
var overlay = document.getElementById('modal-new'); var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) { if (overlay && !overlay.classList.contains('active')) {
overlay.classList.add('active'); overlay.classList.add('active');
@@ -813,7 +826,7 @@ const Tutorial = {
+ '<strong>Quellen deaktivieren</strong> - Temporär oder dauerhaft ausschließen', + '<strong>Quellen deaktivieren</strong> - Temporär oder dauerhaft ausschließen',
position: 'right', position: 'right',
onEnter: function() { onEnter: function() {
setTimeout(function() { Tutorial._stepTimeout(function() {
var overlay = document.getElementById('modal-sources'); var overlay = document.getElementById('modal-sources');
if (overlay && !overlay.classList.contains('active')) { if (overlay && !overlay.classList.contains('active')) {
if (typeof App !== 'undefined' && App.openSourceManagement) { if (typeof App !== 'undefined' && App.openSourceManagement) {
@@ -822,6 +835,13 @@ const Tutorial = {
} }
}, 1500); }, 1500);
}, },
onExit: function() {
var overlay = document.getElementById('modal-sources');
if (overlay) {
overlay.classList.remove('active');
overlay.style.zIndex = '';
}
},
}, },
// 22 - Quellen Modal // 22 - Quellen Modal
{ {
@@ -923,10 +943,30 @@ const Tutorial = {
this._hideCursor(); this._hideCursor();
this._clearSubHighlights(); this._clearSubHighlights();
// Step-Timers canceln
this._clearStepTimers();
// Alle Modals schliessen die das Tutorial geoeffnet haben koennte
['modal-new', 'modal-sources'].forEach(function(id) {
var overlay = document.getElementById(id);
if (overlay) {
overlay.classList.remove('active');
overlay.style.zIndex = '';
}
});
// Cleanup-Callbacks // Cleanup-Callbacks
this._cleanupFns.forEach(function(fn) { try { fn(); } catch(e) {} }); this._cleanupFns.forEach(function(fn) { try { fn(); } catch(e) {} });
this._cleanupFns = []; this._cleanupFns = [];
// Formular-Inputs zuruecksetzen
var titleInput = document.getElementById('inc-title');
if (titleInput) titleInput.value = '';
var descInput = document.getElementById('inc-description');
if (descInput) descInput.value = '';
var selType = document.getElementById('inc-type');
if (selType) { selType.value = 'adhoc'; try { selType.dispatchEvent(new Event('change')); } catch(e) {} }
// Demo-View entfernen // Demo-View entfernen
this._removeDemoView(); this._removeDemoView();
@@ -996,6 +1036,7 @@ const Tutorial = {
_exitStep(i) { _exitStep(i) {
var step = this._steps[i]; var step = this._steps[i];
this._clearStepTimers();
if (step.onExit) { if (step.onExit) {
step.onExit(); step.onExit();
} }