Tutorial: Formular live mit Cursor ausfuellen statt statisch vorab
Step 3 ist jetzt eine interaktive Demo: - Cursor faehrt zum Titel-Feld, tippt "Explosion in Hamburger Hafen" Zeichen fuer Zeichen ein - Cursor wechselt zur Beschreibung, tippt Kurztext - Modal scrollt nach unten, Cursor wechselt Aktualisierung auf Auto - Jedes Feld wird beim Ausfuellen gehighlightet - _simulateTyping(): Neue Helfer-Methode fuer Zeichen-fuer-Zeichen-Eingabe - Step 4 (Typ-Wechsel) scrollt Modal zurueck nach oben zum Typ-Feld Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -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=20260316f"></script>
|
||||
<script src="/static/js/tutorial.js?v=20260316g"></script>
|
||||
<script src="/static/js/chat.js?v=20260316f"></script>
|
||||
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>
|
||||
|
||||
|
||||
@@ -460,7 +460,7 @@ const Tutorial = {
|
||||
id: 'new-incident-btn',
|
||||
target: '#new-incident-btn',
|
||||
title: 'Neue Lage anlegen',
|
||||
text: 'Hier starten Sie die Erstellung einer neuen Lage. Im nächsten Schritt zeigen wir Ihnen das Formular dazu.',
|
||||
text: 'Mit diesem Button erstellen Sie eine neue Lage. Wir simulieren jetzt die Eingabe f\u00fcr Sie.',
|
||||
position: 'right',
|
||||
onEnter: function() {
|
||||
Tutorial._stepTimeout(function() {
|
||||
@@ -475,41 +475,29 @@ const Tutorial = {
|
||||
if (overlay) overlay.classList.remove('active');
|
||||
},
|
||||
},
|
||||
// 3 - Neue Lage Modal: Überblick
|
||||
// 3 - Formular ausf\u00fcllen (Cursor-Demo)
|
||||
{
|
||||
id: 'new-incident-modal',
|
||||
target: '#modal-new .modal',
|
||||
title: 'Lage konfigurieren',
|
||||
text: 'Das Formular zur Lage-Erstellung. Hier legen Sie fest:<br><br>'
|
||||
+ '<strong>Titel</strong> - Kurze Bezeichnung des Vorfalls<br>'
|
||||
+ '<strong>Beschreibung</strong> - Kontext und Hintergrundinformationen<br>'
|
||||
+ '<strong>Art der Lage</strong> - Live-Monitoring oder Analyse/Recherche<br>'
|
||||
+ '<strong>Quellen</strong> - Internationale und Telegram-Quellen ein/aus<br>'
|
||||
+ '<strong>Sichtbarkeit</strong> - Öffentlich oder privat für Ihr Team<br>'
|
||||
+ '<strong>Aktualisierung</strong> - Manuell oder automatisch mit Intervall',
|
||||
text: 'Beobachten Sie, wie das Formular Schritt f\u00fcr Schritt ausgef\u00fcllt wird. '
|
||||
+ 'So legen Sie eine neue Lage an.',
|
||||
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';
|
||||
// Demo: Titel vorausfüllen
|
||||
var titleInput = document.getElementById('inc-title');
|
||||
if (titleInput) titleInput.value = 'Explosion in Hamburger Hafen';
|
||||
var descInput = document.getElementById('inc-description');
|
||||
if (descInput) descInput.value = 'Schwere Explosion im Hamburger Hafengebiet, Burchardkai-Terminal';
|
||||
// Formular zuruecksetzen
|
||||
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();
|
||||
},
|
||||
onExit: function() {
|
||||
var overlay = document.getElementById('modal-new');
|
||||
if (overlay) {
|
||||
overlay.classList.remove('active');
|
||||
overlay.style.zIndex = '';
|
||||
}
|
||||
var titleInput = document.getElementById('inc-title');
|
||||
if (titleInput) titleInput.value = '';
|
||||
var descInput = document.getElementById('inc-description');
|
||||
if (descInput) descInput.value = '';
|
||||
// Werte stehen lassen (werden in stop() aufgeraeumt)
|
||||
},
|
||||
},
|
||||
// 4 - Lage-Typ: Live vs Recherche (mit Cursor-Demo)
|
||||
@@ -531,8 +519,13 @@ const Tutorial = {
|
||||
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() {
|
||||
Tutorial._highlightSub('#inc-type');
|
||||
Tutorial._simulateTypeSwitch();
|
||||
}, 500);
|
||||
},
|
||||
onExit: function() {
|
||||
var overlay = document.getElementById('modal-new');
|
||||
@@ -1295,6 +1288,100 @@ const Tutorial = {
|
||||
this._enableNavAfterDemo();
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Tipp-Simulation: Text Zeichen fuer Zeichen eingeben
|
||||
// -----------------------------------------------------------------------
|
||||
_simulateTyping(input, text, ms) {
|
||||
var self = this;
|
||||
var charDelay = ms / text.length;
|
||||
return new Promise(function(resolve) {
|
||||
var i = 0;
|
||||
function typeNext() {
|
||||
if (!self._isActive || i >= text.length) { resolve(); return; }
|
||||
input.value += text[i];
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
i++;
|
||||
setTimeout(typeNext, charDelay);
|
||||
}
|
||||
typeNext();
|
||||
});
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Formular-Ausf\u00fcll-Demo (Step 3)
|
||||
// -----------------------------------------------------------------------
|
||||
async _simulateFormFill() {
|
||||
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 || !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();
|
||||
this._highlightSub('#inc-title');
|
||||
await this._simulateTyping(titleInput, 'Explosion in Hamburger Hafen', 1200);
|
||||
await this._wait(500);
|
||||
this._clearSubHighlights();
|
||||
|
||||
// 2. 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);
|
||||
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)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren