/** Inhalt der Datei: basic24.js **/ // basic js 2024 G. Stephan // cookie setzen und abrufen function cookie(name, value , days=7 ) { // Wenn kein Wert übergeben wird, den Cookie abrufen if (value === undefined) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) === ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); } return null; // Cookie nicht gefunden } else { // Cookie setzen const expires = "; expires=" + new Date(Date.now() + (days * 24 * 60 * 60 * 1000) ).toUTCString(); // Cookie läuft nach 7 Tagen ab document.cookie = name + "=" + value + expires + "; path=/"; // Setze den Cookie } } function parseUrl(url) { let parsedUrl; // Funktion zur Prüfung, ob eine URL absolut ist function isAbsoluteUrl(url) { return /^https?:\/\//i.test(url); } try { // Prüfe, ob die URL absolut ist if (isAbsoluteUrl(url)) { // Wenn die URL absolut ist, verwende sie direkt parsedUrl = new URL(url); } else { // Wenn es sich um eine relative URL handelt, baue sie auf Basis von window.location.href parsedUrl = new URL(url, window.location.href); } } catch (error) { console.error("Fehler beim Parsen der URL:", error); return null; } // Extrahiere den Teil der URL ohne Query-Parameter const urlWithoutQuery = parsedUrl.origin + parsedUrl.pathname; // Bereinige den Pfad, um doppelte Schrägstriche zu entfernen const cleanedPath = parsedUrl.pathname.replace(/([^:]\/)\/+/g, "$1"); // Extrahiere den Dateinamen samt Endung const pathParts = cleanedPath.split('/'); const fileNameWithExtension = pathParts.pop(); // Letztes Element ist der Dateiname // Der verbleibende Pfad (ohne Dateinamen) const filePath = pathParts.join('/'); // Stelle sicher, dass der Pfad korrekt ist (füge führenden / hinzu, falls nötig) const correctedFilePath = filePath.startsWith('/') ? filePath : '/' + filePath; // Extrahiere die Query-Parameter und speichere sie in einem Objekt const urlParams = {}; parsedUrl.searchParams.forEach((value, key) => { urlParams[key] = value; }); // Gib ein Objekt zurück, das die URL, den Dateinamen, den Pfad und die Query-Parameter enthält return { url: parsedUrl.origin + cleanedPath, // Die vollständige URL ohne Query-Parameter params: urlParams, // Die Query-Parameter als Objekt fileName: fileNameWithExtension, // Der Dateiname mit der Endung path: correctedFilePath , origin: window.location.origin // Der Pfad ohne den Dateinamen, mit führendem / }; } function getLastPath(path) { // Pfad in einzelne Teile zerlegen const parts = path.endsWith('/') ? path.slice(0, -1).split('/') : path.split('/'); // Array, um die letzten Pfade zu speichern const subPaths = []; // Erstellen einer Kopie des Original-Pfads für die Berechnung let currentParts = [...parts]; // Kopiere das Array der Teile // Schleife, um den Pfad zu verkürzen und die letzten Pfade zu speichern while (currentParts.length > 0) { // Füge den Pfad mit Schrägstrich hinzu, außer bei der obersten Ebene const subPath = currentParts.join('/') + (currentParts.length > 1 ? '/' : ''); subPaths.push(subPath); currentParts.pop(); // Entferne das letzte Element } // Entferne den letzten Teil des ursprünglichen Pfads, um den tieferen Pfad zu berechnen parts.pop(); // Entferne das letzte Element (niedrigste Ebene) // Berechnung des tieferen Pfads, ohne Schrägstrich bei der obersten Ebene const lowerPath = parts.length > 0 ? parts.join('/') + '/' : ''; // Speichere die subPaths als eine Konstante const allSubPaths = subPaths; // Rückgabe des tieferen Pfads und des Arrays return { lowerPath, // Der Pfad eine Stufe höher allSubPaths // Alle letzten Pfade (vom tiefsten bis zum obersten) }; } function isClassDeclared(className) { for (let i = 0; i < document.styleSheets.length; i++) { try { if (!document.styleSheets[i].href || document.styleSheets[i].href.startsWith(window.location.origin)) { let rules = document.styleSheets[i].cssRules || document.styleSheets[i].rules; for (let j = 0; j < rules.length; j++) { if (rules[j].selectorText === `.${className}`) { return true; } } } } catch (e) { // Ignoriere den Fehler für Cross-Origin-Stylesheets console.warn('Auf Stylesheet konnte nicht zugegriffen werden:', document.styleSheets[i].href, e); } } return false; } function resizeImages(obj={ w : 180 }) { var w = obj.w, windowWidth = obj.container ? obj.container.offsetWidth : window.innerWidth, numThumbnails = Math.floor(windowWidth / w ), // 180px ist dieursprüngliche Breite der Thumbnails newThumbnailWidth = Math.ceil( ( windowWidth / numThumbnails) * .97 ) ; document.querySelectorAll('.thumbnail').forEach(function(thumbnail) { thumbnail.style.width = (newThumbnailWidth) + 'px'; thumbnail.style.height = newThumbnailWidth + 'px'; }); } function hslToHex(h, s, l) { s /= 100; l /= 100; const a = s * Math.min(l, 1 - l); const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return `#${[0, 8, 4].map(i => Math.round(f(i) * 255).toString(16).padStart(2, '0')).join('')}`; } function rgbToHex(rgb) { const rgbValues = rgb.match(/\d+/g); // Extrahiere die Zahlen (R, G, B) if (!rgbValues || rgbValues.length < 3) return null; // Überprüfen, ob RGB gültig ist return `#${rgbValues.slice(0, 3) .map(value => parseInt(value).toString(16).padStart(2, '0')) .join('')}`; } function farbengenerator(numColors) { const colors = []; const hueStep = 360 / (numColors / 2); // Berechne den Farbton-Schritt for (let i = 0; i < numColors; i++) { const hue = (i % (numColors / 2)) * hueStep; // Farbton für die aktuelle Farbe const lightness = i < numColors / 2 ? (i / (numColors / 2)) * 50 : 50 + ((i - numColors / 2) / (numColors / 2)) * 50; // Helligkeit colors.push(hslToHex(hue, 100, lightness)); } return colors; } function getLuminance(hexColor) { // Hexadezimale Farbe zu RGB umwandeln let r = parseInt(hexColor.substr(1, 2), 16) / 255; let g = parseInt(hexColor.substr(3, 2), 16) / 255; let b = parseInt(hexColor.substr(5, 2), 16) / 255; // Gamma-korrigierte Werte berechnen r = (r <= 0.03928) ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); g = (g <= 0.03928) ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); b = (b <= 0.03928) ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); // Relative Luminanz berechnen return 0.2126 * r + 0.7152 * g + 0.0722 * b; } function getTextColor(hexColor,threshold ) { const luminance = getLuminance(hexColor); // Schwellenwert für Luminanz var threshold = threshold || .18; // Wähle weiße oder schwarze Schriftfarbe basierend auf der Luminanz return luminance > threshold ? 'black' : '#FFFFFF'; } function getColors( c , length, number) { const result = []; const totalColors = c.length; // Startindex basierend auf `number` let index = number; while (result.length < totalColors) { // Füge `length`-mal die gleiche Farbe hinzu for (let i = 0; i < length; i++) { result.push(c[index % totalColors]); } // Springe zum nächsten Farbblock index += length; } return result; //.slice(0, totalColors); // Nur `totalColors` Elemente zurückgeben } function getJSON(f,o,e){ fetch( o.pfad , { // method: 'POST', //(standardmäßig GET) headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json' // Optional, sorgt dafür, dass der Server JSON-Antworten zurückgibt }, body: JSON.stringify( o ) // Daten senden }) .then(response => { if (!response.ok) { throw new Error('Netzwerk antwortet: ' + response.statusText); } return response.json(); }) .then(data => { if (data.error) { html('html ' + data.error); } else { f(data,o,e); } }) .catch(error => { console.error('Fehler: getJSON', error); }); } function saveFav(data){ const userString = JSON.stringify(data); localStorage.setItem( 'imgFavoriten' , userString ); } function loadFav(){ const storedUserString = localStorage.getItem( 'imgFavoriten' ), data = JSON.parse(storedUserString); return data||{}; } function isFav(name){ var f = loadFav()||{}; return f[name] ? true : false; } function myConfirmF(message) { if(lf.confirmwait) return; lf.confirmwait = true; function clear(overlay){ //document.body.removeChild(overlay); //modal.destroy(); overlay.destroy(); lf.confirmwait=false; // document.removeEventListener('keydown', handleEscape); } //event.preventDefault(); return new Promise( (resolve) => { // Das Overlay und das Dialogfeld erstellen const overlay = html( stil.center+"to=le 0| w=h 100% | pos fixed | z 300 | bgc rgba(0,0,0,.6)" , document.body ); const modal = html("w 300 | h 200 |col white| bgc crimson| ta center|dis block | br 10", overlay ); // Nachrichtentext const text = html(' | w 300 |h 40| marT 60|html '+message , modal); // Bestätigungsbutton const confirmBtn = html(stil.button+'col gray|html OK|dis ib',modal); confirmBtn.onclick = () => { //event.preventDefault(); clear(overlay); resolve(true); // Auflösung mit "true" bei Bestätigung }; // Abbrechen-Button const cancelBtn = html(stil.button+'col gray|innerText Abbrechen|dis ib',modal); cancelBtn.onclick = () => { //event.preventDefault(); clear(overlay); resolve(false); // Auflösung mit "false" bei Abbruch }; handleEscape = (event) => { if (event.key === 'Escape') { cancelBtn.onclick(); document.removeEventListener('keydown', handleEscape); } } //lf.confirmEscape = document.addEventListener('keydown', handleEscape ); }); } function myConfirm( message, onConfirm=false , onEscape=false ) { myConfirmF(message).then((confirmed) => { if (confirmed && onConfirm) onConfirm(); else if(onEscape) onEscape(); });} /** Inhalt der Datei: carousel.js **/ /* --- Gunthard Stephan 9.24 --- LFox --- */ class Carousel { //constructor(container, imageSources, autoRotate = false, rotateDirection = 'left', duration = 45) { constructor( obj ) { //this.container = document.body; this.imageSources = []; this.autoRotate = true; this.direction = 'left'; this.duration = 50; this.images = []; this.sync(obj); //this.expandArray(); this.totalWidth = 0; this.containerWidth = this.container.offsetWidth; this.containerHeight = this.container.offsetHeight; this.zoom = new ZoomMan({ zoomClick: 'next' }); this.init(); } sync(o){ for(let i in o){ //html('html->'+i) this[i] = o[i]; } } init() { this.setupContainer(); this.loadImages(); } // Setze die Container-Stile für Flexbox setupContainer() { this.container.set('dis flex | ovf visible | pos rel | whiteSpace nowrap '); if(this.autoRotate) return; this.container.set('c pointer'); this.container.addEventListener('click', (event) => { if(event.metaKey){ return; } this.move( event.altKey ? 'right': 'left' ) }); } // Bilder laden und in den Container einfügen loadImages() { var i = 0; //while( i++ < this.imageSources.length ) { this.imageSources.forEach( (src, index) => { //const src = this.imageSources[i]; const img = new Image(); img.set( 'display inline-block | op 0 | transition all 0.5s ease'); img.onload = () => { const imgWidth = (img.naturalWidth / img.naturalHeight) * this.containerHeight; img.set( ' h 100% | w auto' ); this.container.appendChild(img); this.images.push(img); this.totalWidth += imgWidth; setTimeout( ()=> { img.set( 'op 1 ' );} , 400 ); img.addEventListener('click', (event) => { if (event.metaKey) { this.zoom.zoom(img.src); return; } }); if (index === this.imageSources.length - 1) { this.setLeftImg(); } if(this.autoRotate && ++i >= this.imageSources.length ) { setTimeout( ()=> {this.startAutoRotate(this.direction);} , 800 ); } }; img.src = src this.zoom.add( img.src ); if(!this.autoRotate) return; img.addEventListener('click', (event) => { if (event.altKey) { this.direction = this.direction == 'left' ? 'right' : 'left'; this.startAutoRotate( this.direction ); } if (event.metaKey) { this.zoom.zoom(img.src); } }); //}; }); } // Letztes Bild setzen setLeftImg(m = 0) { const img = this.images[this.images.length - 1]; const imgWidth = (img.naturalWidth / img.naturalHeight) * this.containerHeight; if (m === 2) { if (this.temp2) return; const img2 = this.images[ this.images.length - 2 ]; const img2Width = imgWidth + (img2.naturalWidth / img2.naturalHeight) * this.containerHeight; this.temp2 = this.createTempImage(img2.src); this.temp2.set( `transform translateX(-${img2Width}px) | h 100%` ); return; } else { if (!m && this.temp && this.temp instanceof HTMLImageElement){ this.temp.destroy(); this.temp = null; } } if (this.temp) return; this.temp = this.createTempImage(img.src); this.temp.set( `transform translateX(-${imgWidth}px) | h 100%` ); } // Erstellt ein temporäres Bild für die Animation createTempImage(src) { const img = html('t img | pos abs | h 100% | src ' + src, this.container ); //obj.temp.style.transform = `translateX(-${imgWidth}px)`; return img; } // Bilder verschieben move(direction) { if (this.images.length === 0) return; const firstImg = this.images[0]; const lastImg = this.images[this.images.length - 1]; const firstImgWidth = Math.floor( (firstImg.naturalWidth / firstImg.naturalHeight) * this.containerHeight ); const lastImgWidth = (lastImg.naturalWidth / lastImg.naturalHeight) * this.containerHeight; if (direction === 'left') { this.container.set( `transition all 0.8s ease | transform translateX(-${firstImgWidth}px)` ); //console.log(firstImgWidth+' '+this.containerHeight) this.container.addEventListener('transitionend', () => { this.container.set('transition none | transform translateX(0) '); this.container.appendChild(this.container.firstElementChild); this.images.push(this.images.shift()); this.setLeftImg(); }, { once: true }); } else if (direction === 'right') { this.container.style.transition = 'all 0.9s ease'; this.container.style.transform = `translateX(${lastImgWidth}px)`; this.setLeftImg(2); this.container.addEventListener('transitionend', () => { if (this.temp && this.temp instanceof HTMLImageElement) { this.temp.destroy(); this.temp = null; } if (this.temp2 && this.temp2 instanceof HTMLImageElement) { this.temp2.destroy(); this.temp2 = null; } this.container.set('transition none | transform translateX(0) '); this.container.insertBefore(this.container.lastElementChild, this.container.firstElementChild); this.images.unshift(this.images.pop()); this.setLeftImg(1); }, { once: true }); } } stopAutoRotate() { // Entferne die laufende Animation this.container.style.animation = 'none'; this.container.style.transition = 'none'; // Entferne auch etwaige Übergänge } startAutoRotate(direktion) { // Wechsle die Richtung //this.direction = direktion; //this.direction === 'left' ? 'right' : 'left'; // Stoppe die aktuelle Animation this.container.style.animation = 'none'; this.container.offsetHeight; // Trigger reflow this.container.style.transition = 'none'; // Entferne Übergänge // Überprüfe, ob die Bildreihe bereits verdoppelt wurde (Vermeide ständiges Verdoppeln) if (!this.container.classList.contains('duplicated')) { const originalImages = this.container.innerHTML; // Speichere den ursprünglichen Inhalt this.container.innerHTML = originalImages + originalImages; // Verdopple die Bildreihe this.container.classList.add('duplicated'); // Markiere den Container als verdoppelt } const extendedTotalWidth = this.totalWidth * 2; // Überprüfe, ob bereits ein Stil-Element vorhanden ist if (!document.getElementById('carousel-animation-styles'+this.id)) { const style = document.createElement('style'); style.id = 'carousel-animation-styles'+this.id ; // Füge eine ID hinzu, um später darauf zuzugreifen style.innerHTML = ` @keyframes seamlessLeft${this.id} { 0% { transform: translateX(0); } 100% { transform: translateX(-${this.totalWidth}px); } } @keyframes seamlessRight${this.id} { 0% { transform: translateX(-${this.totalWidth}px); } 100% { transform: translateX(0); } } `; document.head.appendChild(style); } //if (this.direction !== direction) { //this.direction = direction; if (this.direction === 'left') { this.container.style.animation = 'none'; void this.container.offsetWidth; // Reset animation this.container.style.animation = `seamlessLeft${this.id} ${this.duration}s linear infinite`; } else { this.container.style.animation = 'none'; void this.container.offsetWidth; // Reset animation this.container.style.animation = `seamlessRight${this.id} ${this.duration}s linear infinite`; } if( this.firstrotation ) return this.container.querySelectorAll('img').forEach((img) => { img.addEventListener('click', () => { if (event.metaKey) { this.zoom.zoom( img.src ); return; } if (event.altKey) { const directions = [ 'left','right','none',]; const currentIndex = directions.indexOf(this.direction); // Berechne den neuen Index const nextIndex = (currentIndex + 1) % directions.length; // Setze die neue Richtung this.direction = directions[nextIndex]; //this.direction = this.direction === 'left' ? 'none' : 'right' ? 'left' : 'right'; if(this.direction === 'none') this.stopAutoRotate(); else this.startAutoRotate(this.direction); } }); }); this.firstrotation = true; if( !this.changeRotation ) return // Event-Listener, um die aktuelle Position zu überwachen this.container.addEventListener('animationiteration', () => { // Nach jeder vollständigen Iteration wird die Richtung geändert this.direction = this.direction === 'left' ? 'right' : 'left'; // Starte die Animation neu in die entgegengesetzte Richtung this.startAutoRotate(); }); } // Automatische Rotation via CSS-Animation starten startAutoRotate__(direction) { const originalImages = this.container.innerHTML; if( !this.firstrotation ) this.container.innerHTML += originalImages; //else this.container.innerHTML = originalImages; this.firstrotation = true; //if(this.imageSources.length < 15) this.container.innerHTML += this.container.innerHTML; const extendedTotalWidth = this.totalWidth * 2; if(!this.id) this.id = zufall(3); if (!document.getElementById('carousel-animation-styles'+this.id)) { const style = document.createElement('style'); style.id = 'carousel-animation-styles'+this.id ; // Füge eine ID hinzu, um später darauf zuzugreifen style.innerHTML = ` @keyframes seamlessLeft${this.id} { 0% { transform: translateX(0); } 100% { transform: translateX(-${this.totalWidth}px); } } @keyframes seamlessRight${this.id} { 0% { transform: translateX(-${this.totalWidth}px); } 100% { transform: translateX(0); } } `; document.head.appendChild(style); } //if (this.direction !== direction) { //this.direction = direction; if (direction === 'left') { this.container.style.animation = 'none'; void this.container.offsetWidth; // Reset animation this.container.style.animation = `seamlessLeft${this.id} ${this.duration}s linear infinite`; } else { this.container.style.animation = 'none'; void this.container.offsetWidth; // Reset animation this.container.style.animation = `seamlessRight${this.id} ${this.duration}s linear infinite`; } //} this.direction = direction; if( this.firstrotation ) return let t = this; let clicker = function(img){ if (event.metaKey) { t.zoom.zoom( img.src ); return; } if (event.altKey) { t.startAutoRotate(t.direction === 'left' ? 'right' : 'left'); } } this.container.querySelectorAll('img').forEach((img) => { img.removeEventListener('click', clicker ); img.addEventListener('click', clicker ); }); this.firstrotation = true; // } } /** Inhalt der Datei: classObserver.js **/ class Observer { constructor(className, callback, options = {}) { this.className = className; this.callback = callback || this.autoloader; this.isPaused = false; // Initialisierung direkt im Konstruktor this.pauseTimer = null; this.triggeredElements = new Set(); const defaultOptions = { root: null, // Standard: beobachtet den Browser-Viewport threshold: 0.5, // 50% Sichtbarkeit autoload : null, dataAtt : 'data-src', idol:null, preload : null // hier wird eine funktion aufgerufen, // die sofort beim durchlauf der querySelectorAll Schleife aufgerufen wird, nicht erst nach dem laden des Bildes }; options.firstload? options.preload = options.firstload : 0; // Merge der übergebenen Optionen mit den Standard-Optionen this.options = Object.assign(defaultOptions, options); // IntersectionObserver erstellen this.observer = new IntersectionObserver(this.handleIntersect.bind(this), this.options); // Elemente der angegebenen Klasse beobachten this.observeElements(); } standardLoad(element){ element.style.opacity = 1; } autoloader(element){ element.addEventListener('load' , ()=>{ this.standardLoad(element); } ); var src = element.getAttribute( this.options.dataAtt ); if(!src) return; element.src = src; this.options.preload ? this.options.preload(element) : 0; } observeElements() { const elements = document.querySelectorAll(`.${this.className}`); elements.forEach(element => { this.observer.observe(element); }); } handleIntersect(entries, observer) { if (this.isPaused) return; entries.forEach(entry => { if (entry.isIntersecting) { //if(lf.wait) return; this.callback(entry.target,this.idol||this); if(this.callback != this.autoloader && this.options.autoload ) this.autoloader(entry.target); this.triggeredElements.add(entry.target); // Element als bereits ausgelöst markieren observer.unobserve(entry.target); // Beobachtung beenden, wenn sichtbar } }); } // Funktion, um die Beobachtung für eine bestimmte Zeit zu pausieren pauseObservation(duration = 1000) { this.isPaused = true; clearTimeout(this.pauseTimer); this.pauseTimer = setTimeout(() => { this.isPaused = false; // Sichtbarkeitsprüfung für alle beobachteten Elemente const elements = document.querySelectorAll(`.${this.className}`); const entries = Array.from(elements).map(element => ({ target: element, isIntersecting: this.isElementInViewport(element), })); // Aufruf von handleIntersect, aber mit Filterung der bereits ausgelösten Elemente this.handleIntersect(entries.filter(entry => !this.triggeredElements.has(entry.target))); }, duration); } isElementInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top < (window.innerHeight || document.documentElement.clientHeight) && rect.bottom > 0 ); } } /** Inhalt der Datei: classOverlay.js **/ class Overlay { constructor(obj={}) { this.bgc = 'crimson'; this.blend = false; this.swipen=true; this.modus='top'; this.sync(obj); this.init(); this.setModus( this.status ); } sync(o){ for(let i in o){ this[i] = o[i]; } } att = stil.transition +stil.center+` z 200 | pos fixed | fs clamp( 70px, 12vw, 140px) | col white | h=w 100% | html Overlayer | cn overlay `; init(){ this.layer = html( this.att , this.node ); this.layer.set('bgc '+this.bgc); this.css ? this.layer.set(this.css) : 0 ; this.layer.set('op '+(this.blend ? 0 : 1).toString() ); } setModus(status,m){ let mapping = { top: 'le=ri 0', left: 'to=bo 0', right: 'to=bo 0', bottom: 'le=ri 0' }; let s = mapping[this.modus] || ''; this.layer.set(s);// +`| ${this.modus} 0px`); if(!m)this.layer.set( this.modus + ( status ? ' 0' : ' -100%') ) ; this.status = status; } changeModus(direction){ if(direction === this.modus) return; var status = this.getStatus(); this.layer.set('le=ri=to=bo auto'); this.layer.set( `${direction} `+(status?' 0':' -100%') ); this.modus = direction; //this.setModus(false,1); } changeClick(direction){ this.changeModus(direction); this.click(); } getStatus(){ this.status = this.layer.css( this.modus ,'int') >= 0 ; // Status abfragen return this.status } click( direction=this.modus ){ event.stopPropagation(); let e = this.layer; let status = this.getStatus(); if(direction !== this.modus)this.changeClick(direction) else this.setModus(!status); //e.set('op '+( status ? (this.blend?0:1) : 1 ) ); if(!status && !this.escapeList){ this.escapeList = document.addEventListener('keydown', (event)=>{ this.handleEscape(event); }); e.addEventListener('wheel', (event)=>{ event.preventDefault(); }); //alert( this.isMobileDevice() ); if( this.isMobileDevice() ) swipen( e , { up : ()=> this.destroy(false) }); else if(this.swipen) swipen( e , { up: ()=> this.destroy(false) }); } //modus ? e.idol = event.target : 0; //e.idol.html( 'Overlayer ' + ( !status ? 'ausblenden' : 'anzeigen') ); } toggle(status){ if(status!=null) this.status = status; this.click(); } isMobileDevice() { const userAgent = navigator.userAgent || navigator.vendor || window.opera; // Erkennung von mobilen Geräten if (/android/i.test(userAgent)) return true; if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) return true; return false; } destroy(modus=false){ if(!this.getStatus()) return; this.click(); //document.removeEventListener('keydown', this.handleEscape ); //this.escapeList = null; } handleEscape(event) { if (event.key === 'Escape') { this.destroy(); } } } /** Inhalt der Datei: class_pjotr.js **/ // 18. November 2024 - G. Stephan LFox class Pjotr { constructor(obj) { this.container = obj.container ; this.images = Array.from(this.container.children); //this.container.querySelectorAll('.pjotr'); this.zoom = false; this.observe = false; this.sync(obj) // Initiale Bindung und Event-Listener this.calculateImageSizes = this.calculateImageSizes.bind(this); this.init(); } sync(o){ for(let i in o) this[i] = o[i]; } // Steps für response anzahl wechsel steps = [ 530 , 650, 950 , 1150 ] // Methode zur Initialisierung postLoad(t){ setTimeout( ()=> this.calculateImageSizes() , 500 ); } css = ` .pjotr { border: 1px solid white; min-height:50px; min-width: 50px; opacity : ${this.observe?0:1}; object-fit: cover; margin : 0px; } `; init() { // css classe .pjotr !isClassDeclared('pjotr') ? html('tag style | textContent '+this.css , document.head ) : 0; // Führe die Berechnung direkt bei der Initialisierung aus this.images.forEach((img) => { img.className = 'pjotr test'; img.addEventListener('load' , this.calculateImageSizes ); }); this.zoom ? this.zoomer = new ZoomMan({clickable:true}) : 0; // Berechnung bei Fenstergrößenänderung window.addEventListener("resize", ()=>{ // Timer für Scroll-Ende zurücksetzen clearTimeout(this.resizeTimer); // Scroll-Ende-Überwachung this.resizeTimer = setTimeout(() => { this.run(); }, 100); // 100ms warten, um sicherzustellen, dass das resizen beendet ist }); this.container.pjotr = this; if(!this.observe) return; var Ob = new Observer( 'pjotr' , ()=>this.postLoad(this) , { threshold : .2, autoload : true , idol : this, preload: this.zoom ? (element) => this.zoomer.add(element) : null }); Ob.standardLoad = (element)=>{ element.style.opacity = 1; } } // Methode zur Berechnung der Anzahl anzuzeigender Bilder getImagesToShow() { let containerWidth = this.container.offsetWidth, imagesToShow = this.steps.length + 1; this.steps.forEach((step, index) => { if (containerWidth <= step && imagesToShow === this.steps.length + 1) { imagesToShow = index + 1; } }); return imagesToShow; } // Methode zur Berechnung des Gesamtseitenverhältnisses einer Zeile getTotalAspectRatio(rowStartIndex, imagesToShow) { const rowImages = Array.from(this.images).slice(rowStartIndex, rowStartIndex + imagesToShow); return rowImages.reduce((sum, image) => { const aspectRatio = image.naturalWidth / image.naturalHeight; return sum + aspectRatio; }, 0); } run(){ this.calculateImageSizes(); } // Hauptmethode zur Berechnung der Bildgrößen calculateImageSizes() { let contBorderWidth = parseInt(getComputedStyle(this.container).getPropertyValue('border-width')) || 0, containerWidth = this.container.offsetWidth - ( contBorderWidth * 2) - 2, borderWidth = parseInt(getComputedStyle(this.images[0]).getPropertyValue('border-width')) || 0, // Anzahl der nebeneinander angezeigten Bilder imagesToShow = this.getImagesToShow(), adjustedContainerWidth = containerWidth - ( borderWidth * 2 * imagesToShow ) -2 ; // korrektiv // Berechnung der Breite und Höhe der Bilder this.images.forEach((image, idx) => { const rowStartIndex = Math.floor(idx / imagesToShow) * imagesToShow, remainingImages = this.images.length - rowStartIndex, imagesInRow = Math.min(imagesToShow, remainingImages), // Berechne die Containerbreite für die aktuelle Zeile adjustedContainerWidth = containerWidth - (borderWidth * 2 * imagesToShow) -2 , totalAspectRatio = this.getTotalAspectRatio( rowStartIndex, imagesToShow ), // imagesToShow aspectRatio = image.naturalWidth / image.naturalHeight, imageWidth = Math.floor((aspectRatio / totalAspectRatio) * adjustedContainerWidth), imageHeight = Math.floor(imageWidth / aspectRatio); //console.log(imagesInRow) // Setzen der Breite und Höhe image.style.width = 'auto'//`${imageWidth-2}px`; image.style.height = `${imageHeight-2}px`; image.style.opacity = 1; ///console.log(imageHeight) }); } } /** Inhalt der Datei: doku_class.js **/ /* ---------- Gunthard Stephan 7 24 ----------- LFox -------------- */ // Titel function setTitle(text,pfad='../'){ document.body.set('opacity 0 | transition opacity 2s ease'); //let style = html('tag style',document.head); //style.innerHTML = "img { opacity: 0; transition: opacity 1s ease; }"; //html('t img| src virtuell/bild.jpg?h=300|h 300'); document.addEventListener("DOMContentLoaded", function() { // Sobald die Seite geladen ist, die Opazität auf 1 setzen, um die Seite anzuzeigen document.body.style.opacity = 1; // Alle Bilder mit einem onload Event versehen const images = document.querySelectorAll('img'); images.forEach(img => { img.onload = function() { img.style.opacity = 1; // Bild einblenden, wenn es geladen ist }; }); }); const parent = html('pos rel| le=ri 0px | h auto |pad 5| fs 30 | bgc skyblue | position sticky | z 100 | ta center' ); if(pfad !='false')html(stil.center+"pos abs|ri=to=fs 12px | w=h 20 |br 50% | html x |bgc white|c pointer|oc window.location.href='"+pfad+"'", parent ); document.title = text; return html('html '+text, parent ); } // Sanfte Scrollen zum Anker function smoothScroll(e, anker) { //e.preventDefault(); const o = anker.getBoundingClientRect().top + window.pageYOffset, s = window.pageYOffset, a = o - s, n = 1000; let r = null; window.requestAnimationFrame(function e(t) { r = r || t; const i = Math.min((t - r) / n, 1); window.scrollTo(0, s + a * (i < 0.5 ? 4 * i * i * i : (i - 1) * (2 * i - 2) * (2 * i - 2) + 1)); i < 1 && window.requestAnimationFrame(e); }); } // function muss außerhalb der klasse sein, um "this" nicht zu interpretieren !!!!! function loadScript( o , invalid ){ // if (this.o.load) var i, l=0, e = {} ; Object.entries(o.o).map((k , i) => { if (invalid.includes(k[0])) return; //if (! k[0].strstr('text')) { console.log( k[1]) } //if (! k[0].strstr('text')) { console.log( k[0] +'-'+k[1]) } if (! k[0].strstr('text')) { eval(k[1]); } }); } // Funktion Anzeige mit code und Erklärung class LFExClass { constructor( o , name) { //console.log(name) //o.load = 1; this.sync(o.o); this.name = name; this.o = o; this.load = this.o.load ; this.initialize(); this.onload() } sync(o){ for(let i in o){ this[i] = o[i]; } } //überprüfen, ob hash == thema ist isMyHash(thema){ return '#'+thema === window.location.hash.replaceAll('%20',' '); } onload(){ window.addEventListener('DOMContentLoaded', function () { const currentHash = window.location.hash; const themenanzeigeDiv = lf.themenanzeige; if (themenanzeigeDiv) { const links = themenanzeigeDiv.querySelectorAll('a'); // Überprüfe jeden Link links.forEach(function (link) { // Überprüfe, ob der href-Wert des Links mit dem aktuellen Hash übereinstimmt if (link.hash === currentHash) { // Falls übereinstimmend, wird das onclick-Event ausgelöst if (typeof link.onclick === 'function') { setTimeout(()=>{ link.onclick(); } , 1000 ); } } }); } }); } setMain(){ let om = this.o.main; om.display = html('h->auto |b->1px solid gray | bgc-> white | pad->8'); om.h2 = html(`t->h2 | html-> ${om.title}`, om.display); om.textfeld = html('', om.display); om.textfeld.html(om.text); om.pre = html('t->pre | cn->javascript | mar->10', om.display); om.code = html('t->code| cn->javascript|bgc -> gray | fs->10 | cn->', om.pre); om.code.textContent = om.function; om.code.style['white-space'] = 'pre-wrap'; new ExpandDiv({ node: om.pre, min: 100, status: false }); } invalid = ['o', 'ex', 'main', 'load', 'file' ] createCode(){ var i, l=0, e = {} ; Object.entries(this.o).map((k, i) => { if ( this.invalid.includes(k[0])) return; if (k[0].strstr('text')) { i++; let tag; if (!l) { tag = 'h2 | pos sticky | cn bereich| h auto | padT=padB 10 | top 0 | bgc white'; //this.tafel.id = encodeURIComponent(trim(k[1])); if (!this.content) { //let e = {}; e.e = html('bgc lightgray | br=pad=mar 10', lf.themenanzeige ); e.a = html('t->a | pad->6 | html ->' + trim(k[1]), e.e); e.a.href = '#' + encodeURIComponent(trim(k[1])); e.a.onclick = () => { smoothScroll(event,this.tafel); if(this.load){ this.toggleF(true); return; } // lf.wait = true; this.neuladen( true ); //loadScript() this.setButtonText(); setTimeout(()=>{ lf.wait = false; } , 1000 ); } } } else { tag = 'div | bgc lightgray | br=pad 10 | marT 30'; } if (!k[0].strstr('text_')) { this.text = html('name->' + k[0] + '| t->' + tag,this.tafel); k[0].strstr('-') ? this.text.innerHTML = k[1] : this.text.textContent = k[1]; if (l) return; let e = {}; e.h = html('t a| br 50% | b 1px | w=h->20 |pos abs|ri=to 10| html ^ | fs 20', this.text); e.h.href = '#themenanzeige'; e.h.onclick = () => { smoothScroll(event, lf.themenanzeige); //this.toggleF(false); setTimeout(()=>{ lf.wait = false; } , 1500 ); } this.tafel.h2 = this.text; l++; return; } } else { // code zwischen //- und //+ nicht anzeigen... //var result = k[1].replace(/\/\/-([\s\S]*?)\/\/\+/g, '' ); var result = k[1].replace(/\/\/-([\s\S]*?)(\/\/\+|$)/g, ''); //if (this.load) e.e = eval(k[1]); e.e1 = html('marT 20 |t->p|fs->10',this.tafel); e.e1.innerHTML = k[0]; } this.pre = html('t->pre | cn->javascript | mar->10',this.tafel); this.code = html('t->code| cn->javascript| bgc -> gray | fs->12 | cn->', this.pre); this.code.textContent = result; this.code.style['white-space'] = 'pre-wrap'; this.pre.getCss('h', 'int') > 100 ? new ExpandDiv({ node: this.pre, min: 100, status: false, closeButton: 1 }) : 0; }); } grabContent(){ let siblings = []; let currentElement = this.abhier; while (currentElement) { siblings.push(currentElement); currentElement = currentElement.nextElementSibling; } while (siblings.length) { this.content.appendChild(siblings.shift()); } this.abhier.destroy(); } loadScript(){ //if(this.load) return; this.abhier = html('t->hr|marT=marB->30'); loadScript( this , this.invalid ); this.grabContent(); this.loaded = true; } setObserver(element){ this.observeObj = element; this.observer = new IntersectionObserver(this.handleIntersect.bind(this), { root: null, // Beobachtet den Viewport threshold: .4 // Event auslösen, wenn .5 -> 50% des Elements sichtbar sind }); // Starte die Beobachtung des Elements this.observer.observe( this.observeObj ); } // Diese Methode wird ausgeführt, wenn das Element sichtbar wird handleIntersect(entries, observer) { entries.forEach(entry => { if (entry.isIntersecting) { if(lf.wait) return; if(!this.load ){ // Ruft die load()-Methode der Klasse auf this.neuladen( true ); //loadScript() this.setButtonText(); } observer.unobserve( this.observeObj ); // Optional: Beobachtung beenden } }); } initialize() { // Ausgabe aller Themen in einer Übersicht. if (!lf.themenanzeige || !(lf.themenanzeige instanceof HTMLElement)) { lf.themenanzeige = html('name->themenanzeige | h=w->auto |bgc-> white |pad->10 '); html('clear left | t h3 | html Themenübersicht | pos sticky', lf.themenanzeige); } // Display der Hauptfunktion. if (this.o.main) { this.setMain(); } if (this.o.ex === null) return false; this.tafelContainer = html('pos rel| bgc white | br=pad=mar 10 | h auto', this.parent , this.m ); this.tafel = html('name tafel | h auto', this.tafelContainer); // code erstellen this.createCode(); html( 'h 30' , this.tafel ); html('clear->left'); if (!this.content) { this.content = html('overflow-x hidden|pos rel | bgc lightgray | h -> auto | br=pad=mar 10 | box-sizing border-box | transition all .5s ease'); this.EDcontent = new ExpandDiv({ node: this.content, min: 0, status: false, selfClick: null, auto:true }); this.load ? setTimeout(() => { this.EDcontent.open(); }, 100) : 0; } //this.abhier = html('t->hr|marT=marB->30'); if( this.load ) this.loadScript(); //this.grabContent(); this.contentHeight = this.content.offsetHeight; // Buttons //tafel.minimal = html('dis none|t->input | type button | value Beschreibung minimieren', this.tafelContainer); if (this.name) { this.notation = html('w=op 0| t input | type button | value Notation zeigen', this.tafelContainer); let a = html('t pre | bgc gray | pad=fs 10', this.tafelContainer); a.html( eval(this.name).toString() ); a.style['white-space'] = 'pre-wrap'; let A = new ExpandDiv({ node: a , min: 0, status: false, selfClick: null }); this.notation.onclick = () => { A.toggleText( this.notation , 'Notation ausblenden'); hljs.highlightElement(a); }; //this.codemarker( a ); //hljs.highlightElement(a); } this.toggle = html( 't input | type button | value ausblenden', this.tafelContainer) this.toggle.onclick = () => this.toggleF(); this.toggle.set('dis '+(this.load?'inline-block':'none')) ; let text = 'Skript ausführen , Ergebnis löschen'.split(','); this.hideButton = html('op 1| t input | type button | value ' , this.tafelContainer ); this.hideButton.onclick = ()=>this.hide(); this.setButtonText(); // observe //this.setObserver(this.hideButton); this.content.childNodes.length > 1 ? false : [this.content.set('dis none')]; this.codemarker( this.tafelContainer ); !this.parent ? html('t->hr|marT=marB->30') : 0; } toggleF(m){ if(!this.load)return; this.EDcontent.toggle(m); this.toggle.value = (this.EDcontent.status?'aus':'ein')+'blenden'; this.hideButton.set('dis '+(this.EDcontent.status?'inline-block':'none')) ; } loader(){ lf.dokuInactivate=true; if(lf.script) remove(this.script); this.script = html('t script', document.head ); this.script.src = this.o.file; this.script.onload = ()=>{ console.log(this.name) var obj = doku(this.name, { only:true , file:this.o.file }); this.o = obj; this.neuladen(!this.load); this.setButtonText(); } } hide(){ if(this.o.file && !this.load) { this.loader(); return; } this.neuladen(!this.load); this.setButtonText(); } setButtonText(e=this.hideButton,text='Skript ausführen , Ergebnis löschen'.split(',')){ e.value = !this.load ? text[0] : text[1]; } codemarker(bereich) { // Prüfen, ob hljs und die highlightAll()-Methode bereits verfügbar sind if (typeof hljs !== 'undefined' && typeof hljs.highlightAll === 'function') { // Highlight.js ist geladen, führe highlightAll() für den angegebenen Bereich aus hljs.highlightAll(bereich); } else if (typeof window.hljsLadenStatus === 'undefined') { // Highlight.js wird geladen window.hljsLadenStatus = true; // Setze den Status auf true // Dynamisch die Highlight.js-Datei laden html('tag link | rel stylesheet | href system/css/highlight.css', document.head ); var script = document.createElement('script'); script.src = 'system/js/highlight.js'; // Pfad zur Highlight.js-Datei // Sobald die Datei geladen ist, rufe hljs.highlightAll() auf script.onload = function() { hljs.highlightAll(bereich); // Highlight für den angegebenen Bereich nach dem Laden }; // Füge das Script-Tag in den Head-Bereich ein document.head.appendChild(script); } else { // Wenn hljsLadenStatus gesetzt ist und die Bibliothek noch nicht geladen wurde // console.warn('Highlight.js wird bereits geladen oder wurde zuvor geladen, aber die Funktion wird nicht aufgerufen.'); // Optional: Hier könnte man auch die highlightAll(bereich) für einen bereits geladenen Bereich aufrufen // hljs.highlightAll(bereich); } } neuladen(load) { if (this.notation) this.notation.set('w auto|op 1'); this.load = load; this.content.set('op 0'); this.EDcontent.close(); clearAllIntervals(); setTimeout(() => { this.content.empty(); this.toggle.set('display '+(this.load?'inline-block':'none')) ; this.toggle.value = (this.load?'aus':'ein')+'blenden'; if (!this.load) return; // Standardvariable //o = {}; this.loadScript(); this.content.set('dis block| op 1'); setTimeout(() => { this.EDcontent.open(); }, 501); }, 301); } } if(typeof lf === 'undefined' ) lf = {}; lf.ex = function( o , name ){ return new LFExClass( o , name ); } function getVariableName(variable) { // Beispiel zur Demonstration, vermeide die Verwendung von eval in der Praxis return eval(variable); } function doku(nn,obj={}){ // die funktion doku deaktivieren, wenn bereits alle scripte geladen sind // und die Funktion nur nachgeladen wird... if(lf.dokuInactivate && !obj.only) return; if( typeof nn === 'function' ) var f = nn.toString(); if( typeof nn === 'string' ){ var f = eval(nn).toString(), name = nn; } // zerlegen in Zeilen let a = f.split('\n'), o = obj||{}, k=nn , m=0 , temp = '' , counter=a.length , firstline=null ; for(var i in a){ counter--; if(typeof a[i] != 'string' ) continue; var z = a[i]; if(!z.trim() && k==nn ) continue; // Überschrift, erste namensgebende Zeile if(!firstline && z.trim().substr(0,3) != '//*'){ if(z.trim().substr(0,2) == '//') z = z.replaceAll('//', '//*'); else z = '//*'+z; firstline = true; } // letzte Zeile der Funktion if(z.trim() == '}' && !counter ) { temp ? o[k] = temp : 0; break; } // return nicht interpretieren if(z.trim().strstr('return')&& counter == 1 ) { temp ? o[k] = temp : 0; break; } // kommentierte Zeilen - Namensgeber für das Zeilenobjekt if(z.trim().substr(0,3) == '//*' ) { kTemp = z.split('//*'); kTemp[0].trim() ? temp += '\n'+kTemp[0] : 0; temp && temp.trim() ? o[k] = temp : 0; k = kTemp[1]; //k = z.trim().substr(0,2) == '//' ? z.split('//')[1] : z; temp = ''; m = 0; continue; } // Anführungszeichen aus text entfernen if (k && z.trim().startsWith('"')) { o[k + 'text'] = (o[k + 'text'] ?? '') + z.replaceAll('"', ''); } else if( k ){ m ? temp += '\n'+z : temp = z; m++; if( k.strstr("eval-") ){ temp = eval(z); k = k.replaceAll('eval-', ' '); } } } o.ex = 1; if(!obj.only) lf.ex( o , name ); return o; } /** Inhalt der Datei: expandDiv.js **/ /* setzt die html - funktion voraus - G. Stephan LFox 2024 */ class ExpandDiv { constructor(obj) { this.o = obj instanceof HTMLElement ? { node : obj } : obj; if(typeof this.o != 'object' ) return; this.content = this.o.node; this.setStandard(); this.sync(this.o); this.init(); this.status == false ? this.close() : this.status = true; // endcheck this.selfClick === true && this.min == undefined ? this.min = parseInt(this.content.style.fontSize)*1.5 || 20 : 0 ; } setStandard(){ this.selfClick = true; this.modus = 'height'; // height oder width this.time = this.o.time || 1; this.transition = `width ${this.time}s ease, height ${this.time}s ease, background-color 2s ease, opacity 2s ease`; //this.min = parseInt(this.o.min != undefined ? this.o.min : parseInt(this.content.style.fontSize)*1.5 || 20); //this.min = parseInt(this.content.style.fontSize)*1.5 || 20; } init() { // Container erstellen this.setContainer(); // Höhe des Containers auf die Höhe des Inhalts setzen this.setHeight(); // Event Verhalten this.setClick(); } sync(o){ for(let i in o){ //html('html->'+i) this[i] = o[i]; } } setClick(){ if( !this.selfClick ) return; this.content.addEventListener('click', () => { // bei CloseButton() return //this.selfClick == null //var m = this.selfClick == 'open' ? true : this.selfClick == 'close' ? false : null; this.closeButton ? this.open() : this.toggle(); }); this.content.addEventListener('dblclick', () => { this.close(); }); } setContainer(h) { let neu = this.container = this.content.cloneNode(false); let currentParent = this.content.parentNode , nextSibling = this.content.nextSibling ; this.container.appendChild(this.content); nextSibling ? currentParent.insertBefore( this.container , nextSibling ) : currentParent.appendChild( neu ); this.container.css({ transition : this.transition , ovf : 'hidden' , pad : 0 }); this.content.css({ mar : 0 , transition : 'background-color 2s ease , opacity 1s ease, color 2s ease, opacity 1s ease' }); if(this.closeButton){ //this.container.css('pos') == 'static' ? this.container.css('pos','rel') : 0; this.setCloseButton(); //this.selfClick = null; } //this.chanceText(); //dev //this.container.css('b->2px solid red'); //|box-sizing->border-box } setCloseButton(){ if( this.container.css('h','int')<150) return; this.closeButton = html('pos->rel|ta->center|h->1|ff->arial', this.container ); this.closeButton = html('pos->abs|br->50%|bgc->rgba(255,255,255,.7)|w=h->25|fs->20|top->-35|ri=bo->10|html->⇡|c->pointer', this.closeButton ); this.closeButton.onclick = ()=>{ this.close();} //console.log( this.container.css('pos') ); } chanceText( newText , htmlmodus=null ) { let element = this.content; //element.style.opacity = .2; setTimeout(() => { htmlmodus ? element.innerHTML = newText : element.textContent = newText; element.style.transition = 'none'; //element.style.opacity = 0; // Zwinge den Browser, das neue Styling zu rendern void element.offsetHeight; // Einlesen der Höhe, um Reflow zu erzwingen element.style.transition = `background-color 2s ease , opacity 2s ease`; element.style.opacity = 1; this.open(); }, 200 ); } refresh(){ let element = this.content; element.set('transition none'); element.set('h auto'); element.style.height = element.scrollHeight + 'px'; void element.offsetHeight; element.style.transition = `background-color 2s ease , opacity 2s ease`; this.open(); } chanceHTML(newText){ this.chanceText(newText,true); } getHeight(modus) { var modus = modus || this.modus; //return modus == 'width' ? this.content.offsetWidth : this.content.offsetHeight ; var w = this.content.style[modus].strstr('%') ? this.getProzentLength(modus) : this.content.offsetWidth; !w ? w = 100+'%' : 0; //console.log(w); return modus == 'width' ? w : this.content.offsetHeight ; } getProzentLength(modus){ let parentL = modus == 'width' ? this.content.parentElement.offsetWidth : this.content.parentElement.offsetHeight, elementL = modus == 'width' ? this.content.offsetWidth : this.content.offsetHeight, prozent = (elementL / parentL) * 100; return `${prozent.toFixed(2)}%`; } setHeight(h,modus) { this.container.style.height === 'auto' ? this.container.set('h '+ this.container.offsetHeight) : 0; //this.container.style[this.modus] = ( h != undefined ? h : this.getHeight() ) + 'px'; setTimeout( ()=>{ this.container.css( modus || this.modus , ( h != undefined ? h : this.getHeight(modus||this.modus) ) ); },100 ); lf.bugwait = true; setTimeout( ()=>{ lf.bugwait = false; } , 400 ); this.auto && h ? setTimeout( ()=>{ this.container.set('h auto') } , 1000 ) : 0; } toggle(m){ if(m != undefined) m == true ? this.open() : this.close(); else this.status == false ? this.open() : this.close(); } toggleText(e,text){ !this.tempText ? this.tempText = [ e.value ? e.value : e.innerHTML , text ] : 0; this.toggle(); var text = this.tempText[ this.status ? 1 : 0 ]; e.value ? e.value = text : e.html( text ); } open(x,modus){ this.setHeight( x || this.getHeight(modus) , modus ); // ausfahren if h || w < 1 this.container.getCss('w','int') < 1 ? this.setHeight( this.getHeight('width') , 'width' ) : 0 ; this.container.getCss('h','int') < 1 ? this.setHeight( this.getHeight('height') , 'height' ) : 0 ; this.status = true; } close(x,modus){ this.setHeight( x || this.min , modus ); this.status = false; } set(h,modus){ this.setHeight(h,modus); //this.container.css( modus || this.modus , ( h != undefined ? h : this.getHeight(modus||this.modus) ) ); //this.open(x,modus); } clear(){ // ....... } } /** Inhalt der Datei: farben.js **/ var cssColors = [ // Rottöne "IndianRed", "LightCoral", "Salmon", "DarkSalmon", "LightSalmon", "Crimson", "Red", "FireBrick", "DarkRed", // Orangetöne "OrangeRed", "Tomato", "Coral", "DarkOrange", "Orange", // Gelbtöne "Gold", "Yellow", "LightYellow", "LemonChiffon", "LightGoldenRodYellow", "PapayaWhip", "Moccasin", "PeachPuff", "PaleGoldenRod", "Khaki", "DarkKhaki", // Grüntöne "GreenYellow", "Chartreuse", "LawnGreen", "Lime", "LimeGreen", "PaleGreen", "LightGreen", "MediumSpringGreen", "SpringGreen", "MediumSeaGreen", "SeaGreen", "ForestGreen", "Green", "DarkGreen", "YellowGreen", "OliveDrab", "Olive", "DarkOliveGreen", "MediumAquaMarine", "DarkSeaGreen", "LightSeaGreen", "DarkCyan", "Teal", // Blautöne "Aqua", "Cyan", "LightCyan", "PaleTurquoise", "Aquamarine", "Turquoise", "MediumTurquoise", "DarkTurquoise", "CadetBlue", "SteelBlue", "LightSteelBlue", "PowderBlue", "LightBlue", "SkyBlue", "LightSkyBlue", "DeepSkyBlue", "DodgerBlue", "CornflowerBlue", "MediumSlateBlue", "RoyalBlue", "Blue", "MediumBlue", "DarkBlue", "Navy", "MidnightBlue", // Violetttöne "Lavender", "Thistle", "Plum", "Violet", "Orchid", "Fuchsia", "Magenta", "MediumOrchid", "MediumPurple", "BlueViolet", "DarkViolet", "DarkOrchid", "DarkMagenta", "Purple", "Indigo", "SlateBlue", "DarkSlateBlue", "MediumSlateBlue", "RebeccaPurple", // Brauntöne "Cornsilk", "BlanchedAlmond", "Bisque", "NavajoWhite", "Wheat", "BurlyWood", "Tan", "RosyBrown", "SandyBrown", "GoldenRod", "DarkGoldenRod", "Peru", "Chocolate", "SaddleBrown", "Sienna", "Brown", "Maroon", // Weiß-/Grautöne "White", "Snow", "HoneyDew", "MintCream", "Azure", "AliceBlue", "GhostWhite", "WhiteSmoke", "SeaShell", "Beige", "OldLace", "FloralWhite", "Ivory", "AntiqueWhite", "Linen", "LavenderBlush", "MistyRose", "Gainsboro", "LightGray", "LightGrey", "Silver", "DarkGray", "DarkGrey", "Gray", "Grey", "DimGray", "DimGrey", "SlateGray", "SlateGrey", "DarkSlateGray", "DarkSlateGrey", "Black" ]; /** Inhalt der Datei: gatter_class.js **/ class Gatter { constructor(obj) { this.zeilen = 10; this.spalten = 10; this.arrow = ['up','down','left','right']; // Wechsel mit Pfeiltasten this.swipe = ['up','down','left','right']; // Wechsel durch Scrollen this.vertical = cookie('Ordnung vertikal') === 'true'; this.zoom = new ZoomMan({clickable:true}); this.kreis = 'marL=w=h 5|br 50%|b 1px solid white|bgc green|dis ib|'; this.setContent = (i,t)=> true; //html('html '+i,parent); this.farbe = ['#001033']; //sortColors; this.Wechselautomatik = cookie('Wechselautomatik') === 'true'; this.SwipeReverse = cookie('SwipeReverse')==='true'; this.Richtungswechsel = cookie('Richtungswechsel')==='true'; this.activeIndex=null; this.lastActiveIndex=null; this.anzeigen=[]; this.sync(obj); this.init(); } sync(o){ for(let i in o){ this[i] = o[i]; } } cButton(obj={}){ html(stil.button+`html ${obj.text}|`+obj.css,obj.parent).onclick = function(event){ event.stopPropagation(); obj.f(); } } save = Array.from({ length: this.zeilen*this.spalten }, (_, i) => (i === 33 || i === 44) ? true : null); setNumbers(){ this.numbers = this.vertical ? this.setVerticalNumbers(this.zeilen, this.spalten) : new Array(this.zeilen*this.spalten).fill(); } init(){ this.a = []; // css classe .ovl laden bzw erstellen !isClassDeclared('ovl') ? html('tag style | textContent '+ gattercss , document.head ) : 0; this.cc = html('w=h 100% | z 199| to=le 0px| ovf hidden| dis none' , this.node ); this.cc.set(`position ${ this.node ?'absolute': 'fixed'}`); this.setNumbers(); this.setGatter(); this.setSwipe(); this.pref(); // Einstellungen // setInterval( ()=> this.observeHash(), 800 ); } setContent(index,content){ //this.a[index] = content; } direction(i,direction){ var a = this.a[i]; if(a && direction) a.direction = direction; return !a ? null : a.direction; } checkArrowParent(parent){ // pfeiltasten child nur aktiv, wenn parent im sichtfeld return (parent && parent.Gatter.a[parent.Gatter.activeIndex] !== parent) } warten() { this.wait = true; setTimeout(() => { this.wait = false; }, 650); } setArrow(event){ //console.log( this.checkArrowParent(this.parent) ) if( this.wait || this.checkArrowParent(this.parent) ) return; if(this.activeIndex===null) return; this.warten() var idx = this.activeIndex || 0, k=event.key, r = cookie('ArrowReverse') === 'true'; if(this.zoom.active) return; ['ArrowLeft','ArrowRight','ArrowDown','ArrowUp'].includes(k) ? event.preventDefault() : 0; k === 'ArrowLeft' ? this.run1(idx, r ? 'right' : 'left','arrow') : k === 'ArrowRight' ? this.run1(idx, r ? 'left' :'right','arrow') : k === 'ArrowDown' ? this.run1(idx,r ? 'up' :'down','arrow') : k === 'ArrowUp' ? this.run1(idx,r ? 'down' :'up','arrow') : 0; } setSwipe(){ // Pfeiltasten if(this.arrow) document.addEventListener('keydown', (event) => this.setArrow(event) ); // Scrollen if(this.swipe) swipen( this.cc , { up: () => this.run1(false,'up','swipe'), down: () => this.run1(false,'down','swipe'), left: () => this.run1(false,'left','swipe'), right: () => this.run1(false,'right','swipe'), run : (d)=> { if(this.wait) return null;; this.warten() return this.getCorrectDirection(d); } , // Bedingung für jede Richtung scroll : (event)=> { return this.getCorrectScroll(event); } , // Bedingung für jede Richtung all : this.swipeParent||false , // Swipen des Parent setzt sich durch //run : (e)=> { console.log(e === this.cc); return e === this.cc; } // Bedingung für jede Richtung }); //console.log(this.swipeParent) } getCorrectDirection(d){ if( !this.a[this.activeIndex] || !this.a[this.activeIndex].direction) return true; return this.a[this.activeIndex].direction.includes(d) ; } getCorrectScroll(event){ //return true; if( !this.a[this.activeIndex] || !this.a[this.activeIndex].scroll ) return true; let target = event.target, result = target; while (target) { // Wenn ein swipe-fähiges Element gefunden wird, prüfe, ob das Event darauf oder innerhalb seiner Kinder ist if (target.isscrolled) { result = target; // Gibt das swipe-fähige Element zurück break; } target = target.parentElement; // Gehe zum Parent } //console.log( (result !== this.a[this.activeIndex].scroll) ) return result !== this.a[this.activeIndex].scroll; } writeBox(parent,m,idx){ var c = html('', parent ); var a=[]; this.a.forEach((number,idx)=>{ const i = idx, //(this.vertical?(this.numbers[idx]-1):idx), farbe = this.farbe[ i % this.farbe.length ]; if(!m && i && (farbe !== this.farbe[(i-1) % this.farbe.length]) ) html('clear left | h 1 | w 100%', c ); var e = html( stil.box + stil.center + `cn app | dis none |` +`title ${i+' '+idx+' '+farbe} | html ${ i+1 }| bgc `+farbe , c ); e.set('w=h clamp( 67px, 10vw, 80px )| margin clamp( 1px, 10vw, 2px )| col '+ getTextColor(rgbToHex(e.css('bgc')),.4) ); e.onclick = ()=> this.open(i, this.activeIndex && i < this.activeIndex ? 'down' : 'up'); a[ i ] = e ; }); //idx ? this.setScrollable( idx , c ) : 0; // html('clear left | h 60 | w 100%', c ) this.anzeigen.push(a); return a; } // Gatterübersicht writeGatter(parent){ var c = html('fs 0|cn grid-c', parent ), a=[]; c.style.gridTemplateColumns = `repeat(${this.spalten}, 1fr)`; // Gleichmäßige Spalten c.style.gridTemplateRows = `repeat(${this.zeilen}, 1fr)`; // Gleichmäßige Zeilen this.a.forEach((number,idx)=>{ const i = (this.vertical?(this.numbers[idx]-1):idx), farbe = this.farbe[ i % this.farbe.length ]; var e = html( stil.center+`title ${i+' '+idx+' '+farbe}|pos rel|cn colorbox | html ${ i+1 }| ovf hidden| bgc `+farbe , c ); e.set('c pointer|col '+ getTextColor(rgbToHex(e.css('bgc')),.4) ); e.onclick = ()=> this.open(i, !this.activeIndex===null || i e.set a[ i ] = e ; // save //var s = html(this.kreis+'pos abs|ri=to 3|bgc transparent',e); //s.onclick = ()=>{ setSave(i); } //this.save[i]?s.set('bgc red|op .9') :0; }); this.anzeigen.push(a); return a; } setGatter(){ this.numbers.forEach((number,idx)=>{ const i = (this.vertical?(number-1):idx), farbe = this.farbe[ i % this.farbe.length ]; //e = html( `title ${i+' '+idx+' '+farbe}|pos rel|cn colorbox | html ${ i+1 }| ovf hidden| bgc `+farbe , this.c ), var el = html( stil.center +`fs 80|cn ovl |dis none| ovf hidden| bgc `+ farbe , this.cc ), bc = html( 'z 3|pos absolute |op 0|z 10| fs 14| bo 5% | dis none | w auto ' , el ); this.a[ i ] = el; //el.monitor = e; el.scrollF = {}; el.Gatter = this; if(this.counter){ // zum Testen - Zähler // Kreis var n = html(stil.center +'pos abs|w=h 150|z 2|dis none|cn zahlen|br 50%|bgc teal|col white|b 0px solid white|html '+(i+1),el); if(cookie('Nummer einblenden')==='true') n.set('dis flex'); html('pos abs|bo 23|fs 12|text '+farbe , n ); n.onclick = (event)=> { event.stopPropagation(); n.set('trans opacity 1s ease | op 0'); setTimeout(()=>n.set('dis none'),1000); } // Button rechts unten var cl = html(stil.center+stil.button+'dis none|br 50%|html X|pos abs|ri=bo 5|w=h 20',el); cl.onclick = (event)=> { event.stopPropagation(); this.close(); this.active = false; } // Button links unten html(stil.button+'br 50%|html ⚙️|pos abs|le=bo 5|w=h 20',el).onclick = (event)=> { event.stopPropagation(); bc.set( 'op ' +(bc.css('op')==1?0:1) ); n.set('op 1|dis flex'); bc.set( 'dis ' +(bc.css('op')==0?'none':'inline-block') ); cl.set( 'dis ' +(bc.css('op')==0?'none':'inline-block') ); } } //el.forbidden = this.forbidden || []; this.directions ? this.direction(i,this.directions):0; //content el.content = html(stil.box+'bfv hidden|z 1|ovfY scroll|pos abs|w=h 100%|ta left|pad 15|dis block|le=to 0',el) el.content.set('fs clamp(20px, 3vw, 25px)'); el.content.set('col '+ getTextColor(rgbToHex(el.css('bgc')),.4) ); this.setContent(i,this); //button var cButton = this.cButton; cButton({parent:bc,f:()=>this.run(false,'left'),text:'links',key:'ArrowLeft'}); cButton({parent:bc,f:()=>this.run(false,'down'),text:'unten',key:'ArrowDown'}); //cButton({parent:bc,f:()=>{el.set('dis none|le=ri=bo auto|to -100%');cc.set('dis none');},text:'X'}); cButton({parent:bc,f:()=> this.pref.toggle(),text:'⚙️'}); // cButton({parent:bc,f:(event)=>setRotable(el),text:'R'}); cButton({parent:bc,f:()=>this.run(false,'up'),text:'oben'}); //html('t br',bc) cButton({parent:bc,f:()=>this.run(false,'right'),text:'rechts'}); cButton({parent:bc,f:()=> { el.Bild = el.Bild ? false : true; event.target.set('op '+(el.Bild?1:.5)); }, text:'Bild',css:'op .5'} ); /**/ //cButton({parent:bc,f:sethash , text:'Hash lesen' } ); }); } setVerticalNumbers(zeilen, spalten){ const numbers = Array(zeilen * spalten).fill(null); // Vertikale Nummerierung berechnen let number = 1; for (let col = 0; col < spalten; col++) { for (let row = 0; row < zeilen; row++) { const index = row * spalten + col; // Boxen horizontal im DOM numbers[index] = number++; // Nummerieren nach vertikaler Logik } } return numbers; } isElementInViewport(el) { // Funktion zum Prüfen von Sichtbarkeit (display, visibility, opacity) const isVisible = (el) => { const style = window.getComputedStyle(el); return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'; }; // Überprüfe das Element und alle seine Eltern while (el) { const rect = el.getBoundingClientRect(); // Wenn das Element oder ein Elternteil unsichtbar oder außerhalb des Viewports ist, return false if (!isVisible(el) || rect.top > window.innerHeight || rect.bottom < 0 || rect.left > window.innerWidth || rect.right < 0) { return false; } el = el.parentElement; // Gehe zum nächsten Elternteil } return true; } // function, die beim verlassen des aktiven Feldes ausgelöst wird onleave(idx){ if( idx==='undefined' || !this.a[idx]) return; var e = this.a[idx]; if(e.onleaveF && typeof e.onleaveF === 'function' ) e.onleaveF(); } onready(idx){ if( idx==='undefined' || !this.a[idx]) return; var e = this.a[idx]; if(e.onreadyF && (typeof e.onreadyF === 'function') ) e.onreadyF(); } // individuelle Scrollfunction setScrollF(idx,direction,f){ this.a[idx].scrollF[direction] = f; } getScrollF(idx,direction){ if( !this.a[idx].scrollF[direction] ) return false; this.a[idx].scrollF[direction](this); return true; } scroll(idx,direction){ var a = this.a[idx]; //if(a && direction) a.scroll = direction; //return !a ? null : a.scroll; } // scrollbare Bereiche setScrollable(idx,area){ var area = area||this.a[idx].content; area.isscrolled = true; this.a[idx].scroll = area; this.parent ? this.parent.scroll = area : 0; } // mit Filter run1(idx , direction , type ){ if(type === 'arrow' && this.arrow && !this.arrow.includes( direction ) ) return; if(type === 'swipe' && this.swipe && !this.swipe.includes( direction ) ) return; if(this.activeIndex===null) return; if(idx===false) var idx = this.activeIndex || 0; if( this.a[idx].direction && !this.a[idx].direction.includes( direction ) ) return; if( this.getScrollF(idx,direction) ) return; this.run( idx , direction ); } run2(idx , direction , next , fromHash=null ){ this.run( idx , direction , next , fromHash ) } run( idx , direction , next , fromHash=null ){ if(this.activeIndex===null) return; if(idx===false) var idx = this.activeIndex || 0; if(this.SwipeReverse){ // cookie('SwipeReverse')==='true' //var direction = this.reverse(direction); } var m = ['up','down'].includes(direction), i = next != null ? next : this.getNext( idx , direction ), a = this.a; // einschränkung if(!next && !m && cookie('Nur vertikal wechseln')==='true') return; else if(!next && m && cookie('Nur horizontal wechseln')==='true') return; if(!next && this.save[idx]==='shot') return; // überspringen , gesperrt if( !next && this.save[i]) { while(!this.a[i] || this.save[i] ){ i = this.getNext( i , direction ); } } // überspringen , wenn kein inhalt if( !next && cookie('Nur Inhalte')==='true' ){ var q = this.a.length; while ( this.save[i] || !a[i] || !this.isContent(a[i])) { i = this.getNext(i, direction); // Berechne i neu if(!q--) break; } i = (i + a.length) % a.length; } if(idx === i || !this.a[i]) return; if(direction === 'left') { var le = 'le', ri = 'ri'; } else if(direction === 'right') { var le = 'ri', ri = 'le'; } else if(direction === 'up') { var le = 'to', ri = 'bo'; } else if(direction === 'down') { var le = 'bo', ri = 'to'; } var index = (i + this.a.length) % this.a.length, n = this.a[ index ], e = this.a[ idx ]; if( !n ){ alert('ungültig'); return; } // transition ab- und zuschalten var transition = 'transition all .5s ease|'; var trans = next && !direction ? 'transition none|' : transition; n.set('dis flex|'+(m?'ri=le 0':'to=bo 0')); n.set(`${le} auto | ${ri} -100%`) //stil.transition+ e.set( trans + `${ri} auto | ${le} 0 `); //this.activeIndex = index; setTimeout( ()=>{ e.set(` ${le} -100%`); n.set( trans + `${ri} 0`); //if(cookie('Nummer einblenden')==='true') // if( n.children[1]) n.children[1].set('dis '+(cookie('Nummer einblenden')==='true' ? 'flex' : 'none') ); return; // pjotr if( this.isContent( n,true ) === 2 ){ var p = n.querySelectorAll('.pjtr')[0]; if(p.pjotr) p.pjotr.run(); } } , 100 ); setTimeout( ()=> { e.set('transition none'); // && a.indexOf(n) != this.activeIndex if ( a.indexOf(e) != this.activeIndex ) e.set('display none'); this.onleave(idx); this.setAnzeigeIcon(this.activeIndex,1); this.setAnzeigeIcon(this.lastActiveIndex,1) // löschen this.lastActiveIndex = this.activeIndex; this.setAnzeigeIcon(this.lastActiveIndex,2); //!this.lastActiveIndex ? this.lastActiveIndex = index : 0; this.activeIndex = index; this.setAnzeigeIcon(this.activeIndex,3); setTimeout( ()=>this.onready(index) , 500 ); if(!fromHash && !this.parent && cookie('Hash')==='true') document.location.hash = index+','+direction; } , 620 ); // e.set('le=ri=bo=to auto'); } getNext(num, direction, columns = this.spalten, rows = this.zeilen, isVertical = this.vertical) { if(this.activeIndex===null) return; const currentIndex = num; // Die aktuelle Position let currentRow, currentCol; // Richtungsumkehr if ( this.Richtungswechsel ) { // const reverse = { right: 'left', left: 'right', up: 'down', down: 'up' }; direction = this.reverse(direction); //reverse[direction]; } // Aktuelle Position bestimmen if (isVertical) { // Vertikale Zählweise: Spalten werden zuerst gefüllt currentCol = Math.floor(currentIndex / rows); // Spalten-Index currentRow = currentIndex % rows; // Zeilen-Index } else { // Horizontale Zählweise: Zeilen werden zuerst gefüllt currentRow = Math.floor(currentIndex / columns); // Zeilen-Index currentCol = currentIndex % columns; // Spalten-Index } let newRow = currentRow; let newCol = currentCol; // Bewegung basierend auf der Richtung if (direction === 'right') { if (isVertical) { // Rechts in der vertikalen Zählweise: Nächste Spalte newCol = (currentCol + 1) % columns; } else { // Rechts in der horizontalen Zählweise: Nächste Spalte newCol = (currentCol + 1) % columns; } } else if (direction === 'left') { if (isVertical) { // Links in der vertikalen Zählweise: Vorherige Spalte newCol = (currentCol - 1 + columns) % columns; } else { // Links in der horizontalen Zählweise: Vorherige Spalte newCol = (currentCol - 1 + columns) % columns; } } else if (direction === 'down') { if (isVertical) { // Unten in der vertikalen Zählweise: Nächste Zeile newRow = (currentRow + 1) % rows; } else { // Unten in der horizontalen Zählweise: Nächste Zeile newRow = (currentRow + 1) % rows; } } else if (direction === 'up') { if (isVertical) { // Oben in der vertikalen Zählweise: Vorherige Zeile newRow = (currentRow - 1 + rows) % rows; } else { // Oben in der horizontalen Zählweise: Vorherige Zeile newRow = (currentRow - 1 + rows) % rows; } } else { throw new Error("Ungültige Richtung! Benutze 'left', 'right', 'up' oder 'down'."); } var s = cookie('Stopautomatik') === 'true'; if(this.Wechselautomatik||s){ if( newRow < currentRow && direction === 'down') newCol = (newCol + 1) % columns; else if( newRow > currentRow && direction === 'up') newCol = (newCol - 1 + columns) % columns; if( newCol < currentCol && direction === 'right') newRow = (newRow + 1) % rows; else if( newCol > currentCol && direction === 'left') newRow = (newRow - 1 + rows) % rows; if(s && ( newRow != currentRow && newCol != currentCol) ){ cookie('Stopautomatik Warnung') === 'true' ? myConfirm('Ende erreicht') : 0; return; } } // Berechnung der neuen Position if (isVertical) { // Vertikale Zählweise return newCol * rows + newRow; } else { // Horizontale Zählweise return newRow * columns + newCol; } } setAnzeigen(index,text,t){ setTimeout( ()=> this.anzeigen.forEach( (a)=> { if(t) text = t.innerText!='Titel'? t.innerText: text; a[index].innerHTML = text.substr(0,30) ; a[index].title = text; a[index].set('dis flex'); } ) , 300 ); } // Border der aktiven Sites setzen setAnzeigeIcon(index,modus=0){ if(index === null || this.activeIndex === null) return; this.anzeigen.forEach( ( el , idx )=> { //el.playIcon ? el.playIcon.destroy() : 0; if(modus && modus<2) { el[index].set('b '+ el[index].getAttribute('data-border') ); return ; } //if(modus!==2) el.playIcon = html(stil.center+'br 50%|w=h 20|bgc white|b 1px solid gray|pos abs|to=le 0|fs 10|html 🔈' , el[index] ); !el[index].getAttribute('data-border') ? el[index].set('data-border '+el[index].css('b')) : 0; el[index].set( modus === 2 ? 'b 2px dashed white |' : 'b 2px solid white |' ); }) } setAudioIcon(index,modus){ this.anzeigen.forEach( ( el , idx )=> { el.playIcon ? el.playIcon.destroy() : 0; if(modus && modus!==2) { delete el.playIcon ; el[index].set('b '+ el[index].getAttribute('data-border') ); return ; } if(modus!==2) el.playIcon = html(stil.center+'br 50%|w=h 20|bgc white|b 1px solid gray|pos abs|to=le 0|fs 10|html 🔈' , el[index] ); !el[index].getAttribute('data-border') ? el[index].set('data-border '+el[index].css('b') ) : 0; el[index].set('b 2px dashed white |'); }); } getSwipe(direction){ return this.SwipeReverse ? this.reverse(direction) : direction; } reverse(direction){ var reverse = {right:'left',left:'right', up:'down',down:'up'}; return reverse[direction]; } observeHash(){ var h = document.location.hash.replace('#','').split(','), hash = parseInt( h[0] ); if( this.activeIndex === hash || !this.a[ hash ] ) return; //console.log( h[1] + this.reverse( h[1] ) ) //this.hash = true; //this.run( false , h[1] , hash , true ); this.open(hash, h[1]) } isContent(el,m){ const img = Array.from(el.children).some(child => child.classList.contains('img') ); const pjtr = Array.from(el.children).some(child => child.classList.contains('pjtr') ); if(m) return img ? 1 : pjtr ? 2 : false; return ( this.content || pjtr || img || (el.content && trim(el.content.html())) )?true:false; } // ------------------------------------- E I N S T E L L U N G E N ---------------------- pref(){ var pref = this.pref = new Overlay({css:'bgc DarkSlateGrey'}), setPref = this.setPref; pref.layer.empty(); pref.container = html( 'cn s|br 5|w=h 60% | bgc lightgray | color black | fs 15 | dis block | ta left | pad 5' , pref.layer ); // Überschrift var div = html( stil.center +'mar 1|w 100%| h 170 | color white', pref.container ); div.set('h 100| bgc gray | html Einstellungen | fs clamp( 15px, 6vw, 50px)'); // Close-Button html( stil.close , pref.container ).onclick = ()=> pref.toggle(false); this.setPref({ text:'Richtungswechsel' , default : false , help:'Kehrt die Richtung um, aus der die Inhalte kommen, rechts zu link, oben zu unten, abhängig von Swip- oder Pfeilrichtung.'}); this.setPref({ text:'ArrowReverse' , default : false , help:'Wechselt das Pfeilrichtungsverhalten'}); this.setPref({ text:'SwipeReverse' , default : false , help:'Wechselt die Swiprichtung'}); this.setPref({ text:'ScrollReverse' , default : false , help:'Wechselt die Scroll- und Pfeilrichtung'}); this.setPref({ text:'Ordnung vertikal' , default : false , help:'Ordnet die Zahlen vertikal, statt horizontal'}); this.setPref({ text:'Farbspektrum' , default : false , help:'Farbspektrum'}); this.setPref({ text:'Nur Inhalte' , default : false , help:'Beim Durchswipen nur Datensätze mit Inhalten anzeigen.'}); this.setPref({ text:'Nur vertikal wechseln' , default : false , help:'Horizontalen Wechsel unterbinden.'}); this.setPref({ text:'Nur horizontal wechseln' , default : false , help:'vertikalen Wechsel unterbinden.'}); this.setPref({ text:'Save aktiv' , default : false , help:'Gesperrte Felder im Swipen unterbinden.'}); this.setPref({ text:'Wechselautomatik' , default : false , help:'Automatischer Spalten- und Zeilenwechsel'}); this.setPref({ text:'Stopautomatik' , default : false , help:'Stoppt bei Spalten- und Zeilenende'}); this.setPref({ text:'Stopautomatik Warnung' , default : false , help:'Warnt bei Spalten- und Zeilenende'}); this.setPref({ text:'Autoplay' , default : false , help:'Videos oder Audios starten automatisch beim Wechseln auf die Seite des Videos '}); this.setPref({ text:'Autostop' , default : false , help:'Videos oder Audios stoppen automatisch beim Verlassen der Seite.'}); this.setPref({ text:'Hash' , default : false , help:'Setzt beim Wechsel der Tafeln einen Hash'}); this.setPref({ text:'Editable' , default : false , help:'Texte bearbeiten'}); this.setPref({ text:'Nummer einblenden' , default : false , help:'Kreis mit Zähler beim Aufruf einer Tafel einblenden.'}); this.setPref({ text:'HLS' , default : false , help:'HLS für Video ein'}); this.setPref({ text:'Fernseher' , default : false , help:'Fernseher'}); this.setPref({ text:'Youtube' , default : false , help:'Youtube abspielen'}); } setPref(obj={}){ var att = 'html '+obj.text , pref = this.pref, button = html( stil.button + att , pref.container ); obj.att ? button.set(obj.att) : 0; obj.help ? button.title = obj.help : 0; // Erklärung, Hilfe button.onclick = ()=>{ var e = event.target, status = e.css('op') < 1 ? false : true; e.set('op '+(status ? .5 : 1 ) ); cookie( obj.text , !status ); this[ obj.text ] = !status; //console.log(cookie(obj.text)) } var m = cookie(obj.text) === null ? obj.default : cookie(obj.text)==='true' ; button.set('op '+( (m?1:.5) )); } destroy(i){ if(!this.a[i]) return; this.a[i].destroy(); this.a.splice(i,1); } close(index=null,direction='up'){ this.activePlayer ? this.activePlayer.pause() : 0; var nextindex = ( this.activeIndex-1 + this.a.length) % this.a.length; this.a[ nextindex ].set('op 0'); this.run2( false , direction, nextindex ); //this.activeIndex = null; // !!!!!!!!!! setTimeout( ()=> { this.a[ nextindex ].set('op 1'); this.setAnzeigeIcon(nextindex,1) this.a.forEach( (el,idx)=> { if(index!==null && idx === index) return; el.set('dis none|le=ri=bo auto|to -100%'); this.onleave(idx); }); if(index!==null) return; this.cc.set('dis none'); this.activeIndex = null; }, 800); } open(index,direction='down'){ if( this.activeIndex != null ){ this.run2( false, direction, index ); return; //alert(4) } this.cc.set('dis block'); this.activeIndex = index; var preindex; setTimeout( ()=>{ preindex = (index-1 + this.a.length) % this.a.length this.a[ preindex ].set('dis flex|op 0'); this.run2( preindex , direction, index ); } , 100 ); //this.a[index].set('dis flex|to=le 0 '); setTimeout( ()=>{ this.onready(index); this.a[ preindex ].set('op 1'); this.setAnzeigeIcon( preindex ,1) } , 700 ); if( !this.parent && cookie('Hash')==='true' ) document.location.hash = index+','+direction; } next(direction){ var i = (this.activeIndex||0)+1; i>=this.a.length?i=0:0; this.open( i , direction ) } destroy(){ this.cc.destroy(); } } /** Inhalt der Datei: petersburg_class.js **/ class Petersburg { constructor(elements , obj={} ) { this.elements = elements; this.f = obj.f; this.obj = obj; //this.height = 80; this.display = this.elements[0].style.display || 'block'; this.run(); this.setResize(); } berechnung( el ){ setTimeout( ()=> { var w = this.type === 'img' ? el.naturalWidth : el.offsetWidth , h = this.type === 'img' ? el.naturalHeight : el.offsetHeight , calculatedWidth = (w/h) * this.height, calculatedHeight = (h/w) * this.width; //this.obj.modus === 'w' ? el.ph.set('h ' + calculatedHeight ) : if (!this.obj.wh) el.ph.set('w ' + calculatedWidth ) ; //el.ph.setAttribute('data-width',calculatedWidth); this.calculateAndMoveImages(); }, 10 ); } // Funktion, um die Positionen der Bilder zu berechnen und sie an die neuen Orte zu bewegen calculateAndMoveImages() { // Setzt die Bilder auf die Positionen der Platzhalter this.elements.forEach( ( element )=> { var x = element.ph.offsetLeft, y=element.ph.offsetTop; if (this.obj.wh){ if(element.offsetWidth > element.offsetHeight) { y += (element.ph.offsetHeight-element.offsetHeight)/2; } else { x += (element.ph.offsetWidth-element.offsetWidth)/2; } //console.log(element.offsetHeight) } !this.obj.hardbreak ? element.set('trans all .5s ease-in-out'):element.set('dis '+this.display);; element.style.transform = `translate(${x}px, ${y}px)`; }); } run() { this.elements.forEach( ( el , idx )=> { !this.type ? (this.type = el.tagName.toLowerCase() === 'img' ? 'img' : 'div') : 0; !this.width ? this.width = el.offsetWidth||this.obj.wh : 0; !this.height ? this.height = el.offsetHeight||this.obj.wh : 0; //platzhalter - trans all .5s ease-in-out | le=to 0 el.set(' pos absolute | clear left |display '+this.display+' | z 2 | le=to 0 '); !this.obj.hardbreak ? el.set('trans all .5s ease-in-out'): el.set('dis none'); if(!el.ph){ el.ph = html(`z 1| float left | h=w ${ this.height } | pos rel`, el.parentNode ); el.ph.set('mar '+ el.css('mar') ); el.set('mar 0'); } //el.ph.set('bgc orange' ); el.P = this; var t = this; if(this.f) el.addEventListener('click', function(){ t.f(this); }); /**/ if (this.type === 'img') { //if(this.f) el.onload = ()=>{ this.berechnung(el); } } else { // Für Divs: die Funktion direkt ausführen, da es kein onload gibt. this.berechnung(el); } }); } setResize(){ let resizeTimeout; window.addEventListener('resize', () => { clearTimeout(resizeTimeout); // Warten, bis das Resizing abgeschlossen ist resizeTimeout = setTimeout(() => { this.calculateAndMoveImages(); }, 200); // 200ms Wartezeit nach dem Ende des Resizings }); } } /** Inhalt der Datei: rotable.js **/ /* ---------- Gunthard Stephan 7 24 ----------- LFox -------------- */ const RotableSymbol = Symbol('Rotable'); class Rotable { constructor(obj) { // prüfen, ab bereits elem der instanz if (Rotable.isRotable( obj.node = obj.node || obj.n || obj )) { //console.log('Dieses Element ist bereits eine Rotable-Instanz.'); // Prüfen, ob copy gesetzt ist if(obj.copy) obj.node = this.cloneNode( obj ); else throw new Error('Element ist bereits eine Rotable-Instanz.'); } else if(obj.copy) obj.node = this.cloneNode( obj ); this.o = obj instanceof HTMLElement ? { node : obj } : obj; this.o = this.str_to_obj(this.o); this.o.n ? this.o.node = this.o.n : 0; this.front = this.o.node; this.deg = 0; // Parameter des Obj synchronisieren this.sync(this.o); // Rotationstyp this.initRotations(); // wesentliche Parameter setzen und synchronisieren this.initParams(); this.syncParams(); // Frontseite setzen this.setupNode(); // Container this.createContainers(); // Rückseite setzen this.initBack(); // Typ bestimmen - Images usw this.setType(); // Clickverhalten this.addClickListener(); this.addBackClick() // //this.updateNodePosition(); // Symbol setzen zur eindeutigen Identifizierung der Klassenzugehörigkeit this.front[RotableSymbol] = true; } sync(o){ for(let i in o){ this[i] = o[i]; } } static isRotable(node) { return node && node[RotableSymbol] === true; } str_to_obj(o) { // für die Umwandlung von String zu Objekt o = sto(o); return o; } setType(){ //console.log('hu'); if(!this.type) return; //console.log('hallo'); if( typeof(this.type) === 'object' && this.type.name == 'images') this.setImages(); } setImages(){ var suffix = this.type.suffix || ''; this.front.css('bgs->cover|bgp->center|bgi->'+this.type.images[0]+suffix ); } cloneNode( o ){ var e = o.node.cloneNode(false), parentN = o.parent || document.body; return parentN.appendChild(e); var e = o.node.cloneNode(false), parentN = o.parent || document.body; //return parentN.appendChild(e); return o.node.parentNode.lastChild.insertBefore( e , parentN.lastChild.nextSibling ); } initRotations() { this.rot = { a: this.o.rotation === 'v' ? 'rotateX(0deg)' : //this.o.rotation === 've' ? `rotateX(${this.deg}deg)` : //this.o.rotation === 'he' ? `rotateY(${this.deg+=360}deg)` : this.o.rotation === 'd' ? 'rotateX(0deg) rotateY(0deg)' : 'rotateY(0deg)', b: this.o.rotation === 'v' ? 'rotateX(180deg)' : //this.o.rotation === 've' ? `rotateX(${this.deg}deg)` : //this.o.rotation === 'he' ? `rotateY(${this.deg+=180}deg)` : this.o.rotation === 'd' ? 'rotateX(180deg) rotateY(360deg)' : 'rotateY(180deg)' }; this.o.sicht = this.o.rotation === 'd'; } initParams() { this.params = { 'backface-visibility': 'visible', 'transformStyle': 'preserve-3d', 'transition': 'all 1s ease', transform: this.rot.a, 'box-sizing': 'border-box', pos: 'absolute' }; this.paramsC1 = { 'perspective': '300px', 'backface-visibility': 'hidden', // rückseite der rückseite nicht sichtbar pad:0, mar:this.front.style.margin || 0, pos: this.front.css('position'), w: this.front.style.width || '100%', h: this.front.style.height == ('auto'||'') ? this.front.offsetHeight : this.front.style.height || '100%', //h: this.front.style.height, // || '100%', le: this.front.css('le'), ri: this.front.css('ri'), to: this.front.css('to'), bo: this.front.css('bo'), br: this.front.css('br'), dis: this.front.css('dis'), float: (this.front.css('float') || 'none'), 'name' : 'c1', 'box-sizing': 'border-box' , //bgc : 'green' }; //console.log( this.front.style.height ) } syncParams() { let sync = (p,m) => { for (let i in this.o) { let s, l = lf.short[i] && lf.short[i] !== 'undefined' ? lf.short[i] : i; lf.styleCommands.inArray(s = lf.cssToJsParameter(i)) ? l = s : 0; if (p[i] || p[l] || p[lf.shortReverse[i]] || p[lf.shortReverse[l]]) { delete p[i]; delete p[lf.shortReverse[i]]; delete p[lf.shortReverse[l]]; p[l] = this.o[i]; } } }; sync(this.params,true); sync(this.paramsC1); //html('html->' ).innerHTML = JSON.stringify( this.params ); } setupNode() { this.oldParams = {}; for (let i in this.params){ this.oldParams[i] = this.front.css(i); //html('html->1').innerHTML = i + this.front.css(i); } var params = 'w,h'.split(','); this.front.css(this.params); this.front.Rotable = this; } copyCss(vorlage,copie,original){ for (let i in vorlage){ copie[i] = original.css(i); //html('html->1').innerHTML = i + this.front.css(i); } //this.front.css(this.params); } createContainers() { if (!this.o.c1) this.c1 = html(this.paramsC1, this.front, 3); if (!this.o.c2) this.c2 = html(' box-sizing border-box | name c2|mar->0|pos->rel|w=h->100%|transform-style -> preserve-3d|transition->transform 1s | bgc->none|transform->'+this.rot.a, this.front, 3); this.front.set('w=h 100% | mar 0'); } set(w,h){ var params = { w:w , h:h , transition : 'all 1s ease' }; this.c1.set(params); this.c2.set(params); } changeTag(oldElement, newTagName) { const newElement = document.createElement(newTagName); // Attribute kopieren for (const attr of oldElement.attributes) { newElement.setAttribute(attr.name, attr.value); } // Inhalt kopieren newElement.innerHTML = oldElement.innerHTML; // Neues Element an die Stelle des alten Elements einfügen oldElement.parentNode.replaceChild(newElement, oldElement); return newElement; } newBack( back ){ if (!this.back || this.wait ) return this.wait = true; // bild durch div ersetzen if(this.back.tagName == 'IMG'){ var neu = this.changeTag(this.back , 'DIV' ); this.back = neu; } else this.back.empty(); let b = this.back.appendChild( this.backOriginal ); b.css({ transform : this.rot.b, bfv: 'hidden', br : 0 , mar:0, w: '100%', h: '100%' }); // 'rotateY(90deg) scaleX(-1)' let bb = new Rotable( { node : b , back : back , rotation : this.o.rotation } ); bb.clickFunc(); setTimeout( ()=> { bb.clear(); this.back.onclick = null; this.back.remove(); this.o.back = back ; //alert( this.front ) this.initBack(); this.addBackClick(); this.wait = false; }, 1000 ); } oldnewBack( back , node1 ){ if (!this.o.back) return this.o.back.onclick = null; this.o.back.remove(); //this.front = node; this.o.back = back ; //alert( this.front ) this.initBack(); this.addBackClick(); //return this; } initBack() { if( !this.o.back ) return; if (typeof(this.o.back) === 'object') { // kopie des originals this.backOriginal = this.o.back.cloneNode(true); this.back = this.o.back.cloneNode(true); this.c2.appendChild(this.back); } else if (typeof(this.o.back) !== 'object') { // parameter statt true this.o.back != true ? this.o.setBack = this.o.back : 0; this.back = html( this.params , this.c2); this.back.name = 'back'; this.o.myback = true; this.backOriginal = this.back.cloneNode(true); if (this.o.inherit) { //this.o.back.cloneCss( this.front ); //this.front.css({'backface-visibility': 'hidden'}); //this.front.setCss('bfv -> hidden'); } } this.back = this.back || this.o.back; this.back.Rotable = this; if (typeof(this.back) === 'object') { if (this.o.inherit) { this.back.cloneCss( this.front ); //this.front.css({'backface-visibility': 'hidden'}); } else this.back.css({ br : 0 , w: '100%', h: '100%' }); this.back.css(this.params); this.back.css({ transform: this.rot.b , bfv: 'hidden' , transition : 'all 0.5s ease'} ); if ( parseInt(this.front.css('left'))) { this.front.set('to=le=ri=bo->0'); this.back.set('to=le=ri=bo->0'); } this.backCss = this.o.backStyle || this.o.setBack || this.o.backCss ; if (this.backCss) this.setBackCss(); //this.front.css('z->2'); //this.front.css('z->2 | backface-visibility -> hidden'); } // Rückseite der Front ausblenden if(this.backside != 'visible') this.front.css('bfv->hidden'); //this.c2.css('bfv->hidden'); } setBackCss(){ this.back.set( this.str_to_obj( this.backCss ) ); } clickFunc(o) { if(this.wait) return; this.wait = true; var t = this; this.c1.classList.toggle('flipped',o); this.c2.style.transform = this.c1.classList.contains('flipped') ? this.rot.b : this.rot.a; setTimeout(function(){t.wait = null;},1000); //this.deg += 180; } toggle(o){ this.clickFunc(o); } addClickListener() { //let t = this; if(this.o.click === false) return; this.o.click = this.o.click || this.c2 ; // this.front this.o.click.onclick = (event) => { event.stopPropagation(); this.clickFunc(); //if (event.target === this.o.click ) { //|| (this.back && event.target === this.back)) { // this.clickFunc(); //} else { // event.stopPropagation(); //} }; this.o.click.css('c->pointer'); if(this.o.click == this.front) this.oldParams.cursor = 'default'; } addBackClick(){ return; if (this.back && this.o.click == this.front ) { this.back.onclick = this.front.onclick; this.back.css('c->pointer'); } } updateNodePosition() { const l = parseInt(this.front.css('le')) || parseInt(this.front.css('to')) || parseInt(this.front.css('bo')) || parseInt(this.front.css('ri')); //html(`pos->abs|to=le->10|html->${this.c1.css('w')} ${l}`, this.front); } isFrontside(){ let i = this.c2.style['transform'].strstr( this.rot.a ); //console.log(i) return i; } isBackside(){ return this.c2.style['transform'].strstr( this.rot.b ); } getSide(reverse){ return !reverse ? (this.isFrontside() ? this.front : this.back) : (this.isBackside() ? this.front : this.back) ; } goFrontside(){ this.clickFunc(false); } goBackside(){ //this.o.back.css({ transform: this.rot.b , bfv: 'hidden' }); this.clickFunc(true); } clear(instanz) { if (!Rotable.isRotable(this.front)) { console.error('Das Element gehört nicht zu dieser Instanz.'); return; // this.front; } //console.log('clear') delete this.front.onclick; delete this.front.click; let temp = this.front.cloneNode(true); let parent = this.c1.parentNode; let e = parent.insertBefore( temp , this.c1 ) e.setCss( this.oldParams ); e.css( { w:this.c1.style.width , h:this.c1.style.height , mar:this.c1.style.margin } ); if (this.back) delete this.back.onclick; if (this.o.myback) this.back.destroy(); this.c1.destroy(); delete this.front[RotableSymbol]; delete this; return e; //this.front = e; //return e; // neu erstelltes elem zurück } } /** Inhalt der Datei: stile.js **/ // allgemeine CSS - Stile var stil = { float : 'float left |', center : 'dis->flex|jfc=ai=ta center|', centerIb : 'dis->ib | jfc=ta center| ', bgi : 'box-sizing border-box | bgs cover | bgp center | ', grid : 'dis grid | jfc=ai=ta center | flex-wrap wrap | mar 0 auto | gridTemplateColumns repeat( auto-fill, minmax( 300px, 1fr)) |', box : 'box-sizing border-box |', regler : 'tag input | type range |pos rel| mar=to 5|', button :'fs clamp(10px,2vw,15px) | c pointer | z 2 | dis ib | mar=pad=br 4 | bgc white |', //float left | transition : '|transition all 1s ease |', close : 'bfv hidden|br 50%|w=h 20|html x|fs 13|bgc white|pos abs|ri=to 5| dis flex|jfc=ai=ta center|c pointer|b 1px solid gray|', cover : 'bgp cover | |', } // url's für Sender var sender = { ARD : 'https://mcdn.daserste.de/daserste/de/master.m3u8' , ZDF : 'http://zdf-hls-15.akamaized.net/hls/live/2016498/de/high/master.m3u8', //http://zdf-hls-15.akamaized.net/hls/live/2016498/de/high/master.m3u8 Arte : 'https://artesimulcast.akamaized.net/hls/live/2030993/artelive_de/index.m3u8', Phoenix : "http://zdf-hls-19.akamaized.net/hls/live/2016502/de/high/master.m3u8", '3Sat' : "https://zdf-hls-18.akamaized.net/hls/live/2016501/dach/high/master.m3u8", MDR : "https://mdrtvsnhls.akamaized.net/hls/live/2016928/mdrtvsn/master.m3u8", Bayern : "https://mcdn.br.de/br/fs/bfs_nord/hls/de/master.m3u8", RBB : "https://rbb-hls-berlin.akamaized.net/hls/live/2017824/rbb_berlin/master.m3u8", Kika : "https://kikageohls.akamaized.net/hls/live/2022693/livetvkika_de/master.m3u8", //SWR : 'https://swrbwd-hls.akamaized.net/hls/live/2018672/swrbwd/master.m3u8', NDR : "https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_nds/master.m3u8", WDR : "https://mcdn.wdr.de/wdr/wdrfs/de/master.m3u8", Alpha : "https://mcdn.br.de/br/fs/ard_alpha/hls/de/master.m3u8", }; /** Inhalt der Datei: swipen.js **/ function swipen( element, actions) { const MIN_DISTANCE = 100; let startX = 0, startY = 0, scrollX = 0, scrollY = 0, isTouch = false, wait = false, sc = false, all=actions.all; // Markiere das Element als Swipe-fähig if( !actions.all) element.isswipe = true; function handleSwipe(direction,event) { if(wait) return; if (actions.run && !actions.run(direction,event)) { scrollX = scrollY = 0; warten(); return false; } if (actions[direction]) actions[direction](); scrollX = scrollY = 0; warten(); return true; } function warten() { wait = true; setTimeout(() => { wait = false; scrollX = scrollY = 0; }, 700); } function findSwipeTarget(e) { // Suche von unten nach oben im DOM, ob ein Swipe-fähiges Element gefunden wird let target = e.target; while (target && target !== element) { if (target.isswipe) return target; // Swipe-fähiges Child gefunden target = target.parentElement; } return element; // Fallback: Parent (aktuelles Element) } function findSwipeTarget_neu(e) { let target = e.target; // Suche von `e.target` nach oben bis zum Root-Element (`element`) while (target) { // Wenn ein swipe-fähiges Element gefunden wird, prüfe, ob das Event darauf oder innerhalb seiner Kinder ist if (target.isswipe) { return target; // Gibt das swipe-fähige Element zurück } target = target.parentElement; // Gehe zum Parent } return element; // Fallback: Das aktuelle Parent-Element wird zurückgegeben } function blockScroll(event){ if (actions.scroll && !actions.scroll(event)) return false return true; } let debounceTimeout; function debounce(fn, delay) { clearTimeout(debounceTimeout); debounceTimeout = setTimeout(fn, delay); } // Event-Listener für Trackpad element.addEventListener('wheel', (e) => { //debounce( ()=> { const swipeTarget = findSwipeTarget(e); if ( swipeTarget !== element && swipeTarget.isswipe ) { // Wenn das Event auf einem Child ausgelöst wird, das Swipe unterstützt, wird das Parent ignoriert return; } scrollX += e.deltaX; scrollY += e.deltaY; const isVertical = Math.abs(scrollY) > Math.abs(scrollX); // scroll bedingung if( !blockScroll(e) && isVertical ) { scrollX = scrollY = 0; return; } else e.preventDefault(); if (!wait && isVertical && Math.abs(scrollY) > MIN_DISTANCE) { cookie('ScrollReverse') === 'true' ? handleSwipe(scrollY > 0 ? 'up' : 'down',e) : handleSwipe(scrollY > 0 ? 'down' : 'up',e); } else if (!wait && Math.abs(scrollX) > MIN_DISTANCE) { cookie('ScrollReverse') === 'true' ? handleSwipe(scrollX > 0 ? 'left' : 'right',e) : handleSwipe(scrollX > 0 ? 'right' : 'left',e); } //}, 200 ); // sc ? e.preventDefault() : 0; }); // Event-Listener für Touchgeräte element.addEventListener('touchstart', (e) => { if (e.touches.length === 2) { warten(); return; } const swipeTarget = findSwipeTarget(e); if (swipeTarget !== element && swipeTarget.isswipe ) { // Wenn das Event auf einem Child ausgelöst wird, das Swipe unterstützt, wird das Parent ignoriert scrollX = scrollY = 0; e.preventDefault() return; } if (!wait && e.touches.length === 1) { isTouch = true; startX = e.touches[0].clientX; startY = e.touches[0].clientY; } }); // , { passive: false } element.addEventListener('touchmove', (e) => { if (e.touches.length === 2) { warten(); return; } const swipeTarget = findSwipeTarget(e); if (swipeTarget !== element && swipeTarget.isswipe ) { // Wenn das Event auf einem Child ausgelöst wird, das Swipe unterstützt, wird das Parent ignoriert scrollX = scrollY = 0; return; } const deltaX = e.touches[0].clientX - startX; const deltaY = e.touches[0].clientY - startY; const isVertical = Math.abs(deltaY) > Math.abs(deltaX); // scroll bedingung if( !blockScroll(e) && isVertical ) { scrollX = scrollY = 0; return; } else e.preventDefault(); if (!wait && isTouch) { if (Math.abs(deltaY) > MIN_DISTANCE) { cookie('SwipeReverse') === 'true' ? handleSwipe(deltaY > 0 ? 'up' : 'down',e) : handleSwipe(deltaY > 0 ? 'down' : 'up',e); isTouch = false; } else if (Math.abs(deltaX) > MIN_DISTANCE) { cookie('SwipeReverse') === 'true' ? handleSwipe(deltaX > 0 ? 'left' : 'right',e) : handleSwipe(deltaX > 0 ? 'right' : 'left',e); isTouch = false; } //sc ? e.preventDefault() : 0; } }, { passive: false }); } /* function swipen_alt(element, actions) { const MIN_DISTANCE = 100; let startX = 0, startY = 0, scrollX = 0, scrollY = 0, isTouch = false, wait = false, sc = null; function handleSwipe(direction) { if (actions.run && !actions.run(direction)) { scrollX = scrollY = 0; return false; } // Bedingung if (actions[direction]) actions[direction](); scrollX = scrollY = 0; // Reset return true; } function warten() { wait = true; setTimeout(() => { wait = false; scrollX = scrollY = 0; }, 700); } // Event-Listener für Trackpad (Zwei-Finger-Gesten) element.addEventListener('wheel', (e) => { if(lf.teststop) return; if (e.target !== e.currentTarget) { } if(e.target.className==='nsc'){ e.preventDefault(); return;} scrollX += e.deltaX; scrollY += e.deltaY; const isVertical = Math.abs(scrollY) > Math.abs(scrollX); if (!wait && isVertical && Math.abs(scrollY) > MIN_DISTANCE) { warten(); sc = handleSwipe(scrollY > 0 ? 'down' : 'up'); } else if (!wait && Math.abs(scrollX) > MIN_DISTANCE) { warten(); sc = handleSwipe(scrollX > 0 ? 'right' : 'left'); } sc ? e.preventDefault() : 0; // Verhindern des Scrollens bei Touchpad }); // Event-Listener für Touchgeräte element.addEventListener('touchstart', (e) => { if (e.touches.length === 2) { warten(); return; } if(e.target.className==='nsc'){ e.preventDefault();return;} //if ( !e.target.className ) { scrollX = scrollY = 0; return; }; // interim // Verhindern des Scrollens bei Touchgeräten if (!wait && e.touches.length === 1) { isTouch = true; startX = e.touches[0].clientX; startY = e.touches[0].clientY; } }, { passive: false }); element.addEventListener('touchmove', (e) => { if (e.touches.length === 2) { warten(); return; } if (e.target.matches('.imgC')) { event.preventDefault(); // Blockiere nur, wenn das Ziel die Klasse `.prevent-scroll` hat } if(e.target.className ==='nsc') { e.preventDefault();return;} //if ( !e.target.className ) { scrollX = scrollY = 0; return; }; // interim if (actions.run && !actions.run()) { scrollX = scrollY = 0; return; } // Bedingung e.preventDefault(); // Verhindern des Scrollens bei Touchgeräten if (!wait && isTouch) { const deltaX = e.touches[0].clientX - startX; const deltaY = e.touches[0].clientY - startY; const isVertical = Math.abs(deltaY) > Math.abs(deltaX); if (Math.abs(deltaY) > MIN_DISTANCE) { handleSwipe(deltaY > 0 ? 'down' : 'up'); isTouch = false; } else if (Math.abs(deltaX) > MIN_DISTANCE) { handleSwipe(deltaX > 0 ? 'right' : 'left'); isTouch = false; } e.preventDefault(); // Verhindern des Scrollens bei Touchgeräten } }, { passive: false }); // Setzt passive Option auf false } */ /** Inhalt der Datei: zoom.js **/ class ZoomMan { /* August 2024 - Gunthard Stephan - LFox */ constructor(obj) { // standard this.zoomableElements = []; this.currentIndex = -1; this.touchStartX = 0; this.touchEndX = 0; this.touchStartY = 0; this.touchEndY = 0; this.autohighsrc = true; this.minSwipeDistance = 60; // Mindestentfernung für eine Wischgeste this.buttons = {}; this.meta = true; // Metainfos bei altClick this.rotateY = 0; this.rotation = 0; if (typeof obj == 'object') this.sync(obj); this.initStyles(); this.createZoomOverlay(); this.setupEventListeners(); } // Touch-Start-Event handleTouchStart(event) { //event.stopPropagation() if(!this.active) return; event.preventDefault(); if (event.touches.length === 1) { // Nur eine Berührung für Swipe this.touchStartX = event.changedTouches[0].screenX; this.touchStartY = event.changedTouches[0].screenY; } } // Touch-Move-Event handleTouchMove(event) { //event.stopPropagation() if(!this.active) return; if (event.touches.length === 1) { this.touchEndX = event.changedTouches[0].screenX; this.touchEndY = event.changedTouches[0].screenY; } } // Touch-End-Event handleTouchEnd(event) { if(!this.active) return; //event.stopPropagation(); const deltaX = this.touchEndX - this.touchStartX; const deltaY = this.touchEndY - this.touchStartY; // Überprüfen, ob die Geste mehr horizontal oder vertikal ist if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontaler Swipe if (Math.abs(deltaX) > this.minSwipeDistance) { // Mindest-Swipe-Distanz prüfen //event.stopPropagation(); // stoppt das schließen von overlay if (deltaX > 0) { // Swipe nach rechts (zum vorherigen Bild) this.navigateZoom(-1); } else { // Swipe nach links (zum nächsten Bild) this.navigateZoom(1); } } } else { // Vertikaler Swipe if (Math.abs(deltaY) > this.minSwipeDistance) { // Mindest-Swipe-Distanz prüfen //event.stopPropagation(); // stoppt das schließen von overlay if (deltaY > 0) { // Swipe nach unten (Overlay schließen) this.closeZoomOverlay(); // Schließen des Overlays } else if (deltaY < 0){ // Swipe nach oben (Overlay schließen) this.metaRun(); //loadMeta(); // vorsicht, wurde auch durch klick ausgelöst.... } } } } // Setup Event Listeners for Touch Gestures setupTouchEventListeners() { //this.zoomedImage.addEventListener('touchstart', (event) => { event.stopPropagation(); this.handleTouchStart(event) }, false); //this.zoomedImage.addEventListener('touchmove', (event) =>{ event.stopPropagation(); this.handleTouchMove(event) }, false); //this.zoomedImage.addEventListener('touchend', () =>{ event.stopPropagation(); this.handleTouchEnd()}, false); this.zoomOverlay.addEventListener('touchstart', (event) => { this.handleTouchStart(event)}, false); this.zoomOverlay.addEventListener('touchmove', (event) =>{ event.stopPropagation(); this.handleTouchMove(event)}, false); this.zoomOverlay.addEventListener('touchend', () => { event.stopPropagation();this.handleTouchEnd()}, false); } setupEventListeners() { document.addEventListener('keydown', (event) => { if (this.active) { if (event.key === 'ArrowLeft') { this.navigateZoom(1); // Previous image } else if (event.key === 'ArrowRight') { this.navigateZoom(-1); // Next image } else if (event.key === 'Escape') { this.closeZoomOverlay(); //close } } }); // schließen des overlays //if( !this.zoomClick ) this.zoomOverlay.addEventListener('click', () => this.closeZoomOverlay()); //else this.zoomOverlay.addEventListener('dblclick', () => this.closeZoomOverlay()); } sync(o){ for(let i in o){ this[i] = o[i]; } } isMobileDevice() { const userAgent = navigator.userAgent || navigator.vendor || window.opera; // Erkennung von mobilen Geräten if (/android/i.test(userAgent)) return true; if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) return true; return false; } isClassDeclared(className) { for (let i = 0; i < document.styleSheets.length; i++) { try { if (!document.styleSheets[i].href || document.styleSheets[i].href.startsWith(window.location.origin)) { let rules = document.styleSheets[i].cssRules || document.styleSheets[i].rules; for (let j = 0; j < rules.length; j++) { if (rules[j].selectorText === `.${className}`) { return true; } } } } catch (e) { // Ignoriere den Fehler für Cross-Origin-Stylesheets console.warn('Auf Stylesheet konnte nicht zugegriffen werden:', document.styleSheets[i].href, e); } } return false; } initStyles() { const css = ` .zoom-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; opacity: 0; transition: opacity 0.5s ease; visibility: hidden; z-index: 1000; overflow: hidden; user-select: none; } .zoom-overlay img { position absolute; max-width: 90%; max-height: 90%; width : auto; height : auto; transition: all 1s ease; user-select: none; /* Verhindert die Markierung des Bildes */ } .zoom-overlay.visible { opacity: 1; visibility: visible; } .zoom-button { border-radius:5px; position: relative; justify-content: center; align-items: center; display:flex; right : 10px; top : auto; margin-right: 0px; margin-top: 8px; cursor : pointer; background-color : white; height: 20px; border : 1px solid gray; font-size: 8px; } .nav-button { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(0, 0, 0, 0.6); color: white; border: none; font-size: 2rem; cursor: pointer; padding: 0.5rem; z-index: 1001; user-select: none; } .nav-button.prev { left: 10px; } .nav-button.next { right: 10px; } .minipreview { opacity: 0; position: absolute; top: 0; left: 100px; /* Vorschau erscheint rechts vom kleinen Bild */ z-index: -1; user-select: none; } .minipreview img { width: 130px; /* Größe des Vorschau-Bildes */ height: auto; } /* ----- */ `; if( !this.isClassDeclared('zoom-overlay') ) html('tag style | textContent ' + css, document.head ); } createZoomOverlay() { if (!this.zoomOverlay) { this.zoomOverlay = html('cn zoom-overlay'); // Create and append the zoomed image element this.zoomedImage = html(stil.transition+'tag img | w=h auto', this.zoomOverlay ); // Hinzufügen der Touch-Event-Listener für die Swipe-Gesten this.setupTouchEventListeners(); // <- NEU this.zoomedImage.addEventListener('click', (event) => { if (event.target != this.zoomedImage) return; event.stopPropagation(); // stoppt das schließen von overlay //alt if(event.altKey){ this.metaRun(); return; } //next this.zoomClick == 'next' ? this.navigateZoom(-1) : 0; if(this.zoomClick) return; this.closeZoomOverlay(); }); if(this.zoomClick != 'next') this.zoomedImage.addEventListener('dblclick', (event) => { if (event.target != this.zoomedImage) return; this.closeZoomOverlay(); }); /* this.closeButton = html('bfv hidden|br 50%|w=h 25|html x|fs 16|bgc white|pos abs|ri=to 15| dis flex |jfc=ai=ta center|c pointer ',this.zoomOverlay); this.closeButton.addEventListener('click', (event) => { event.stopPropagation(); this.closeZoomOverlay(); }); if( !this.zoomClick ) this.closeButton.set('dis none'); */ // navigation buttons if(!this.isMobileDevice()){ this.prevButton = html('tag button | cn nav-button prev | html <', this.zoomOverlay); this.prevButton.addEventListener('click', (event) => { event.stopPropagation(); // stoppt das schließen von overlay this.navigateZoom(1); }); this.nextButton = html('tag button | cn nav-button next | html >', this.zoomOverlay); this.nextButton.addEventListener('click', (event) => { event.stopPropagation(); // stoppt das schließen von overlay this.navigateZoom(-1); }); } var setClick = (e)=>{ e.addEventListener('touchend', (event)=> { event.preventDefault(); this.buttonclick(event,e);} ); e.addEventListener('click', (event)=> this.buttonclick(event,e)); } var bc = html('pos abs|to=ri 5|ta center|w 35',this.zoomOverlay) if( this.zoomClick ) if(!this.buttons.rotate) setClick( this.closeButton = html('fs 10|cn zoom-button|html X',bc)); this.fav = html('fs 10|cn zoom-button|html 🩶',bc); if(!this.buttons.rotate) setClick( this.fav ); if(!this.buttons.rotate) setClick( html('fs 16|cn zoom-button|html ⇆',bc) ); if(!this.buttons.rotate) setClick( html('fs 16|cn zoom-button|html ↺',bc) ); if(!this.buttons.rotate) setClick( html('fs 16|cn zoom-button|html ℹ︎',bc) ); if(this.isMobileDevice()) return; return; // Vorschau this.preview = html('cn minipreview',); this.previewImg = html('t img | src ',this.preview); this.preview.addEventListener('mouseover', (event) => { this.preview.set('z -1|transition all 0s'); // Abstand zum Cursor this.preview.style.left = (event.pageX + 30) + "px"; }); this.previewW ? this.previewImg.set('w '+this.previewW ): 0; } } rotateCheck(rotation) { // Normiere die Rotation auf einen Wert zwischen 0 und 360 let normalizedRotation = ((rotation % 360) + 360) % 360; // Überprüfe, ob der Wert -90 oder -270 entspricht return (normalizedRotation === 270 || normalizedRotation === 90); } buttonclick(event,e){ event.stopPropagation(); var e = e||event.target; //gs.lbi.isBackside() ? rotation += 90 : rotation -= 90; this.rotation = this.rotation || 0; this.rotateY = this.rotateY || 0; //this.rotation = this.rotateY ? this.rotation += 90 : this.rotation -= 90; //this.rotateY = (!this.rotateY ? 180 : 0) this.zoomedImage.set('transition transform 1s ease'); e.innerHTML === 'X' ? this.closeZoomOverlay() : e.innerHTML === '↺' ? this.rotateY ? this.rotation += 90 : this.rotation -= 90 : e.innerHTML === '⇆' ? this.rotateY = (!this.rotateY ? 180 : 0) : 0; var r = this.rotateCheck(this.rotation), width = this.R ? window.innerWidth*.8 : window.innerWidth; !this.R ? this.zoomedImage.set( `max-width ${r?(window.innerHeight/width)*90:90}% ` ) : 0; e.innerHTML === 'ℹ︎' ? this.metaRun() : e.innerHTML === '🩶' || e.innerHTML === '💛' ? this.setFav() : //e.innerHTML === '↺' ? this.zoomedImage.set( `transform rotateZ(${ this.rotation -= 90 }deg)` ) : this.zoomedImage.set( `transform rotateY(${ this.rotateY }deg) rotateZ(${ this.rotation }deg)` ) //this.zoomedImage.css({transform : 'rotate(' + (this.rotation-= 90) + 'deg)' , transition: 'transform 1s ease' }) //: 0; } showFav(data,ob,t){ //console.log(data.name); if(typeof t.meta === 'object') return; t.fav.html( isFav(data.name) ? '💛' : '🩶' ); t.tempFileName = data.name; } setFav(content){ if(typeof this.meta === 'object') return; var name = this.tempFileName, f = loadFav()||{}; !isFav(name) ? f[name] = { date : Date.now() , content : content } : f[name] ? delete f[name] : 0; saveFav(f); this.fav.html( isFav(name) ? '💛' : '🩶' ); } metaRun(){ var e = this.zoomedImage; if(!this.meta || !this.active) return; if(!this.zoomMeta){ this.zoomMeta = true; let c = html(stil.center + 'w=h 90% | bfv hidden', e, 3); this.R = new Rotable({ node: c, click: false, perspective: 1200 + 'px', back: 'bgc rgba(255,255,255,.6) | br=pad 10 | ovf scroll | pos rel' }); this.R.front.set('bfv visible') e.set('max-width=max-height 100%'); this.R.content = html('w 100%',this.R.back); html( stil.close + 'b 1px solid gray|pos abs', this.R.back).onclick = (event) => { event.preventDefault(); // wichtig für touch event.stopPropagation(); this.R.toggle(); } this.R.back.addEventListener('click', (event) => { event.stopPropagation(); if (event.target !== this.R.back) return; if(event.altKey) this.R.toggle() }); } setTimeout(()=>{ this.loadMeta(); this.R.toggle(); },200 ); } loadMeta(f){ if(!this.active) return; if( !f && typeof this.meta === 'object' && this.meta.meta ) { this.meta.meta(); return; } var u = parseUrl(this.zoomedImage.src); getJSON( f||this.waspassiert ,{ i: u.params.i , bild : u.fileName , pfad : lf.selfpath+'/virtuell/getImgInfo.php' },this); } waspassiert(data,ob,t){ var b = t.R.content; b.empty(); html('float left|marR=marB 10| t img|h 80|src '+t.zoomedImage.src , b ); html(`html Pseudo-Name: ${ob.bild.small()}` , b); html(`html Originaler Name: ${data.name.small()} ` , b); html('html Info: '+ Object.values(data.info).join(' / ').small() , b); html('html Größe: '+ data.size.small() , b); ob.i ? html('html Index: '+ ob.i.small() , b) : 0; } reset(){ const l = this.zoomableElements.length; var i = this.zoomableElements.length; while(i--){ var element = this.zoomableElements[i] this.remove(element) } //this.zoomOverlay.remove(); console.log( l + ' --- '+this.zoomableElements.length ) return; var i = this.zoomableElements.length; while(i--){ } } remove(element) { const index = this.zoomableElements.indexOf(element); if (index !== -1) { // Entfernen des Elements aus dem Array this.zoomableElements.splice(index , 1); // Entfernen der Event-Listener const newElement = element.cloneNode(true); element.parentNode.replaceChild(newElement,element); } } addArray(elements){ var i = elements.length; while(i--) this.add( elements[i] ); } add(element) { //if( Array.isArray(element) ) { this.addArray(element); return; } // img or div if (!(element instanceof HTMLImageElement || element instanceof HTMLDivElement)) { //var url = this.parseUrl(element).url; if( typeof element == 'string' ){ //var elementObj = { src : element , isurl : true }; // Überprüfen, ob bereits ein HTMLImageElement mit derselben 'src' oder ein Objekt mit derselben 'src' existiert if (!this.zoomableElements.some(el => { if (el instanceof HTMLImageElement) { //return el.src === elementObj.src; // Vergleich zwischen HTMLImageElement.src und dem String 'src' return el.src === element; } else { return el === element; } })) { this.zoomableElements.push( element ); } else { //console.log('Element oder URL bereits vorhanden'); } return; } else console.log('Element kein ImageElement oder DivElement oder Url'); return; } // Für HTMLImageElement oder HTMLDivElement: // Überprüfen, ob das exakte Element bereits vorhanden ist oder die 'src' mit einer String-URL übereinstimmt if (this.zoomableElements.some(el => { if (el instanceof HTMLImageElement) { return el.src === element.src; // Vergleich der src-Attribute von HTMLImageElements } if (typeof el == 'string') { return el.src === element; // Vergleich der src-Attribute von HTMLImageElements } else { return el === element; // Vergleich der Objektreferenzen } })) { //console.log('Element oder URL bereits vorhanden'); return; } this.zoomableElements.push (element); const t = this; this.clickable ? element.set('c pointer'):0; element.addEventListener('click', (event) => { if (event.target != element ) return; if ( this.clickable || event.metaKey ) { event.stopPropagation(); this.zoom(element); } }); element.addEventListener("mouseover", function(event) { return; const data = this.getAttribute("data-minipreview"); if( !t.minipreview && (!data || data == 'false' )) return; t.previewImg.src = this.src; t.preview.set(' op 1 | z 10 '); }); element.addEventListener("mousemove", function(e) { return var data = this.getAttribute("data-minipreview"); if( !t.minipreview && (!data || data == 'false') ) return; if(t.isMobileDevice()) return; const [xOff, yOff] = [20, -30], [pW, pH] = [t.preview.offsetWidth, t.preview.offsetHeight], [vW, vH] = [window.innerWidth, window.innerHeight], [sX, sY] = [window.scrollX, window.scrollY]; let l = e.pageX + xOff - sX, to = e.pageY + yOff - sY; // Wenn nicht genug Platz rechts, positioniere das Bild links vom Cursor if (l + pW > vW) l = e.pageX - pW - xOff - sX; // Wenn nicht genug Platz unten, positioniere das Bild oben vom Cursor if (to + pH > vH) to = e.pageY - pH - yOff - sY; if (to < 0) to = 0; // Setze die Position der Vorschau t.preview.set({left : `${Math.max(l, 0) + sX}px`, top : `${to + sY}px` }); }); element.addEventListener("mouseout", function() { return t.preview.set(' op 0 | transition all .3s ease'); }); return this; } addPreview(element,w){ return; element.setAttribute("data-minipreview", 1 ); w ? this.previewImg.set('w '+w): 0; } // öffnen des Overlays zoom(element){ //if(this.wait) return; this.wait = true; setTimeout( ()=>{ this.wait = false; }, 800 ); this.zoomedImage.style.transition = 'none'; this.currentIndex = this.zoomableElements.indexOf(element); setTimeout( ()=>{ this.showZoomedImage(); } , 100 ); this.active = true; // instance as active } addClick(element){ if( this.clickable ) return; //var t = this; element.addEventListener("click", (event)=>{ this.zoom(element); }); element.set('c pointer'); } checkIndex(index){ return (index >= 0 && index < this.zoomableElements.length) ? true : false; } preload(src,index){ let image = new Image(); image.onload = ()=>{ //image = null; if( typeof index != 'undefined' ){ this.zoomedImage.src = src; // next & pre vorladen if( this.checkIndex(index-1) ) this.preload( this.getImageSrc(index-1).high ); if( this.checkIndex(index+1) ) this.preload( this.getImageSrc(index+1).high ); } }; image.src = src; } parseUrl_old(url) { // Versuche, eine absolute URL zu erstellen, wenn es sich um einen relativen Pfad handelt let parsedUrl; try { // Versuche die URL direkt zu verwenden (für absolute URLs) parsedUrl = new URL(url); } catch (error) { // Wenn es fehlschlägt, baue eine absolute URL basierend auf dem aktuellen Standort parsedUrl = new URL(url, window.location.origin); } // Extrahiere den Teil der URL ohne Query-Parameter const urlWithoutQuery = parsedUrl.origin + parsedUrl.pathname; // Extrahiere die Query-Parameter und speichere sie in einem Objekt const urlParams = {}; parsedUrl.searchParams.forEach((value, key) => { urlParams[key] = value; }); // Gib ein Objekt zurück, das beide Teile enthält return { url: urlWithoutQuery, params: urlParams }; } parseUrl(url) { var parsedUrl, url = url.replaceAll('"',''); // Funktion zur Prüfung, ob eine URL absolut ist function isAbsoluteUrl(url) { return /^https?:\/\//i.test(url); } try { // Prüfe, ob die URL absolut ist if (isAbsoluteUrl(url)) { // Wenn die URL absolut ist, verwende sie direkt parsedUrl = new URL(url); } else { // Wenn es sich um eine relative URL handelt, baue sie auf Basis von window.location.href parsedUrl = new URL(url, window.location.href); } } catch (error) { console.error("Fehler beim Parsen der URL:", error); return null; } // Extrahiere den Teil der URL ohne Query-Parameter const urlWithoutQuery = parsedUrl.origin + parsedUrl.pathname; // Bereinige den Pfad, um doppelte Schrägstriche zu entfernen const cleanedPath = parsedUrl.pathname.replace(/([^:]\/)\/+/g, "$1"); // Extrahiere den Dateinamen samt Endung const pathParts = cleanedPath.split('/'); const fileNameWithExtension = pathParts.pop(); // Letztes Element ist der Dateiname // Der verbleibende Pfad (ohne Dateinamen) const filePath = pathParts.join('/'); // Stelle sicher, dass der Pfad korrekt ist (füge führenden / hinzu, falls nötig) const correctedFilePath = filePath.startsWith('/') ? filePath : '/' + filePath; // Extrahiere die Query-Parameter und speichere sie in einem Objekt const urlParams = {}; parsedUrl.searchParams.forEach((value, key) => { urlParams[key] = value; }); // Gib ein Objekt zurück, das die URL, den Dateinamen, den Pfad und die Query-Parameter enthält return { url: parsedUrl.origin + cleanedPath, // Die vollständige URL ohne Query-Parameter params: urlParams, // Die Query-Parameter als Objekt fileName: fileNameWithExtension, // Der Dateiname mit der Endung path: correctedFilePath , // Der Pfad ohne den Dateinamen, mit führendem / origin: window.location.origin }; } getImageSrc(index){ if (this.currentIndex === -1) return; const currentElement = this.zoomableElements[index]; var highsrc, lowsrc, url={}; this.currentElement = currentElement; // reine url let isurl = typeof currentElement == 'string'; if( isurl ) lowsrc = currentElement; else if (currentElement.tagName === 'IMG') { lowsrc = currentElement.src; } else if (currentElement.tagName === 'DIV') { const backgroundImage = currentElement.style.backgroundImage; const imageUrl = backgroundImage.slice(5, -2); // "url('...')" to "..." lowsrc = imageUrl; } //console.log(lowsrc); if(lowsrc) url = this.parseUrl(lowsrc); // zoom url in data-attribut o.ä. if(!isurl && this.largeAttribute && (highsrc = currentElement.getAttribute( this.largeAttribute ))){ highsrc = highsrc; } // bei verkleinerten Bildern Original suchen... else if( this.autohighsrc && url.params && ( url.params.w || url.params.h ) ){ highsrc = url.url +'?h=600'+ (url.params.i ? '&i='+url.params.i : ''); //console.log(' highsrc= '+highsrc + ' path= '+url.path + ' filename= '+url.fileName + ' origin= '+url.origin ); } return {low:lowsrc,high:highsrc}; } setImageSrc(index){ let o = this.getImageSrc(index || this.currentIndex); this.zoomedImage.src = o.low; if( o.high ) this.preload( o.high , index || this.currentIndex ); // meta if( this.R && this.R.isBackside() && typeof this.meta !== 'object' ) { this.loadMeta(); } } createTempImage(){ } showZoomedImage(nav) { this.active = true; // Überprüfe, ob das Overlay gerade geöffnet wird oder nicht // Harten übergang definieren in if ( nav && !this.hardbreak && !this.wait ) { const wW = window.innerWidth ; // Alte Bild-Transitions this.zoomedImage.style.transition = 'transform 0.5s ease, opacity 0.5s ease'; //this.zoomedImage.style.transform = `translateX( ${wW*nav*-1}px)` ; this.zoomedImage.set( `transform rotateY(${ this.rotateY }deg) rotateZ(${ this.rotation }deg) translateX( ${wW*nav*-1}px)` ) setTimeout(() => { // Setze die Übergangseffekte für das neue Bild this.zoomedImage.set('transition none'); this.zoomedImage.style.opacity = '0'; //this.zoomedImage.style.transform = `translateX( ${wW*nav}px)` ; //: `translateX(${100*nav}%)`; this.zoomedImage.set( `transform rotateY(${ this.rotateY }deg) rotateZ(${ this.rotation }deg) translateX( ${wW*nav}px)` ) this.setImageSrc(); // favorit symbol aktualisieren this.loadMeta(this.showFav); // Setze die neuen Bild-Transitions nach kurzer Verzögerung setTimeout(() => { this.zoomedImage.style.transition = 'transform 0.5s ease, opacity 0.5s ease'; //this.zoomedImage.style.transform = 'translateX(0)'; this.zoomedImage.set( `transform rotateY(${ this.rotateY }deg) rotateZ(${ this.rotation }deg) translateX( ${0}px)` ) this.zoomedImage.style.opacity = '1'; setTimeout( () => { this.zoomedImage.set('transition none'); }, 1000 ); }, 10); }, 500); // Die Verzögerung entspricht der Dauer der Übergangsanimation } else { this.zoomedImage.style.transition = 'none'; this.setImageSrc(); this.zoomOverlay.classList.add('visible'); this.loadMeta(this.showFav); } } jumpTo(index) { if (index < 0 || index >= this.zoomableElements.length) { console.error('Index außerhalb des Bereichs'); return; } this.currentIndex = index; this.showZoomedImage(); this.active = true; // Setze die Instanz als aktiv } closeZoomOverlay() { if(this.wait) return; this.R ? this.R.toggle(false) : 0; this.zoomedImage.style.transition = 'none'; this.zoomOverlay.classList.remove('visible'); this.active = false; // instanz inactive } navigateZoom(direction) { this.active = true; if (this.currentIndex === -1) return; this.currentIndex -= direction; if (this.currentIndex < 0) { this.currentIndex = this.zoomableElements.length - 1; } else if (this.currentIndex >= this.zoomableElements.length) { this.currentIndex = 0; } this.showZoomedImage(direction); } }