diff --git a/src/static/js/tutorial.js b/src/static/js/tutorial.js
index 6db3483..8dfc032 100644
--- a/src/static/js/tutorial.js
+++ b/src/static/js/tutorial.js
@@ -731,16 +731,24 @@ const Tutorial = {
Tutorial._clearSubHighlights();
},
},
- // 5 - Sidebar Filter
+ // Sidebar Filter
{
id: 'sidebar-filters',
target: '.sidebar-filter',
title: 'Lagen filtern',
text: 'Mit diesen Filtern steuern Sie, welche Lagen angezeigt werden:
'
- + 'Alle - Zeigt sämtliche Lagen Ihrer Organisation
'
+ + 'Alle - Zeigt s\u00e4mtliche Lagen Ihrer Organisation
'
+ 'Eigene - Nur Lagen, die Sie selbst erstellt haben
'
- + 'Bei vielen Lagen hilft dies, den Überblick zu behalten.',
+ + 'Bei vielen Lagen hilft dies, den \u00dcberblick zu behalten.',
position: 'right',
+ disableNav: true,
+ onEnter: function() {
+ Tutorial._runDemo(Tutorial._simulateFilterSwitch);
+ },
+ onExit: function() {
+ Tutorial._clearSubHighlights();
+ Tutorial._hideCursor();
+ },
},
// 6 - Demo-Lage einführen
{
@@ -872,33 +880,97 @@ const Tutorial = {
Tutorial._clearSubHighlights();
},
},
- // 14 - Faktencheck: Einzelner Eintrag
+ // Faktencheck: Status-Demo
{
id: 'faktencheck-detail',
target: '.factcheck-item[data-fc-status="confirmed"]',
title: 'Faktencheck-Eintrag',
text: 'Jeder Faktencheck-Eintrag besteht aus:
'
- + 'Status-Symbol - Farbcodiert für schnelle Einordnung (links)
'
- + 'Behauptung - Die geprüfte Aussage
'
- + 'Quellenanzahl - Wie viele Quellen diese Behauptung stützen
'
- + 'Die Filterfunktion oben rechts ermöglicht es, nach Status zu filtern, '
- + 'z.B. nur unbestätigte Meldungen anzeigen.',
+ + 'Status-Symbol - Farbcodiert f\u00fcr schnelle Einordnung
'
+ + 'Behauptung - Die gepr\u00fcfte Aussage
'
+ + 'Quellenanzahl - Wie viele Quellen diese Behauptung st\u00fctzen
'
+ + 'Beobachten Sie, wie der Cursor die verschiedenen Status durchgeht:',
position: 'left',
+ disableNav: true,
onEnter: function() {
- // Zum nicht-verifizierten Eintrag scrollen
- var fcList = document.getElementById('factcheck-list');
- if (fcList) fcList.scrollTo({ top: fcList.scrollHeight, behavior: 'smooth' });
- Tutorial._stepTimeout(function() {
- if (fcList) fcList.scrollTo({ top: 0, behavior: 'smooth' });
- }, 2000);
- var item = document.querySelector('.factcheck-item[data-fc-status="confirmed"]');
- if (item) item.classList.add('tutorial-sub-highlight');
- Tutorial._cleanupFns.push(function() {
- if (item) item.classList.remove('tutorial-sub-highlight');
- });
+ Tutorial._runDemo(Tutorial._simulateFactcheckStati);
},
onExit: function() {
Tutorial._clearSubHighlights();
+ Tutorial._hideCursor();
+ },
+ },
+ // Ereignis-Timeline
+ {
+ id: 'timeline',
+ target: '[gs-id="timeline"]',
+ title: 'Ereignis-Timeline',
+ text: 'Die Timeline zeigt den chronologischen Verlauf aller Ereignisse. '
+ + 'Klicken Sie auf einen Zeitpunkt, um die zugeh\u00f6rige Meldung anzuzeigen.
'
+ + 'Punkte - Meldungen und Lageberichte auf der Zeitachse
'
+ + 'Detail-Panel - Zeigt Quelle, Titel und Zeitstempel
'
+ + 'So k\u00f6nnen Sie auch \u00e4ltere Lagebilder abrufen und den Verlauf nachvollziehen.',
+ position: 'top',
+ disableNav: true,
+ onEnter: function() {
+ Tutorial._runDemo(Tutorial._simulateTimeline);
+ },
+ onExit: function() {
+ Tutorial._clearSubHighlights();
+ Tutorial._hideCursor();
+ },
+ },
+ // Karte: Kachel-Ansicht
+ {
+ id: 'karte',
+ target: '[gs-id="karte"]',
+ title: 'Geografische Verteilung',
+ text: 'Die Karte zeigt per Geoparsing automatisch erkannte Orte aus den Quellen.
'
+ + 'Orte einlesen - Startet das Geoparsing manuell neu
'
+ + 'Vollbild - Vergr\u00f6\u00dfert die Karte auf den gesamten Bildschirm
'
+ + 'Im n\u00e4chsten Schritt \u00f6ffnen wir die Vollbildansicht.',
+ position: 'top',
+ disableNav: true,
+ onEnter: function() {
+ if (Tutorial._demoMapTileMap) {
+ Tutorial._demoMapTileMap.invalidateSize();
+ setTimeout(function() {
+ if (Tutorial._demoMapTileMap) Tutorial._demoMapTileMap.setView([53.545, 9.98], 12);
+ }, 200);
+ }
+ Tutorial._runDemo(Tutorial._simulateKarteButtons);
+ },
+ onExit: function() {
+ Tutorial._clearSubHighlights();
+ Tutorial._hideCursor();
+ },
+ },
+ // Karte: Vollbild
+ {
+ id: 'karte-fullscreen',
+ target: '.map-fullscreen-header',
+ title: 'Karte im Vollbild',
+ text: 'Die Orte werden automatisch aus den Quellenartikeln erkannt und auf der Karte dargestellt:
'
+ + '● Hauptereignisort - Wo das Ereignis stattfindet
'
+ + '● Erw\u00e4hnt - In Meldungen genannte Orte
'
+ + '● Kontext - Orte im weiteren Zusammenhang
'
+ + 'Klicken Sie auf einen Marker f\u00fcr Details und verkn\u00fcpfte Artikel.',
+ position: 'left',
+ disableNav: true,
+ onEnter: function() {
+ var chatBtn = document.getElementById('chat-toggle-btn');
+ if (chatBtn) chatBtn.style.display = 'none';
+ var bubble = document.getElementById('tutorial-bubble');
+ if (bubble) bubble.style.zIndex = '99999';
+ Tutorial._openDemoMapFullscreen();
+ },
+ onExit: function() {
+ Tutorial._closeDemoMapFullscreen();
+ var chatBtn = document.getElementById('chat-toggle-btn');
+ if (chatBtn) chatBtn.style.display = '';
+ var bubble = document.getElementById('tutorial-bubble');
+ if (bubble) bubble.style.zIndex = '';
+ Tutorial._clearSubHighlights();
},
},
// 15 - Quellen
@@ -921,105 +993,24 @@ const Tutorial = {
Tutorial._clearSubHighlights();
},
},
- // 16 - Timeline
+ // Dashboard anpassen (Drag + Resize)
{
- id: 'timeline',
- target: '[gs-id="timeline"]',
- title: 'Ereignis-Timeline',
- text: 'Die Timeline zeigt den chronologischen Verlauf aller Ereignisse:
'
- + 'Meldungen - Einzelne Artikel und Nachrichten aus den Quellen
'
- + 'Lageberichte - Automatisch erstellte Zusammenfassungen (hervorgehoben)
'
- + 'Nutzen Sie die Filter oben:
'
- + 'Alle/Meldungen/Lageberichte - Typ-Filter
'
- + '24h/7T/Alles - Zeitraum eingrenzen
'
- + 'Suchfeld - Freitextsuche in allen Einträgen',
- position: 'top',
- onEnter: function() {
- Tutorial._highlightSub('.ht-controls');
- },
- onExit: function() {
- Tutorial._clearSubHighlights();
- },
- },
- // 17 - Karte: Kachel-Ansicht
- {
- id: 'karte',
- target: '[gs-id="karte"]',
- title: 'Geografische Verteilung',
- text: 'Die Karte zeigt per Geoparsing automatisch erkannte Orte aus den Quellen.
'
- + 'Orte einlesen - Startet das Geoparsing manuell neu
'
- + 'Vollbild - Vergr\u00f6\u00dfert die Karte auf den gesamten Bildschirm
'
- + 'Im n\u00e4chsten Schritt \u00f6ffnen wir die Vollbildansicht und schauen uns die Marker im Detail an.',
- position: 'top',
- onEnter: function() {
- // Tile-Map Resize triggern
- if (Tutorial._demoMapTileMap) {
- Tutorial._demoMapTileMap.invalidateSize();
- setTimeout(function() {
- if (Tutorial._demoMapTileMap) Tutorial._demoMapTileMap.setView([53.545, 9.98], 12);
- }, 200);
- }
- Tutorial._highlightSub('#geoparse-btn');
- Tutorial._stepTimeout(function() {
- Tutorial._clearSubHighlights();
- Tutorial._highlightSub('#map-expand-btn');
- }, 2500);
- },
- onExit: function() {
- Tutorial._clearSubHighlights();
- },
- },
- // 18 - Karte: Vollbild + Zoom + Marker-Demo
- {
- id: 'karte-fullscreen',
- target: '.map-fullscreen-header',
- title: 'Karte im Vollbild',
- text: 'Die Karte zoomt jetzt auf den Ereignisort. Die Marker zeigen:
'
- + '● Hauptereignisort - Burchardkai Terminal (6 Artikel)
'
- + '● Erw\u00e4hnt - Hamburg Innenstadt (2 Artikel)
'
- + '● Kontext - Elbe / Hafengebiet (1 Artikel)
'
- + 'Die Legende unten rechts erkl\u00e4rt die Farbkategorien. '
- + 'Klicken Sie auf einen Marker f\u00fcr Details und verkn\u00fcpfte Artikel.',
- position: 'left',
- disableNav: true,
- onEnter: function() {
- var chatBtn = document.getElementById('chat-toggle-btn');
- if (chatBtn) chatBtn.style.display = 'none';
- Tutorial._openDemoMapFullscreen();
- },
- onExit: function() {
- Tutorial._closeDemoMapFullscreen();
- var chatBtn = document.getElementById('chat-toggle-btn');
- if (chatBtn) chatBtn.style.display = '';
- Tutorial._clearSubHighlights();
- },
- },
- // 18 - Drag Demo
- {
- id: 'drag-demo',
+ id: 'layout-demo',
target: '[gs-id="lagebild"] .card-header',
- title: 'Kacheln verschieben',
- text: 'Alle Kacheln im Dashboard lassen sich frei per Drag-and-Drop verschieben. '
- + 'Greifen Sie dazu die Kopfzeile einer Kachel und ziehen Sie sie an die gewünschte Position.
'
- + 'Beobachten Sie die virtuelle Maus-Demo:',
+ title: 'Dashboard anpassen',
+ text: 'Alle Kacheln lassen sich frei verschieben und in der Gr\u00f6\u00dfe anpassen. '
+ + 'Greifen Sie die Kopfzeile zum Verschieben oder den unteren Rand zum Vergr\u00f6\u00dfern.
'
+ + 'Beobachten Sie die Demo: Erst wird das Lagebild verschoben, dann vergr\u00f6\u00dfert.',
position: 'right',
disableNav: true,
onEnter: function() {
- Tutorial._runDemo(Tutorial._simulateDrag);
+ Tutorial._runDemo(Tutorial._simulateLayoutDemo);
},
- },
- // 19 - Resize Demo
- {
- id: 'resize-demo',
- target: '[gs-id="faktencheck"]',
- title: 'Kacheln in der Größe anpassen',
- text: 'Ziehen Sie am rechten unteren Rand einer Kachel, um ihre Größe zu verändern. '
- + 'So können Sie wichtigen Inhalten wie dem Faktencheck mehr Platz einräumen.
'
- + 'Beobachten Sie die virtuelle Maus-Demo:',
- position: 'left',
- disableNav: true,
- onEnter: function() {
- Tutorial._runDemo(Tutorial._simulateResize);
+ onExit: function() {
+ if (typeof LayoutManager !== 'undefined' && LayoutManager._grid) {
+ LayoutManager._applyLayout(LayoutManager.DEFAULT_LAYOUT);
+ }
+ Tutorial._hideCursor();
},
},
// 20 - Theme
@@ -1031,17 +1022,17 @@ const Tutorial = {
+ 'Ihre Auswahl wird automatisch gespeichert und beim nächsten Besuch beibehalten.',
position: 'bottom',
},
- // 21 - Quellen verwalten
+ // Quellen verwalten
{
id: 'sources-btn',
target: '.sidebar-sources-link button:first-child',
- title: 'Quellenverwaltung öffnen',
+ title: 'Quellenverwaltung \u00f6ffnen',
text: 'In der Seitenleiste ganz unten finden Sie den Zugang zur Quellenverwaltung. '
- + 'Hier können Sie:
'
- + 'Neue Quellen hinzufügen - URL eingeben oder automatisch erkennen lassen
'
+ + 'Hier k\u00f6nnen Sie:
'
+ + 'Neue Quellen hinzuf\u00fcgen - URL eingeben oder automatisch erkennen lassen
'
+ 'Bestehende Quellen bearbeiten - Kategorie, Sprache, Notizen anpassen
'
- + 'Quellen deaktivieren - Temporär oder dauerhaft ausschließen',
- position: 'right',
+ + 'Quellen deaktivieren - Tempor\u00e4r oder dauerhaft ausschlie\u00dfen',
+ position: 'top',
onEnter: function() {
Tutorial._stepTimeout(function() {
var overlay = document.getElementById('modal-sources');
@@ -1122,30 +1113,36 @@ const Tutorial = {
Tutorial._hideCursor();
},
},
- // 23 - Chat
+ // Chat-Assistent
{
id: 'chat',
target: '#chat-toggle-btn',
title: 'Chat-Assistent',
- text: 'Der Chat-Assistent steht Ihnen jederzeit zur Verfügung. '
+ text: 'Der Chat-Assistent steht Ihnen jederzeit zur Verf\u00fcgung. '
+ 'Stellen Sie Fragen zur Bedienung des Monitors und erhalten Sie sofort eine Antwort.
'
+ 'Beispiele:
'
+ '"Wie erstelle ich eine neue Lage?"
'
+ '"Was bedeuten die Faktencheck-Status?"
'
+ '"Wie exportiere ich einen Lagebericht?"',
- position: 'left',
+ position: 'top',
},
- // 24 - Ende
+ // Ende
{
id: 'end',
target: null,
title: 'Rundgang abgeschlossen',
text: 'Sie kennen jetzt alle wichtigen Funktionen des AegisSight Monitors.
'
- + 'Die Demo-Daten werden nach dem Schließen entfernt. '
- + 'Erstellen Sie Ihre erste eigene Lage über den Button "+ Neue Lage" in der Seitenleiste.
'
+ + 'Die Demo-Daten werden nach dem Schlie\u00dfen entfernt. '
+ + 'Erstellen Sie Ihre erste eigene Lage \u00fcber den Button "+ Neue Lage" in der Seitenleiste.
'
+ 'Bei weiteren Fragen steht Ihnen der Chat-Assistent '
- + 'oder unser Support unter support@aegis-sight.de zur Verfügung.',
+ + 'oder unser Support unter support@aegis-sight.de zur Verf\u00fcgung.',
position: 'center',
+ onEnter: function() {
+ Tutorial._stepTimeout(function() {
+ var bubble = document.getElementById('tutorial-bubble');
+ if (bubble) bubble.style.top = '55%';
+ }, 50);
+ },
},
];
},
@@ -1746,8 +1743,11 @@ const Tutorial = {
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' });
+ var elRect = el.getBoundingClientRect();
+ var bodyRect = modalBody.getBoundingClientRect();
+ var offset = elRect.top - bodyRect.top + modalBody.scrollTop;
+ var targetScroll = offset - Math.min(40, bodyRect.height * 0.2);
+ modalBody.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' });
},
// -----------------------------------------------------------------------
@@ -1787,6 +1787,8 @@ const Tutorial = {
// -----------------------------------------------------------------------
// Step 4: Art der Lage (Typ-Wechsel)
// -----------------------------------------------------------------------
+ // Step 4: Art der Lage (simuliertes Dropdown)
+ // -----------------------------------------------------------------------
async _simulateTypeSwitch() {
this._demoRunning = true;
var sel = document.getElementById('inc-type');
@@ -1795,15 +1797,67 @@ const Tutorial = {
var pos = await this._cursorToElement('#inc-type');
await this._wait(300);
- // Wechsel zu Recherche
- sel.value = 'research';
- sel.dispatchEvent(new Event('change'));
- await this._wait(2000);
+ // Simuliertes Dropdown
+ var rect = sel.getBoundingClientRect();
+ var dropdown = document.createElement('div');
+ dropdown.id = 'tutorial-fake-dropdown';
+ dropdown.style.cssText = 'position:fixed;z-index:99999;background:var(--bg-card,#1a1f2e);'
+ + 'border:1px solid var(--border,#2a3040);border-radius:8px;box-shadow:0 8px 32px rgba(0,0,0,0.4);'
+ + 'overflow:hidden;left:' + rect.left + 'px;top:' + (rect.bottom + 4) + 'px;width:' + rect.width + 'px;'
+ + 'opacity:0;transform:translateY(-4px);transition:opacity 0.2s,transform 0.2s;';
- // Zur\u00fcck zu Live-Monitoring
+ var opt1 = document.createElement('div');
+ opt1.textContent = 'Live-Monitoring';
+ opt1.style.cssText = 'padding:10px 14px;font-size:14px;color:var(--text-primary,#e0e0e0);'
+ + 'background:var(--accent-alpha,rgba(212,175,55,0.15));transition:background 0.15s;';
+
+ var opt2 = document.createElement('div');
+ opt2.textContent = 'Analyse / Recherche';
+ opt2.style.cssText = 'padding:10px 14px;font-size:14px;color:var(--text-primary,#e0e0e0);'
+ + 'transition:background 0.15s;';
+
+ dropdown.appendChild(opt1);
+ dropdown.appendChild(opt2);
+ document.body.appendChild(dropdown);
+
+ await this._wait(50);
+ dropdown.style.opacity = '1';
+ dropdown.style.transform = 'translateY(0)';
+ await this._wait(400);
+
+ // Cursor zu Live-Monitoring
+ var opt1Rect = opt1.getBoundingClientRect();
+ await this._animateCursor(pos.x, pos.y,
+ opt1Rect.left + opt1Rect.width / 2, opt1Rect.top + opt1Rect.height / 2, 400);
+ await this._wait(1200);
+
+ // Cursor zu Analyse/Recherche
+ var opt2Rect = opt2.getBoundingClientRect();
+ await this._animateCursor(
+ opt1Rect.left + opt1Rect.width / 2, opt1Rect.top + opt1Rect.height / 2,
+ opt2Rect.left + opt2Rect.width / 2, opt2Rect.top + opt2Rect.height / 2, 400);
+ opt1.style.background = '';
+ opt2.style.background = 'var(--accent-alpha,rgba(212,175,55,0.15))';
+ sel.value = 'research';
+ try { sel.dispatchEvent(new Event('change')); } catch(e) {}
+ await this._wait(1500);
+
+ // Zurueck zu Live-Monitoring
+ opt1Rect = opt1.getBoundingClientRect();
+ opt2Rect = opt2.getBoundingClientRect();
+ await this._animateCursor(
+ opt2Rect.left + opt2Rect.width / 2, opt2Rect.top + opt2Rect.height / 2,
+ opt1Rect.left + opt1Rect.width / 2, opt1Rect.top + opt1Rect.height / 2, 400);
+ opt2.style.background = '';
+ opt1.style.background = 'var(--accent-alpha,rgba(212,175,55,0.15))';
sel.value = 'adhoc';
- sel.dispatchEvent(new Event('change'));
- await this._wait(800);
+ try { sel.dispatchEvent(new Event('change')); } catch(e) {}
+ await this._wait(1000);
+
+ dropdown.style.opacity = '0';
+ dropdown.style.transform = 'translateY(-4px)';
+ await this._wait(250);
+ if (dropdown.parentNode) dropdown.remove();
this._hideCursor();
this._demoRunning = false;
@@ -2209,6 +2263,281 @@ const Tutorial = {
this._enableNavAfterDemo();
},
+
+ // -----------------------------------------------------------------------
+ // Sidebar-Filter Demo
+ // -----------------------------------------------------------------------
+ async _simulateFilterSwitch() {
+ this._demoRunning = true;
+ await this._wait(400);
+ var btns = document.querySelectorAll('.sidebar-filter button, .sidebar-filter .filter-btn');
+ var allBtn = null, ownBtn = null;
+ btns.forEach(function(b) {
+ var t = b.textContent.trim().toLowerCase();
+ if (t === 'alle') allBtn = b;
+ if (t === 'eigene') ownBtn = b;
+ });
+ if (!allBtn) allBtn = document.querySelector('.sidebar-filter [data-filter="all"]');
+ if (!ownBtn) ownBtn = document.querySelector('.sidebar-filter [data-filter="own"]');
+ if (!allBtn || !ownBtn) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
+
+ var ar = allBtn.getBoundingClientRect();
+ this._showCursor(ar.left - 30, ar.top - 20, 'default');
+ await this._wait(300);
+ await this._animateCursor(ar.left - 30, ar.top - 20, ar.left + ar.width/2, ar.top + ar.height/2, 400);
+ allBtn.classList.add('tutorial-sub-highlight');
+ await this._wait(1500);
+ allBtn.classList.remove('tutorial-sub-highlight');
+
+ var or2 = ownBtn.getBoundingClientRect();
+ await this._animateCursor(ar.left+ar.width/2, ar.top+ar.height/2, or2.left+or2.width/2, or2.top+or2.height/2, 500);
+ ownBtn.classList.add('tutorial-sub-highlight');
+ await this._wait(1500);
+ ownBtn.classList.remove('tutorial-sub-highlight');
+
+ ar = allBtn.getBoundingClientRect();
+ or2 = ownBtn.getBoundingClientRect();
+ await this._animateCursor(or2.left+or2.width/2, or2.top+or2.height/2, ar.left+ar.width/2, ar.top+ar.height/2, 500);
+ allBtn.classList.add('tutorial-sub-highlight');
+ await this._wait(1000);
+ allBtn.classList.remove('tutorial-sub-highlight');
+
+ this._hideCursor();
+ this._demoRunning = false;
+ this._enableNavAfterDemo();
+ },
+
+ // -----------------------------------------------------------------------
+ // Faktencheck-Stati Demo
+ // -----------------------------------------------------------------------
+ async _simulateFactcheckStati() {
+ this._demoRunning = true;
+ await this._wait(400);
+ var fcList = document.getElementById('factcheck-list');
+ if (!fcList) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
+
+ var stati = ['confirmed','established','unconfirmed','disputed','contradicted'];
+ var prevX, prevY;
+ for (var i = 0; i < stati.length; i++) {
+ if (!this._isActive) break;
+ var item = fcList.querySelector('[data-fc-status="' + stati[i] + '"]');
+ if (!item) continue;
+ item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ await this._wait(300);
+ var r = item.getBoundingClientRect();
+ var tx = r.left + 20, ty = r.top + r.height/2;
+ if (prevX !== undefined) {
+ await this._animateCursor(prevX, prevY, tx, ty, 400);
+ } else {
+ this._showCursor(tx - 40, ty - 30, 'default');
+ await this._wait(200);
+ await this._animateCursor(tx - 40, ty - 30, tx, ty, 400);
+ }
+ item.classList.add('tutorial-sub-highlight');
+ await this._wait(1500);
+ if (i < stati.length - 1) item.classList.remove('tutorial-sub-highlight');
+ prevX = tx; prevY = ty;
+ }
+ this._hideCursor();
+ this._demoRunning = false;
+ this._enableNavAfterDemo();
+ },
+
+ // -----------------------------------------------------------------------
+ // Timeline Demo
+ // -----------------------------------------------------------------------
+ async _simulateTimeline() {
+ this._demoRunning = true;
+ await this._wait(400);
+ var points = document.querySelectorAll('.ht-point');
+ if (!points.length) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
+ var detailPanel = document.querySelector('.ht-detail-panel');
+ var entries = this._DEMO_TIMELINE;
+ var prevX, prevY;
+ for (var i = 0; i < Math.min(points.length, entries.length); i++) {
+ if (!this._isActive) break;
+ var point = points[i];
+ var entry = entries[i];
+ var r = point.getBoundingClientRect();
+ var tx = r.left + r.width/2, ty = r.top + r.height/2;
+ if (prevX !== undefined) {
+ await this._animateCursor(prevX, prevY, tx, ty, 400);
+ } else {
+ this._showCursor(tx - 40, ty - 30, 'default');
+ await this._wait(200);
+ await this._animateCursor(tx - 40, ty - 30, tx, ty, 400);
+ }
+ points.forEach(function(p) { p.classList.remove('active'); });
+ point.classList.add('active');
+ if (detailPanel) {
+ var isSn = entry.type === 'snapshot';
+ detailPanel.innerHTML = '