Add renamed docs, backup, and Gitea workflow

This commit is contained in:
mw
2025-12-27 17:42:06 +00:00
parent c5e9b8675d
commit 16a068a8dd
241 changed files with 68 additions and 13 deletions
+100
View File
@@ -0,0 +1,100 @@
// Funktion zum Aktualisieren der Body-Klassen basierend auf dem aktuellen Pfad
function updateBodyClasses() {
// Aktuelle URL-Pfad ohne Domain
const path = window.location.pathname;
// Entferne führende und abschließende Schrägstriche
const cleanPath = path.replace(/^\/|\/$/g, '');
// Entferne alle vorherigen dynamischen Klassen
// (wir müssen eine Liste der zu entfernenden Klassen erstellen, da sich die classList während der Iteration ändert)
const classesToRemove = [];
for (let i = 0; i < document.body.classList.length; i++) {
const className = document.body.classList[i];
// Bewahre nur bestimmte MkDocs-spezifische Klassen
if (!className.startsWith('md-') &&
className !== 'no-js' &&
className !== 'js') {
classesToRemove.push(className);
}
}
// Entferne die Klassen
classesToRemove.forEach(className => {
document.body.classList.remove(className);
});
// Wenn der Pfad leer oder eine Entwickler Github Page ist (Startseite), füge die Klasse 'home' hinzu
if (cleanPath === '' || cleanPath === 'satware.ai') {
document.body.classList.add('home');
} else {
// Teile den Pfad in Segmente auf
const segments = cleanPath.split('/');
// Füge Klassen für jedes Segment hinzu
segments.forEach(function(segment) {
if (segment) {
document.body.classList.add(segment);
}
});
}
// Optional: Debug-Ausgabe in der Konsole
console.log('Updated body classes:', document.body.className);
}
// Initial beim Laden der Seite
document.addEventListener('DOMContentLoaded', updateBodyClasses);
// Bei Navigation innerhalb der MkDocs-Seite
// Wir müssen auf das MkDocs-spezifische Event hören
document.addEventListener('DOMContentLoaded', function() {
// Warte kurz, bis MkDocs vollständig initialisiert ist
setTimeout(function() {
// Finde alle internen Links
const internalLinks = document.querySelectorAll('a[href^="/"]:not([target]), a[href^="./"]:not([target]), a[href^="../"]:not([target])');
// Füge Event-Listener für Klicks auf interne Links hinzu
internalLinks.forEach(link => {
link.addEventListener('click', function() {
// Kurze Verzögerung, um der Navigation Zeit zu geben
setTimeout(updateBodyClasses, 100);
});
});
// Beobachte Änderungen an der URL (History API)
if (window.MutationObserver) {
// Beobachte Änderungen am Titel, was oft ein Indikator für Seitenwechsel ist
const titleObserver = new MutationObserver(updateBodyClasses);
if (document.querySelector('title')) {
titleObserver.observe(document.querySelector('title'), { childList: true });
}
// Beobachte Änderungen am Hauptinhalt
const contentObserver = new MutationObserver(function(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
updateBodyClasses();
break;
}
}
});
if (document.querySelector('.md-content')) {
contentObserver.observe(document.querySelector('.md-content'), {
childList: true,
subtree: true
});
}
}
// Fallback: Regelmäßige Überprüfung auf URL-Änderungen
let lastPath = window.location.pathname;
setInterval(function() {
if (window.location.pathname !== lastPath) {
lastPath = window.location.pathname;
updateBodyClasses();
}
}, 200);
}, 500);
});
View File
@@ -0,0 +1,82 @@
document.addEventListener('DOMContentLoaded', function() {
// Funktion zum Formatieren der Zahlen mit Kommas und Plus-Zeichen
function formatNumber(num, includePlus = true) {
const formatted = num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
return includePlus ? formatted + '+' : formatted;
}
// Funktion zum Extrahieren der Zahl aus dem Text (entfernt das '+' und Kommas)
function extractNumber(text) {
return parseInt(text.replace(/,/g, '').replace('+', ''), 10);
}
// Funktion zum Animieren der Zähler
function animateCounter(counterElement, target) {
// Startpunkt
let start = 0;
// Dauer der Animation in Millisekunden (angepasst an die Größe der Zahl)
const duration = Math.min(2000 + Math.log10(target) * 300, 3000);
// Zeitpunkt des Starts
const startTime = performance.now();
// Funktion für die Animation
function updateCounter(currentTime) {
// Berechne den verstrichenen Zeitanteil (0 bis 1)
const elapsedTime = Math.min((currentTime - startTime) / duration, 1);
// Easing-Funktion für eine natürlichere Animation
const progress = easeOutQuart(elapsedTime);
// Berechne den aktuellen Wert
const currentValue = Math.floor(progress * target);
// Aktualisiere den Zähler mit dem Plus-Zeichen
counterElement.textContent = formatNumber(currentValue, true);
// Wenn die Animation noch nicht abgeschlossen ist, nächsten Frame anfordern
if (elapsedTime < 1) {
requestAnimationFrame(updateCounter);
} else {
// Stelle sicher, dass der endgültige Wert exakt dem Zielwert entspricht
counterElement.textContent = formatNumber(target, true);
}
}
// Easing-Funktion für eine natürlichere Animation
function easeOutQuart(t) {
return 1 - Math.pow(1 - t, 4);
}
// Starte die Animation
requestAnimationFrame(updateCounter);
}
// Intersection Observer zum Erkennen, wann die Zähler sichtbar werden
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// Wenn der Zähler sichtbar wird
if (entry.isIntersecting) {
const counterElement = entry.target;
// Extrahiere die Zielnummer aus dem Text
const targetText = counterElement.textContent;
const target = extractNumber(targetText);
// Setze den Anfangswert auf 0 mit Plus-Zeichen
counterElement.textContent = '0+';
// Starte die Animation
animateCounter(counterElement, target);
// Beobachtung beenden, damit die Animation nur einmal ausgeführt wird
observer.unobserve(counterElement);
}
});
}, {
threshold: 0.1 // 10% des Elements müssen sichtbar sein
});
// Alle Zähler beobachten
document.querySelectorAll('.satag--home-counter-number').forEach(counter => {
observer.observe(counter);
});
});
+101
View File
@@ -0,0 +1,101 @@
// Funktion zur Initialisierung der FAQ-Funktionalität
function initFAQ() {
// Finde alle FAQ-Fragen
const faqQuestions = document.querySelectorAll('.custom-faq-question');
if (faqQuestions.length === 0) {
console.log('Keine benutzerdefinierten FAQ-Elemente gefunden');
return;
}
console.log('Benutzerdefinierte FAQ-Elemente gefunden:', faqQuestions.length);
// Entferne zuerst alle bestehenden Event-Listener, um Duplikate zu vermeiden
faqQuestions.forEach(question => {
// Klonen des Elements, um alle Event-Listener zu entfernen
const newQuestion = question.cloneNode(true);
question.parentNode.replaceChild(newQuestion, question);
});
// Hole die aktualisierten Elemente nach dem Klonen
const updatedFaqQuestions = document.querySelectorAll('.custom-faq-question');
// Füge Event-Listener zu jeder Frage hinzu
updatedFaqQuestions.forEach(question => {
question.addEventListener('click', function() {
// Toggle active class auf der Frage
this.classList.toggle('active');
// Toggle active class auf der Antwort
const answer = this.nextElementSibling;
answer.classList.toggle('active');
// Wenn diese Frage geöffnet wurde, schließe alle anderen
if (this.classList.contains('active')) {
updatedFaqQuestions.forEach(otherQuestion => {
if (otherQuestion !== this && otherQuestion.classList.contains('active')) {
otherQuestion.classList.remove('active');
otherQuestion.nextElementSibling.classList.remove('active');
}
});
// Initialisiere Slideshows innerhalb der geöffneten Antwort
setTimeout(() => {
if (typeof initSlideshows === 'function') {
initSlideshows();
}
}, 100);
}
});
});
console.log('Benutzerdefinierte FAQ-Funktionalität initialisiert');
}
// Führe die Initialisierung beim ersten Laden der Seite aus
document.addEventListener('DOMContentLoaded', initFAQ);
// Führe die Initialisierung aus, wenn der Inhalt der Seite durch MkDocs aktualisiert wird
document.addEventListener('DOMContentSwap', initFAQ);
// Führe die Initialisierung aus, wenn die Seite über den Material for MkDocs-Router aktualisiert wird
document.addEventListener('mdContentChanged', initFAQ);
// Führe die Initialisierung aus, wenn der Inhalt der Seite durch andere Frameworks aktualisiert wird
// MutationObserver, um Änderungen im DOM zu überwachen
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
// Prüfe, ob FAQ-Elemente hinzugefügt wurden
for (let i = 0; i < mutation.addedNodes.length; i++) {
const node = mutation.addedNodes[i];
if (node.nodeType === 1 && (node.classList?.contains('custom-faq-item') ||
node.querySelector?.('.custom-faq-item'))) {
// FAQ-Elemente gefunden, initialisiere die Funktionalität
setTimeout(initFAQ, 100); // Kurze Verzögerung, um sicherzustellen, dass alles geladen ist
break;
}
}
}
});
});
// Starte die Beobachtung des Dokuments
observer.observe(document.body, {
childList: true,
subtree: true
});
// Zusätzlicher Event-Listener für dynamisch geladene Inhalte
window.addEventListener('load', function() {
// Verzögerte Initialisierung, um sicherzustellen, dass alle Inhalte geladen sind
setTimeout(initFAQ, 500);
});
// Für Material for MkDocs spezifische Ereignisse
if (typeof document$.subscribe === 'function') {
document$.subscribe(function() {
// Verzögerte Initialisierung, um sicherzustellen, dass alle Inhalte geladen sind
setTimeout(initFAQ, 100);
});
}
+201
View File
@@ -0,0 +1,201 @@
// Lightbox functionality for the homepage screenshot
document.addEventListener('DOMContentLoaded', function() {
// Get the screenshot image
const screenshotImg = document.querySelector('.screenshot-container img');
// If the image exists
if (screenshotImg) {
// Create lightbox elements
const lightbox = document.createElement('div');
lightbox.className = 'satag-lightbox';
const closeBtn = document.createElement('span');
closeBtn.className = 'satag-lightbox-close';
closeBtn.innerHTML = '&times;';
const lightboxImg = document.createElement('img');
lightboxImg.className = 'satag-lightbox-img';
lightboxImg.src = screenshotImg.src;
lightboxImg.alt = screenshotImg.alt;
// Append elements to the lightbox
lightbox.appendChild(closeBtn);
lightbox.appendChild(lightboxImg);
// Remove any existing lightbox to avoid duplicates
const existingLightbox = document.querySelector('.satag-lightbox');
if (existingLightbox) {
document.body.removeChild(existingLightbox);
}
// Append lightbox to the body instead of the screenshot container
// This allows the lightbox to be as large as the viewport, not constrained by the container
document.body.appendChild(lightbox);
// Function to position the lightbox directly over the original image
function positionLightbox() {
// Get the position and dimensions of the original image
const imgRect = screenshotImg.getBoundingClientRect();
const screenshotContainer = document.querySelector('.screenshot-container');
const containerRect = screenshotContainer.getBoundingClientRect();
// Get the current scroll position
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
// Get viewport dimensions
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Position the lightbox directly over the original image
lightbox.style.position = 'fixed';
lightbox.style.top = imgRect.top + 'px';
lightbox.style.left = imgRect.left + 'px';
lightbox.style.width = imgRect.width + 'px';
lightbox.style.height = imgRect.height + 'px';
lightbox.style.display = 'flex';
lightbox.style.alignItems = 'center';
lightbox.style.justifyContent = 'center';
// Set the lightbox image to fill the lightbox container
lightboxImg.style.position = 'relative';
lightboxImg.style.width = '100%';
lightboxImg.style.height = '100%';
lightboxImg.style.objectFit = 'contain';
// Position the close button in the top-right corner of the lightbox
closeBtn.style.top = '5px';
closeBtn.style.right = '5px';
}
// Function to check if lightbox should be enabled (screen width > 768px)
function shouldEnableLightbox() {
return window.innerWidth > 768;
}
// Update cursor style based on screen width
function updateCursorStyle() {
screenshotImg.style.cursor = shouldEnableLightbox() ? 'pointer' : 'default';
}
// Initial cursor style update
updateCursorStyle();
// Update cursor style when window is resized
window.addEventListener('resize', updateCursorStyle);
// Open lightbox when clicking on the screenshot (only if screen width > 768px)
screenshotImg.addEventListener('click', function(e) {
e.preventDefault(); // Prevent default behavior
// Only activate lightbox if screen width > 768px
if (!shouldEnableLightbox()) {
return;
}
// Position the lightbox over the original image
positionLightbox();
// Display the lightbox - use flex to match our CSS
lightbox.style.display = 'flex';
// Force a reflow to ensure the display change takes effect before adding the active class
void lightbox.offsetWidth;
// Apply transform scale to the lightbox to make it larger
const viewportWidth = window.innerWidth;
if (viewportWidth <= 479) { // Mobile
lightbox.style.transform = 'scale(1.2)';
} else if (viewportWidth <= 959) { // Tablet
lightbox.style.transform = 'scale(1.3)';
} else if (viewportWidth <= 1219) { // Medium screens
lightbox.style.transform = 'scale(1.4)';
} else { // Large screens
lightbox.style.transform = 'scale(1.5)';
}
// Add the active class to trigger the transition
lightbox.classList.add('active');
});
// Function to handle closing with transition
function closeLightboxWithTransition() {
lightbox.style.opacity = '0';
lightbox.style.transform = 'scale(1)'; // Reset scale to original size
// Wait for transition to complete before removing active class
setTimeout(function() {
lightbox.classList.remove('active');
// Reset display to none after the transition is complete
lightbox.style.display = 'none';
// Reset all inline styles after the lightbox is hidden
setTimeout(function() {
// Reset opacity and transform
lightbox.style.opacity = '';
lightbox.style.transform = '';
// Reset position and size styles
lightbox.style.position = '';
lightbox.style.top = '';
lightbox.style.left = '';
lightbox.style.width = '';
lightbox.style.height = '';
lightbox.style.alignItems = '';
lightbox.style.justifyContent = '';
// Reset image styles
lightboxImg.style.width = '';
lightboxImg.style.height = '';
lightboxImg.style.objectFit = '';
// Reset close button styles
closeBtn.style.top = '';
closeBtn.style.right = '';
}, 100);
}, 400); // Match the transition duration from CSS
}
// Close lightbox when clicking on the close button
closeBtn.addEventListener('click', function(e) {
e.stopPropagation(); // Prevent event from bubbling up
closeLightboxWithTransition();
});
// Close lightbox when clicking on the lightbox (outside the image)
lightbox.addEventListener('click', function(e) {
if (e.target === lightbox) {
closeLightboxWithTransition();
}
});
// Close lightbox when pressing Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && lightbox.classList.contains('active')) {
closeLightboxWithTransition();
}
});
// Update lightbox position when window is resized
window.addEventListener('resize', function() {
if (lightbox.classList.contains('active')) {
// Reposition the lightbox based on new viewport dimensions
positionLightbox();
// Apply appropriate transform scale based on viewport width
const viewportWidth = window.innerWidth;
if (viewportWidth <= 479) { // Mobile
lightbox.style.transform = 'scale(1.2)';
} else if (viewportWidth <= 959) { // Tablet
lightbox.style.transform = 'scale(1.3)';
} else if (viewportWidth <= 1219) { // Medium screens
lightbox.style.transform = 'scale(1.4)';
} else { // Large screens
lightbox.style.transform = 'scale(1.5)';
}
}
});
}
});
+221
View File
@@ -0,0 +1,221 @@
// Slideshow functionality for FAQ answers - OPTIMIZED VERSION
document.addEventListener('DOMContentLoaded', initSlideshows);
document.addEventListener('DOMContentSwap', initSlideshows);
document.addEventListener('mdContentChanged', initSlideshows);
// Track initialized slideshows to prevent double-initialization
const initializedSlideshows = new Set();
// Function to initialize all slideshows on the page
function initSlideshows() {
const slideshows = document.querySelectorAll('.faq-slideshow');
if (slideshows.length === 0) {
return;
}
console.log('Slideshows found:', slideshows.length);
slideshows.forEach((slideshow, slideshowIndex) => {
// Create unique ID for this slideshow
const slideshowId = `slideshow-${slideshowIndex}`;
// Skip if already initialized
if (initializedSlideshows.has(slideshowId)) {
return;
}
slideshow.setAttribute('id', slideshowId);
initializedSlideshows.add(slideshowId);
// Get slideshow elements
const container = slideshow.querySelector('.faq-slideshow-container');
const slides = slideshow.querySelectorAll('.faq-slide');
const prevBtn = slideshow.querySelector('button.faq-slideshow-prev');
const nextBtn = slideshow.querySelector('button.faq-slideshow-next');
const dotsContainer = slideshow.querySelector('.faq-slideshow-dots');
console.log('Slideshow elements found:', {
container: !!container,
slides: slides.length,
prevBtn: !!prevBtn,
nextBtn: !!nextBtn,
dotsContainer: !!dotsContainer
});
if (!container || slides.length === 0) {
return;
}
// Current slide index
let currentSlide = 0;
// Function to go to a specific slide
function goToSlide(index) {
console.log(`goToSlide called for slideshow ${slideshowId} with index ${index}`);
// Handle wrapping around
if (index < 0) {
index = slides.length - 1;
console.log(`Wrapped to last slide: ${index}`);
} else if (index >= slides.length) {
index = 0;
console.log(`Wrapped to first slide: ${index}`);
}
// Update current slide index
const previousSlide = currentSlide;
currentSlide = index;
console.log(`Changing slide from ${previousSlide} to ${currentSlide}`);
// Move the container to show the current slide (OPTIMIZED)
const transformValue = `translateX(-${currentSlide * 100}%)`;
console.log(`Setting transform to: ${transformValue}`);
container.style.transform = transformValue;
// Update active dot (OPTIMIZED)
if (dotsContainer) {
const dots = dotsContainer.querySelectorAll('.faq-slideshow-dot');
const activeDot = dotsContainer.querySelector('.faq-slideshow-dot.active');
const newActiveDot = dots[currentSlide];
if (activeDot && activeDot !== newActiveDot) {
activeDot.classList.remove('active');
}
if (newActiveDot && !newActiveDot.classList.contains('active')) {
newActiveDot.classList.add('active');
}
console.log(`Updated active dot to index ${currentSlide}`);
}
}
// Create dots if they don't exist
if (dotsContainer && dotsContainer.children.length === 0) {
for (let i = 0; i < slides.length; i++) {
const dot = document.createElement('div');
dot.className = 'faq-slideshow-dot';
if (i === 0) {
dot.classList.add('active');
}
dot.addEventListener('click', () => {
goToSlide(i);
});
dotsContainer.appendChild(dot);
}
}
// FIXED: Only use addEventListener (remove onclick to prevent double execution)
if (prevBtn) {
console.log('Adding click event listener to prev button for slideshow', slideshowId);
// Remove any existing handlers
prevBtn.onclick = null;
// Add single event listener
prevBtn.addEventListener('click', (e) => {
console.log('Prev button clicked for slideshow', slideshowId);
e.stopPropagation();
e.preventDefault();
goToSlide(currentSlide - 1);
}, { once: false, passive: false });
prevBtn.style.cursor = 'pointer';
}
if (nextBtn) {
console.log('Adding click event listener to next button for slideshow', slideshowId);
// Remove any existing handlers
nextBtn.onclick = null;
// Add single event listener
nextBtn.addEventListener('click', (e) => {
console.log('Next button clicked for slideshow', slideshowId);
e.stopPropagation();
e.preventDefault();
goToSlide(currentSlide + 1);
}, { once: false, passive: false });
nextBtn.style.cursor = 'pointer';
}
// Initialize the first slide
goToSlide(0);
// Add keyboard navigation when slideshow is in focus
slideshow.tabIndex = 0;
slideshow.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
goToSlide(currentSlide - 1);
} else if (e.key === 'ArrowRight') {
goToSlide(currentSlide + 1);
}
});
// Add optimized swipe support for touch devices
let touchStartX = 0;
let touchEndX = 0;
slideshow.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
}, { passive: true });
slideshow.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
}, { passive: true });
function handleSwipe() {
const swipeThreshold = 50;
if (touchEndX < touchStartX - swipeThreshold) {
goToSlide(currentSlide + 1);
} else if (touchEndX > touchStartX + swipeThreshold) {
goToSlide(currentSlide - 1);
}
}
});
}
// MutationObserver to detect when new slideshows are added to the DOM
// FIXED: Renamed to avoid conflicts and added throttling
const slideshowObserver = new MutationObserver((mutations) => {
let hasRelevantMutation = false;
mutations.forEach((mutation) => {
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
const node = mutation.addedNodes[i];
if (node.nodeType === 1 && (node.classList?.contains('faq-slideshow') ||
node.querySelector?.('.faq-slideshow'))) {
hasRelevantMutation = true;
break;
}
}
}
});
if (hasRelevantMutation) {
setTimeout(initSlideshows, 100);
}
});
// Start observing the document
slideshowObserver.observe(document.body, {
childList: true,
subtree: true
});
// Additional event listener for dynamically loaded content
window.addEventListener('load', function() {
setTimeout(initSlideshows, 500);
});
// For Material for MkDocs specific events
if (typeof document$.subscribe === 'function') {
document$.subscribe(function() {
setTimeout(initSlideshows, 100);
});
}
+44
View File
@@ -0,0 +1,44 @@
window.addEventListener('load', function() {
// Testimonial-Wechsel-Funktionalität
const testimonialImages = document.querySelectorAll('.satag--home-testimonial-image-wrapper');
const testimonialTexts = document.querySelectorAll('.satag--home-testimonials-text');
// Funktion zum Wechseln des aktiven Testimonials
function switchTestimonial(id) {
// Entferne 'active' Klasse von allen Bildern und Texten
testimonialImages.forEach(img => img.classList.remove('active'));
testimonialTexts.forEach(text => text.classList.remove('active'));
// Füge 'active' Klasse zum ausgewählten Bild und Text hinzu
document.querySelector(`.satag--home-testimonial-image-wrapper[data-testimonial-id="${id}"]`).classList.add('active');
document.querySelector(`.satag--home-testimonials-text[data-testimonial-id="${id}"]`).classList.add('active');
}
// Event-Listener für Klicks auf die Bilder
testimonialImages.forEach(img => {
img.addEventListener('click', function() {
const id = this.getAttribute('data-testimonial-id');
switchTestimonial(id);
});
});
// Optional: Automatischer Wechsel alle 5 Sekunden
let currentId = 1;
const totalTestimonials = testimonialImages.length;
function autoSwitchTestimonial() {
currentId = currentId % totalTestimonials + 1;
switchTestimonial(currentId);
}
// Kommentiere die nächste Zeile aus, wenn du keinen automatischen Wechsel möchtest
const intervalId = setInterval(autoSwitchTestimonial, 5000);
// Optional: Stoppe den automatischen Wechsel, wenn der Benutzer mit einem Testimonial interagiert
testimonialImages.forEach(img => {
img.addEventListener('click', function() {
clearInterval(intervalId);
});
});
});
+30
View File
@@ -0,0 +1,30 @@
document.addEventListener('DOMContentLoaded', function() {
const scrollWrap = document.querySelector('.md-search__scrollwrap');
if (scrollWrap) {
scrollWrap.setAttribute('tabindex', '0');
scrollWrap.addEventListener('keydown', function(e) {
// Pfeiltasten für Scrolling
if (e.key === 'ArrowDown') {
e.preventDefault();
this.scrollTop += 30;
} else if (e.key === 'ArrowUp') {
e.preventDefault();
this.scrollTop -= 30;
} else if (e.key === 'PageDown') {
e.preventDefault();
this.scrollTop += this.clientHeight;
} else if (e.key === 'PageUp') {
e.preventDefault();
this.scrollTop -= this.clientHeight;
} else if (e.key === 'Home') {
e.preventDefault();
this.scrollTop = 0;
} else if (e.key === 'End') {
e.preventDefault();
this.scrollTop = this.scrollHeight;
}
});
}
});