Tutorial: Formular Feld fuer Feld erklaeren + Klicks blockieren

Formular-Steps komplett ueberarbeitet (Steps 2-9):
- Step 3: Titel + Beschreibung mit Tipp-Animation
- Step 4: Art der Lage (Live vs Recherche) mit Cursor-Demo + Erklaerung
- Step 5: Quellen (International + Telegram) einzeln gehighlightet + erklaert
- Step 6: Sichtbarkeit (Oeffentlich/Privat) mit Toggle-Demo
- Step 7: Aktualisierung + Intervall, Hinweis auf Creditverbrauch
- Step 8: Aufbewahrung erklaert
- Step 9: E-Mail-Benachrichtigungen (alle 3 Optionen einzeln gehighlightet)

Jedes Feld wird mit Cursor angesteuert, gehighlightet und erklaert.
Modal-Body scrollt automatisch zu den jeweiligen Feldern.

Klick-Blockierung: Waehrend des Tutorials sind alle Dashboard-Elemente
nicht anklickbar (pointer-events:none auf body.tutorial-active).
Nur die Tutorial-Bubble mit Navigation bleibt bedienbar.

Duplikate der alten Methoden entfernt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Dev
2026-03-16 16:05:17 +01:00
Ursprung 37d7addd5b
Commit 6d09c0a5fa
3 geänderte Dateien mit 579 neuen und 425 gelöschten Zeilen

Datei anzeigen

@@ -5228,3 +5228,17 @@ a.map-popup-article:hover {
.chat-tutorial-hint-close:hover {
color: var(--text-primary);
}
/* Tutorial: Klicks auf Dashboard blockieren */
body.tutorial-active .dashboard,
body.tutorial-active .modal-overlay,
body.tutorial-active .chat-toggle-btn,
body.tutorial-active #chat-window {
pointer-events: none !important;
}
/* Bubble und Cursor bleiben klickbar */
body.tutorial-active .tutorial-bubble,
body.tutorial-active .tutorial-cursor {
pointer-events: auto !important;
}

Datei anzeigen

@@ -17,7 +17,7 @@
<link rel="stylesheet" href="/static/vendor/MarkerCluster.css">
<link rel="stylesheet" href="/static/vendor/MarkerCluster.Default.css">
<link rel="stylesheet" href="/static/css/network.css?v=20260316a">
<link rel="stylesheet" href="/static/css/style.css?v=20260316e">
<link rel="stylesheet" href="/static/css/style.css?v=20260316f">
</head>
<body>
<a href="#main-content" class="skip-link">Zum Hauptinhalt springen</a>
@@ -764,7 +764,7 @@
<script src="/static/js/api_network.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/tutorial.js?v=20260316g"></script>
<script src="/static/js/tutorial.js?v=20260316h"></script>
<script src="/static/js/chat.js?v=20260316f"></script>
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>

Datei anzeigen

@@ -460,14 +460,13 @@ const Tutorial = {
id: 'new-incident-btn',
target: '#new-incident-btn',
title: 'Neue Lage anlegen',
text: 'Mit diesem Button erstellen Sie eine neue Lage. Wir simulieren jetzt die Eingabe f\u00fcr Sie.',
text: 'Mit diesem Button öffnen Sie das Formular zur Erstellung einer neuen Lage. '
+ 'Wir gehen jetzt gemeinsam alle Felder durch.',
position: 'right',
onEnter: function() {
Tutorial._stepTimeout(function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) {
overlay.classList.add('active');
}
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
}, 1500);
},
onExit: function() {
@@ -475,51 +474,45 @@ const Tutorial = {
if (overlay) overlay.classList.remove('active');
},
},
// 3 - Formular ausf\u00fcllen (Cursor-Demo)
// 3 - Titel und Beschreibung (Cursor-Demo)
{
id: 'new-incident-modal',
id: 'form-title-desc',
target: '#modal-new .modal',
title: 'Lage konfigurieren',
text: 'Beobachten Sie, wie das Formular Schritt f\u00fcr Schritt ausgef\u00fcllt wird. '
+ 'So legen Sie eine neue Lage an.',
title: 'Titel und Beschreibung',
text: 'Geben Sie einen aussagekräftigen <strong>Titel</strong> ein, der das Ereignis klar beschreibt. '
+ 'Die <strong>Beschreibung</strong> liefert zusätzlichen Kontext für die Recherche.<br><br>'
+ 'Beobachten Sie die Eingabe:',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) {
overlay.classList.add('active');
}
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
// Formular zuruecksetzen
var modalBody = document.querySelector('#modal-new .modal-body');
if (modalBody) modalBody.scrollTop = 0;
var t = document.getElementById('inc-title'); if (t) t.value = '';
var d = document.getElementById('inc-description'); if (d) d.value = '';
var r = document.getElementById('inc-refresh-mode'); if (r) { r.value = 'manual'; try { r.dispatchEvent(new Event('change')); } catch(e) {} }
Tutorial._simulateFormFill();
Tutorial._simulateFormTitleDesc();
},
onExit: function() {
// Werte stehen lassen (werden in stop() aufgeraeumt)
Tutorial._clearSubHighlights();
},
},
// 4 - Lage-Typ: Live vs Recherche (mit Cursor-Demo)
// 4 - Art der Lage (Cursor-Demo)
{
id: 'incident-type',
id: 'form-type',
target: '#modal-new .modal',
title: 'Live-Monitoring vs. Recherche',
text: '<strong>Live-Monitoring</strong> beobachtet ein Ereignis in Echtzeit. '
+ 'Hunderte Nachrichtenquellen werden automatisch durchsucht. '
+ 'Ideal f\u00fcr aktuelle Vorf\u00e4lle, Krisen oder sich entwickelnde Lagen.<br><br>'
+ '<strong>Analyse/Recherche</strong> untersucht ein Thema tiefergehend. '
+ 'Keine automatischen Updates, stattdessen gezielte Recherche mit eigenen Suchbegriffen. '
+ 'Ideal f\u00fcr Hintergrundanalysen und Lageberichte.',
title: 'Art der Lage',
text: '<strong>Live-Monitoring</strong> beobachtet ein Ereignis in Echtzeit. Hunderte Quellen werden '
+ 'laufend durchsucht. Ideal für aktuelle Krisen und sich entwickelnde Lagen.<br><br>'
+ '<strong>Analyse/Recherche</strong> untersucht ein Thema tiefergehend ohne automatische Updates. '
+ 'Ideal für Hintergrundanalysen und Lageberichte.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) {
overlay.classList.add('active');
}
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
// Modal-Body nach oben scrollen zum Typ-Feld
var modalBody = document.querySelector('#modal-new .modal-body');
if (modalBody) modalBody.scrollTo({ top: 0, behavior: 'smooth' });
Tutorial._stepTimeout(function() {
@@ -527,19 +520,124 @@ const Tutorial = {
Tutorial._simulateTypeSwitch();
}, 500);
},
onExit: function() {
var sel = document.getElementById('inc-type');
if (sel) { sel.value = 'adhoc'; try { sel.dispatchEvent(new Event('change')); } catch(e) {} }
Tutorial._clearSubHighlights();
},
},
// 5 - Quellen
{
id: 'form-sources',
target: '#modal-new .modal',
title: 'Quellen konfigurieren',
text: '<strong>Internationale Quellen</strong> bezieht englischsprachige und internationale Medien '
+ 'ein (Reuters, BBC, Al Jazeera etc.). Erhöht die Abdeckung, aber auch den Analyseumfang.<br><br>'
+ '<strong>Telegram-Kanäle</strong> liefern oft frühzeitige OSINT-Informationen, '
+ 'können aber auch unbestätigte Meldungen enthalten. Für sensible Lagen empfohlen.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
Tutorial._simulateFormSources();
},
onExit: function() {
Tutorial._clearSubHighlights();
},
},
// 6 - Sichtbarkeit
{
id: 'form-visibility',
target: '#modal-new .modal',
title: 'Sichtbarkeit',
text: '<strong>Öffentlich</strong> bedeutet, dass alle Nutzer Ihrer Organisation diese Lage sehen '
+ 'und darauf zugreifen können.<br><br>'
+ '<strong>Privat</strong> macht die Lage nur für Sie persönlich sichtbar. '
+ 'Nützlich für persönliche Recherchen oder sensible Vorgänge.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
Tutorial._simulateFormVisibility();
},
onExit: function() {
Tutorial._clearSubHighlights();
},
},
// 7 - Aktualisierung und Intervall
{
id: 'form-refresh',
target: '#modal-new .modal',
title: 'Aktualisierung',
text: '<strong>Manuell</strong>: Sie starten Aktualisierungen selbst per Button.<br>'
+ '<strong>Automatisch</strong>: Der Monitor aktualisiert im eingestellten Intervall.<br><br>'
+ '<strong>Wichtig:</strong> Kürzere Intervalle liefern aktuellere Daten, '
+ 'erhöhen aber den Creditverbrauch. Für die meisten Lagen sind 15 bis 30 Minuten ein guter Richtwert.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
Tutorial._simulateFormRefresh();
},
onExit: function() {
Tutorial._clearSubHighlights();
},
},
// 8 - Aufbewahrung
{
id: 'form-retention',
target: '#modal-new .modal',
title: 'Aufbewahrung',
text: 'Legen Sie fest, wie lange die Lage aktiv bleibt. Nach Ablauf der Frist '
+ 'wird sie automatisch ins <strong>Archiv</strong> verschoben.<br><br>'
+ 'Setzen Sie den Wert auf <strong>0</strong> für unbegrenzte Aufbewahrung. '
+ 'Standard sind 30 Tage.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
Tutorial._simulateFormRetention();
},
onExit: function() {
Tutorial._clearSubHighlights();
},
},
// 9 - E-Mail-Benachrichtigungen
{
id: 'form-notifications',
target: '#modal-new .modal',
title: 'E-Mail-Benachrichtigungen',
text: 'Lassen Sie sich per E-Mail informieren bei:<br><br>'
+ '<strong>Neues Lagebild</strong> - Wenn eine aktualisierte Zusammenfassung vorliegt<br>'
+ '<strong>Neue Artikel</strong> - Wenn neue Quellen gefunden werden<br>'
+ '<strong>Statusänderung Faktencheck</strong> - Wenn sich die Bewertung einer Behauptung ändert<br><br>'
+ 'So bleiben Sie auch ohne ständiges Einloggen auf dem Laufenden.',
position: 'left',
disableNav: true,
onEnter: function() {
var overlay = document.getElementById('modal-new');
if (overlay && !overlay.classList.contains('active')) overlay.classList.add('active');
if (overlay) overlay.style.zIndex = '9002';
Tutorial._simulateFormNotifications();
},
onExit: function() {
var overlay = document.getElementById('modal-new');
if (overlay) {
overlay.classList.remove('active');
overlay.style.zIndex = '';
}
// Select zur\u00fccksetzen
var sel = document.getElementById('inc-type');
if (sel) { sel.value = 'adhoc'; sel.dispatchEvent(new Event('change')); }
Tutorial._clearSubHighlights();
},
},
// 5 - Sidebar Filter
// 5 - Sidebar Filter
{
id: 'sidebar-filters',
target: '.sidebar-filter',
@@ -905,8 +1003,9 @@ const Tutorial = {
// Chat schließen falls offen
if (typeof Chat !== 'undefined' && Chat._isOpen) Chat.close();
// Overlay einblenden
// Overlay einblenden + Klicks blockieren
this._els.overlay.classList.add('active');
document.body.classList.add('tutorial-active');
// Keyboard
this._keyHandler = this._onKey.bind(this);
@@ -929,8 +1028,9 @@ const Tutorial = {
this._currentStep = -1;
this._demoRunning = false;
// Overlay ausblenden
// Overlay ausblenden + Klicks freigeben
this._els.overlay.classList.remove('active');
document.body.classList.remove('tutorial-active');
this._els.spotlight.style.opacity = '0';
this._els.bubble.classList.remove('visible');
this._hideCursor();
@@ -1307,146 +1407,117 @@ const Tutorial = {
});
},
// -----------------------------------------------------------------------
// Formular-Ausf\u00fcll-Demo (Step 3)
// -----------------------------------------------------------------------
async _simulateFormFill() {
this._demoRunning = true;
// Helfer: Cursor zu einem Element bewegen
async _cursorToElement(selector, fromX, fromY) {
var el = document.querySelector(selector);
if (!el) return { x: fromX, y: fromY };
var rect = el.getBoundingClientRect();
var tx = rect.left + Math.min(rect.width / 2, 60);
var ty = rect.top + rect.height / 2;
if (fromX !== undefined && fromY !== undefined) {
await this._animateCursor(fromX, fromY, tx, ty, 500);
} else {
this._showCursor(tx, ty, 'default');
}
await this._wait(200);
return { x: tx, y: ty };
},
// Helfer: Modal-Body zu einem Element scrollen
_scrollModalTo(selector) {
var el = document.querySelector(selector);
var modalBody = document.querySelector('#modal-new .modal-body');
if (!el || !modalBody) return;
var elTop = el.offsetTop - modalBody.offsetTop;
modalBody.scrollTo({ top: Math.max(0, elTop - 20), behavior: 'smooth' });
},
// -----------------------------------------------------------------------
// Step 3: Titel + Beschreibung
// -----------------------------------------------------------------------
async _simulateFormTitleDesc() {
this._demoRunning = true;
var titleInput = document.getElementById('inc-title');
var descInput = document.getElementById('inc-description');
var refreshSelect = document.getElementById('inc-refresh-mode');
var modal = document.querySelector('#modal-new .modal');
if (!titleInput) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
if (!titleInput || !modal) {
this._demoRunning = false;
this._enableNavAfterDemo();
return;
}
// Modal-Body scrollen wir nach oben
var modalBody = modal.querySelector('.modal-body');
if (modalBody) modalBody.scrollTop = 0;
// 1. Cursor zum Titel-Feld
var titleRect = titleInput.getBoundingClientRect();
var startX = titleRect.left - 60;
var startY = titleRect.top - 40;
this._showCursor(startX, startY, 'default');
await this._wait(300);
await this._animateCursor(startX, startY, titleRect.left + 20, titleRect.top + titleRect.height / 2, 600);
await this._wait(200);
// Fokus + Tippen
titleInput.focus();
// Cursor zum Titel
this._highlightSub('#inc-title');
var pos = await this._cursorToElement('#inc-title');
titleInput.focus();
await this._simulateTyping(titleInput, 'Explosion in Hamburger Hafen', 1200);
await this._wait(500);
await this._wait(400);
this._clearSubHighlights();
// 2. Cursor zur Beschreibung
// Cursor zur Beschreibung
if (descInput) {
var descRect = descInput.getBoundingClientRect();
await this._animateCursor(titleRect.left + 20, titleRect.top + titleRect.height / 2, descRect.left + 20, descRect.top + 12, 500);
await this._wait(200);
descInput.focus();
this._highlightSub('#inc-description');
await this._simulateTyping(descInput, 'Schwere Explosion im Hafengebiet', 1000);
await this._wait(500);
pos = await this._cursorToElement('#inc-description', pos.x, pos.y);
descInput.focus();
await this._simulateTyping(descInput, 'Schwere Explosion im Hafengebiet, Burchardkai-Terminal', 1200);
await this._wait(400);
this._clearSubHighlights();
}
// 3. Modal-Body runterscrollen zum Refresh-Feld
if (refreshSelect && modalBody) {
// Sanft scrollen
modalBody.scrollTo({ top: modalBody.scrollHeight, behavior: 'smooth' });
await this._wait(600);
var refRect = refreshSelect.getBoundingClientRect();
var prevRect = descInput ? descInput.getBoundingClientRect() : titleRect;
await this._animateCursor(prevRect.left + 20, prevRect.top + 12, refRect.left + refRect.width / 2, refRect.top + refRect.height / 2, 600);
await this._wait(200);
this._highlightSub('#inc-refresh-mode');
refreshSelect.value = 'auto';
try { refreshSelect.dispatchEvent(new Event('change')); } catch(e) {}
await this._wait(1200);
this._clearSubHighlights();
}
// 4. Cursor verschwindet
this._hideCursor();
await this._wait(300);
this._demoRunning = false;
this._enableNavAfterDemo();
},
// -----------------------------------------------------------------------
// Typ-Wechsel-Demo (Step 4)
// Step 4: Art der Lage (Typ-Wechsel)
// -----------------------------------------------------------------------
async _simulateTypeSwitch() {
this._demoRunning = true;
var sel = document.getElementById('inc-type');
if (!sel) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
var rect = sel.getBoundingClientRect();
var targetX = rect.left + rect.width / 2;
var targetY = rect.top + rect.height / 2;
// 1. Cursor erscheint oben links im Modal, f\u00e4hrt zum Select
var startX = rect.left - 80;
var startY = rect.top - 60;
this._showCursor(startX, startY, 'default');
await this._wait(400);
await this._animateCursor(startX, startY, targetX, targetY, 800);
var pos = await this._cursorToElement('#inc-type');
await this._wait(300);
// 2. Klick - wechselt zu Recherche
// Wechsel zu Recherche
sel.value = 'research';
sel.dispatchEvent(new Event('change'));
this._highlightSub('#inc-type');
await this._wait(2000);
// 3. Zur\u00fcck zu Live-Monitoring
// Zur\u00fcck zu Live-Monitoring
sel.value = 'adhoc';
sel.dispatchEvent(new Event('change'));
await this._wait(1000);
await this._wait(800);
// 4. Cursor verschwindet
this._hideCursor();
this._demoRunning = false;
this._enableNavAfterDemo();
},
// -----------------------------------------------------------------------
// Drag-Demo
// Step 5: Quellen (International + Telegram toggles)
// -----------------------------------------------------------------------
async _simulateDrag() {
async _simulateFormSources() {
this._demoRunning = true;
var el = document.querySelector('[gs-id="lagebild"] .card-header');
if (!el) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
this._scrollModalTo('#inc-international');
await this._wait(400);
var rect = el.getBoundingClientRect();
var startX = rect.left + rect.width / 2;
var startY = rect.top + rect.height / 2;
var endX = startX + 200;
var endY = startY;
// International-Toggle highlighten
var intlCheckbox = document.getElementById('inc-international');
var intlLabel = intlCheckbox ? intlCheckbox.closest('.toggle-label') : null;
if (intlLabel) {
this._highlightSub('#inc-international');
var pos = await this._cursorToElement('#inc-international');
await this._wait(1500);
this._clearSubHighlights();
this._showCursor(startX, startY, 'default');
await this._wait(500);
this._els.cursor.classList.remove('tutorial-cursor-default');
this._els.cursor.classList.add('tutorial-cursor-grabbing');
await this._wait(300);
await this._animateCursor(startX, startY, endX, endY, 1500);
await this._wait(200);
this._els.cursor.classList.remove('tutorial-cursor-grabbing');
this._els.cursor.classList.add('tutorial-cursor-default');
await this._animateCursor(endX, endY, startX, startY, 800);
await this._wait(300);
// Telegram-Toggle
var telegramCheckbox = document.getElementById('inc-telegram');
if (telegramCheckbox) {
this._highlightSub('#inc-telegram');
pos = await this._cursorToElement('#inc-telegram', pos.x, pos.y);
// Aktivieren
telegramCheckbox.checked = true;
await this._wait(1500);
this._clearSubHighlights();
}
}
this._hideCursor();
this._demoRunning = false;
@@ -1454,52 +1525,121 @@ const Tutorial = {
},
// -----------------------------------------------------------------------
// Resize-Demo
// Step 6: Sichtbarkeit
// -----------------------------------------------------------------------
async _simulateResize() {
async _simulateFormVisibility() {
this._demoRunning = true;
var el = document.querySelector('[gs-id="faktencheck"]');
if (!el) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
this._scrollModalTo('#inc-visibility');
await this._wait(400);
var rect = el.getBoundingClientRect();
var startX = rect.right - 4;
var startY = rect.bottom - 4;
var endX = startX + 100;
var endY = startY + 60;
var checkbox = document.getElementById('inc-visibility');
if (checkbox) {
this._highlightSub('#inc-visibility');
var pos = await this._cursorToElement('#inc-visibility');
await this._wait(1000);
this._showCursor(startX, startY, 'resize');
await this._wait(500);
// Umschalten auf Privat
checkbox.checked = false;
var textEl = document.getElementById('visibility-text');
if (textEl) textEl.textContent = 'Privat \u2014 nur f\u00fcr dich sichtbar';
await this._wait(1500);
await this._animateCursor(startX, startY, endX, endY, 1200);
await this._wait(200);
await this._animateCursor(endX, endY, startX, startY, 800);
await this._wait(300);
// Zur\u00fcck auf \u00d6ffentlich
checkbox.checked = true;
if (textEl) textEl.textContent = '\u00d6ffentlich \u2014 f\u00fcr alle Nutzer sichtbar';
await this._wait(800);
this._clearSubHighlights();
}
this._hideCursor();
this._demoRunning = false;
this._enableNavAfterDemo();
},
_enableNavAfterDemo() {
var bubble = this._els.bubble;
var nav = bubble.querySelector('.tutorial-bubble-nav');
if (!nav) return;
var index = this._currentStep;
var total = this._steps.length;
// -----------------------------------------------------------------------
// Step 7: Aktualisierung + Intervall
// -----------------------------------------------------------------------
async _simulateFormRefresh() {
this._demoRunning = true;
this._scrollModalTo('#inc-refresh-mode');
await this._wait(400);
var navHtml = '';
if (index > 0) {
navHtml += '<button class="tutorial-btn tutorial-btn-back" onclick="Tutorial.prev()">Zurück</button>';
} else {
navHtml += '<span></span>';
var refreshSelect = document.getElementById('inc-refresh-mode');
if (refreshSelect) {
this._highlightSub('#inc-refresh-mode');
var pos = await this._cursorToElement('#inc-refresh-mode');
await this._wait(800);
// Auf Auto wechseln
refreshSelect.value = 'auto';
try { refreshSelect.dispatchEvent(new Event('change')); } catch(e) {}
await this._wait(1000);
this._clearSubHighlights();
// Intervall-Feld highlighten
var intervalField = document.getElementById('refresh-interval-field');
var intervalInput = document.getElementById('inc-refresh-value');
if (intervalField && intervalInput) {
this._highlightSub('#inc-refresh-value');
pos = await this._cursorToElement('#inc-refresh-value', pos.x, pos.y);
await this._wait(1500);
this._clearSubHighlights();
}
}
if (index < total - 1) {
navHtml += '<button class="tutorial-btn tutorial-btn-next" onclick="Tutorial.next()">Weiter</button>';
} else {
navHtml += '<button class="tutorial-btn tutorial-btn-next" onclick="Tutorial.stop()">Fertig</button>';
this._hideCursor();
this._demoRunning = false;
this._enableNavAfterDemo();
},
// -----------------------------------------------------------------------
// Step 8: Aufbewahrung
// -----------------------------------------------------------------------
async _simulateFormRetention() {
this._demoRunning = true;
this._scrollModalTo('#inc-retention');
await this._wait(400);
var retentionInput = document.getElementById('inc-retention');
if (retentionInput) {
this._highlightSub('#inc-retention');
var pos = await this._cursorToElement('#inc-retention');
await this._wait(2000);
this._clearSubHighlights();
}
nav.innerHTML = navHtml;
this._hideCursor();
this._demoRunning = false;
this._enableNavAfterDemo();
},
// -----------------------------------------------------------------------
// Step 9: E-Mail-Benachrichtigungen
// -----------------------------------------------------------------------
async _simulateFormNotifications() {
this._demoRunning = true;
this._scrollModalTo('#inc-notify-summary');
await this._wait(400);
var checks = ['#inc-notify-summary', '#inc-notify-new-articles', '#inc-notify-status-change'];
var pos;
for (var i = 0; i < checks.length; i++) {
var cb = document.querySelector(checks[i]);
if (!cb) continue;
this._highlightSub(checks[i]);
if (pos) {
pos = await this._cursorToElement(checks[i], pos.x, pos.y);
} else {
pos = await this._cursorToElement(checks[i]);
}
cb.checked = true;
await this._wait(1000);
this._clearSubHighlights();
}
this._hideCursor();
this._demoRunning = false;
this._enableNavAfterDemo();
},
// -----------------------------------------------------------------------