jQuery zu Vanilla JS konvertieren – mit KI! (Cheatsheet & Workflow)

Von jQuery auf Vanilla JS umsteigen bietet einige Vorteile. Neben dem Entfernen von totem Code, kannst Du ganz nebenbei auch deine Website Geschwindigkeit für SEO erhöhen.

Du hast Dich schon mit einem Umstieg von jQuery auf reines JavaScript (auch Vanilla JS genannt) beschäftigt, sonst wärst Du vermutlich nicht hier. Das ist schon mal gut. Auch ich stand vor dieser Entscheidung, deshalb versuche ich Dir beim Umstieg zu helfen und zeige Dir, wieso es sich lohnt und wie Du vorgehen kannst.

Warum du alle jQuery zu JavaScript Online Converter vergessen kannst und wie du trotzdem einfach den Umstieg hinbekommst, zeige ich dir anhand eines tollen Beispiels!

Online jQuery zu JavaScript Converter

Ja, ich sehe schon die Kommentare: „Aber es gibt doch mittlerweile Converter die mein jQuery Code zu JavaScript konvertieren können“. Im Prinzip richtig, aber hast du schon mal einen davon ausprobiert? Da kommen teilweise sehr komische Sachen raus. Beispielsweise wird aus diesem Code:

if ($(window).width() < 768) {
  return true;
} else {
  return false;
}

Dieser Code:

if (document.querySelector(window).width() < 768) {
  return true;
} else {
  return false;
}

document.querySelector(window) Really? 😠

Diese stupfen Umwandlungen funktionieren einfach in vielen Fällen nicht wirklich gut und man hat am Ende mehr Arbeit die Bugs zu beheben, statt von Grund auf selber umzuwandeln – und das ist gar nicht so schwer wie du gleich sehen wirst. Aber schauen wir uns doch erstmal an, warum du überhaupt jQuery durch reines JavaScript ersetzen solltest.

SEO verbessern durch Vanilla JavaScript?

Klingt erstmal komisch, aber es ist was dran. Ich bin ständig dabei, diese Seite und die Artikel zu optimieren. Dabei ist für mich – und auch für Suchmaschinen – die Ladegeschwindigkeit der Website eine wichtige Kennzahl.

Ich nutze gerne PageSpeed Insights zum Testen. Im detaillierten Report bekommt man eine genaue Auflistung aller Probleme, darunter auch die Ladegeschwindigkeit.

Bei der Ausführungszeit von JavaScript hatte ich einen zu hohen Wert. Jetzt bin ich damit sehr zufrieden.

JavaScript-Ausführungszeit nach der Umstellung
JavaScript-Ausführungszeit nach der Umstellung

Auch bei Ressourcen die geladen werden tauchte zusätzlich meine jQuery Datei auf. Und wenn Du hier schaust, gehört die jQuery Datei mit 11KB schon zu einer der größeren Dateien – trotz minified.

Ressourcen, die das Rendering blockieren, nach der Umstellung
Ressourcen, die das Rendering blockieren, nach der Umstellung

Nicht falsch verstehen, ich liebe jQuery – einfach eine geniale Library. Ich habe schon viele tolle Funktionen, wie einen Reading Position Indicator mit jQuery programmiert.

Aber dennoch musste ich das von dieser Seite verbannen – für SEO und vielleicht auch als kleine Herausforderung sich mehr mit Vanilla JS zu beschäftigen.

Toten Code entfernen

Wenn man schon etwas an der Struktur ändert, kann man die Gelegenheit direkt nutzen, um unnötigen und veralteten Code zu entfernen.

Dazu habe ich mir eine Liste aller Funktionen gemacht (waren insgesamt 11 Stück) und habe jeder Funktion eine Priorität vergeben.

Ich habe mit den wichtigen und essentiellen Funktionen angefangen und in Vanilla JS umgeschrieben.

Schritt für Schritt. Wenn man jede Funktion einzeln übernimmt findet man eventuell Fehler oder Code der gar nicht mehr benötigt wird. Diesen kannst Du direkt löschen.

Dadurch wird Deine neue JavaScript Datei gleichzeitig aufgeräumt und der Übersichtlichkeit kommt es auch noch direkt zur Gute.

Eine Alternative zu jQuery ist Vue.js. Einige Funktionalitäten lassen sich damit viel leichter und dynamischer umsetzen. Vue.js funktioniert auch ohne Build Tools – wusstest du das schon?

jQuery Code konvertieren – mit KI (Künstlicher Intelligenz)

Seit dem ChatGPT Einzug in den Alltag der Entwickler gefunden hat, nutze auch dieses Tool sehr regelmäßig und das machen wir uns auch für die Konvertierung von jQuery Code zu nutze. Da ChatGPT aber nicht unbegrenzt lange Texte verarbeiten und erstellen kann, müssen wir ein paar Dinge beachten. Diese Vorgehensweise hat sich für mich bewährt:

  1. Logische Codefragmente ausfindig machen: Wenn du eine Datei mit vielleicht 1000 Zeilen jQuery Code hast, ist dieser im besten Fall sehr modular aufgebaut, so dass du hier einfach den Code in kleinere Teile aufteilen kannst. Das können z.B. einzelne Funktionen sein.
  2. jQuery Code konvertieren: Übergebe die einzelnen Codefragmente mit dem Prompt „Rewrite this jQuery to Code pure Vanilla JS: **CODE** an ChatGPT.
ChatGPT wandelt jQuery Code zu JavaScript um
ChatGPT wandelt jQuery Code zu JavaScript um

3. JavaScript zusammensetzen: Jetzt nimmst du den genierten Code und setzt in Schritt für Schritt in eine neue JavaScript Datei.
4. Code überprüfen: Jetzt solltest du dir den Code nochmal anschauen und ein wenig refactoren. Denn ChatGPT ist bei weitem nicht perfekt! 🙂

Achtung: Beachte, dass du keine sensiblen Daten an ChatGPT weitergibst. Das kann für deine Firma oder dich böse enden!

1:1 jQuery zu JavaScript Übersetzungen

Wie gesagt, ChatGPT macht die Umwandlung nicht perfekt. Als zusätzliche Ressource hat mir deshalb youmightnotneedjquery.com geholfen. Dort werden direkte Funktionen in jQuery und JavaScript verglichen. Ich habe diese Liste für dich noch etwas erweitert.

Ich hoffe, dass du mit Hilfe von ChatGPT und meiner folgenden Zusammenstellung von 1:1 Umwandlungen deine Konvertierung von jQuery zu JavaScript gut meistern kannst.

Document Ready Funktion

Die Funktion wird aufgerufen, wenn Die Seite geladen ist. Damit blockiert die Ausführung von JavaScript nicht das Laden der Seite.

// with jQuery
$(function() {
  /* ... */
  });


// Vanilla JS
function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
  }
ready(() => {
  /* ... */
  });

Elemente selektieren

Der größte Unterschied beim Selektieren von Elementen ist, dass man in reinem JavaScript eine Schleife erstellen muss, falls es mehrere Elemente gibt. Bei jQuery kann man z.B. Events über den Selektor registrieren und es gilt für alle. Genaueres im Abschnitt Event Handling.

// with jQuery
// multiple elements
let buttons = $('button.red-btn');

// one element
let button = $('button.green-btn');


// Vanilla JS
// multiple elements
let buttons = document.querySelectorAll('button.red-btn');

// one element
let button = document.querySelector('button.green-btn');

Mit parentNode bekommst Du das Elternelement. Du kannst die Anweisung auch aneinander reihen, um Elemente noch weiter oben im DOM zu bekommen – also parentNode.parentNode.

// with jQuery
let foobarParent = $('#foobar-container').parent();


// Vanilla JS
let foobarParent = document.querySelector('#foobar-container').parentNode;

Event Handling

Beim Event Handling musst Du schaue, ob Du ein oder mehrere Elemente hast. JQuery ist das egal, es registriert einfach das Event. Für beide Situationen ist hier ein Beispiel.

// with jQuery
$('.link').click(function() {
  /* ... */
  });


// Vanilla JS
// one element
document.querySelector('#link').addEventListener('click', event => {
	/* ... */
	});

// more elements
document.querySelectorAll('.link').forEach(link => {
  link.addEventListener('click', event => {
  	/* ... */
  });
  });

Zum Deregistrieren von Events ist in Vanilla JS die eigentliche Event Callback Funktion notwendig. Wenn Du also ein Event registrierst, solltest Du dieses in einer eigenen Callback Funktion anlegen.

// with jQuery
$('#foobar').off('click');


// Vanilla JS
document.getElementById('foobar').removeEventListener('click', clickEvent);
function clickEvent(event) { }

Aktionen auf Elementen durchführen

Um show() und hide() zu erreichen, ändern wir einfach die CSS Eigenschaft display entsprechend.

// with jQuery
$('.foobar').show();


// Vanilla JS
document.querySelectorAll('.foobar').forEach(element => {
  element.style.display = 'block';
  });
// with jQuery
$('.foobar').hide();


// Vanilla JS
document.querySelectorAll('.foobar').forEach(element => {
  element.style.display = 'none';
  });

Attribute von Elementen abfragen und verändern

Die Abfrage und das Handling der Klassen funktioniert genauso einfach wie mit jQuery. Lediglich die Schreibweise ist ein wenig anders. Eine toggleClass() Funktion könntest Du Dir – falls benötigt – auch ganz einfach selber programmieren.

// with jQuery
if($('.foo').hasClass('bar')) {
  /* ... */
  }


// Vanilla JS
if(document.querySelector('.foo').classList.contains('bar')) {
  /* ... */
  }
// with jQuery
$('.foo').addClass('bar');


// Vanilla JS
document.querySelector('.foo').classList.add('bar');
// with jQuery
$('.foo').removeClass('bar');


// Vanilla JS
document.querySelector('.foo').classList.remove('bar');

Auch die Abfrage von anderen Attributen ist recht ähnlich. Beachte, dass manchmal die Ausgabe anders ist, als bei der jQuery Funktion.

// with jQuery
console.log($('.foobar').attr('checked')); // Output: checked/undefined


// Vanilla JS
console.log(document.querySelector('.foobar').checked); // Output: true/false
// with jQuery
$('.foobar').html();
$('.foobar').html('<span>Hello world!</span>');


// Vanilla JS
document.querySelector('.foobar').innerHTML;
document.querySelector('.foobar').innerHTML = '<span>Hello world!</span>';

Offsets und Dimensionen bestimmen

// with jQuery
let offset = $(window).scrollTop();


// Vanilla JS
let offset = window.pageYOffset;
// with jQuery
$(window).width();


// Vanilla JS
parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", ""));
// with jQuery
$('.foobar').width();


// Vanilla JS
document.querySelector('.foobar').offsetWidth;
// with jQuery
$('.foobar').offset().top;


// Vanilla JS
document.querySelector('.foobar').offsetTop;

Styling von Elementen

Bei Styles, die mit einem Bindestrich verbunden werden, kannst Du die Camel-Case Schreibweise verwenden. So wird z.B. aus justify-content justifyContent.

// with jQuery
$('.foobar').css('display', 'flex');
$('.foobar').css('margin-top', '3rem');

let displayProperty = $('.foobar').css('display');


// Vanilla JS
document.querySelector('.foobar').style.display = 'flex';
document.querySelector('.foobar').style.marginTop = '3rem';

let element = document.querySelector('.foobar');
let elementStyle = getComputedStyle(element, null);
let displayProperty = elementStyle.display;

Neue Elemente erstellen

Wenn Du neue Elemente erstellen willst und in ein Element anfügen möchtest, kannst Du das wie folgt machen.

Einzelne Attribute und Klassen müssen einzeln hinzugefügt werden, genauer beschrieben im Abschnitt Attribute von Elementen abfragen und verändern.

// with jQuery
$('.foo').append('<p class="child" id="child-id">bar</p>');


// Vanilla JS
let bar = document.createElement('p');
bar.classList.add('child');
bar.id = 'child-id';
bar.innerHTML = 'bar';
document.querySelector('.foo').appendChild(bar);

Data Attribute verwalten

HTML Data Attribute helfen dabei einem HTML Element mehr Daten zuzuordnen als das Element vorsieht. Dabei werden Data Attribute als data- Attribut angehängt.

// with jQuery
let action = $('#foo').data('action');
let customAttribute = $('#bar').data('custom-attribute-with-dashes'); // 'data-custom-attribute-with-dashes' in HTML


// Vanilla JS
let action = document.getElementById('foo').dataset.action
let customAttribute = document.getElementById('bar').dataset.customAttributeWithDashes; // 'data-custom-attribute-with-dashes' in HTML
// with jQuery
$('#foo').data('action', 'my-custom-action');


// Vanilla JS
document.getElementById('foo').dataset.action = 'my-custom-action';

So sieht der Umstieg aus: Praxis-Beispiel

Das ist ein Großteil der Funktionen, die ich bei meinem Umstieg benötigt habe.

Ich möchte Dir aber hier exklusiv die JavaScript Datei dieser Seite. Vor- und nach dem Umstieg zu Vanilla JS.

Vielleicht kannst Du die ein- oder andere selber Codezeile benutzen. 🙂

Datei vor dem Umstieg (jQuery)

$(function() {
	documentReady();
	});

// WHEN DOCUMENT LOADED
function documentReady() {
	// priavy container on visit begin
	if (
		!getCookie('cookie-state') ||
		getCookie('cookie-state') == undefined ||
		getCookie('cookie-state') == ''
	) {
		$('.privacy-popup').fadeIn(200);
		initCookieClicker();
	}
	$('.open-cookie-menu').click(function() {
		$('.privacy-popup').fadeIn(200);
		initCookieClicker();
		return false;
	});
	
	// set perfect image ratio
	setImageRatio();
	
	let resizeTimeout;
	$(window).resize(function() {
		clearTimeout(resizeTimeout);
		resizeTimeout = setTimeout(function() {
			setImageRatio();
		}, 200);
	});
	
	
	// remove ad containers
	setTimeout(function() {
	
	  var adblockEnabled = false;
	    
	  // add test element and get its styles
	  $('body').append('<div class="adBanner"></div>');
	  var adElement = document.getElementsByClassName('adBanner')[0];
	  var adElementStyle = getComputedStyle(adElement, null);
	  
	  
	  if(adElementStyle.display === 'none') {   // Adblock enabled
	  	$('.cwebdeasy-g-container').remove();
	  	$('.webd-f-container').remove();
	  }
	  
	}, 1500);	
	
	$(window).scroll(function() {
		let offset = $(window).scrollTop();
		if(offset > $('header#masthead').height()) {
			$('header#masthead').addClass('header-box-shadow');
		} else {
			$('header#masthead').removeClass('header-box-shadow');
		}
	});
	
	// show share icon on mobile
	if ($(window).width() < 768) {
		$('.social-icons.vertical .share-icon')
			.show()
			.click(function() {
				if ($('.social-icons.vertical a').is(':visible')) {
					$('.social-icons.vertical a').fadeOut(200);
				} else {
					$('.social-icons.vertical a').fadeIn(200);
				}
			});
	} else {
		setTimeout(function() {
			$('.social-icons.vertical a').fadeIn(400);
		}, 10000);
	}
	
	// collect menu data
	$('.menu-hauptmenue-container .sub-menu .menu-item a, .menu-hauptmenue-en-container .sub-menu .menu-item a').click(function() {
		_paq.push(['trackEvent', 'Desktop Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect sidebar click
	$('.menu-sidebar-tutorials-de-container li a, .menu-sidebar-tutorials-en-container li a').click(function() {
		_paq.push(['trackEvent', 'Sidebar Tutorials Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect sidebar click
	$('.sidebar-categories a, sidebar-categories a').click(function() {
		_paq.push(['trackEvent', 'Sidebar Categories Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect InPost Menu click
	$('.interesting-container li a').click(function() {
		_paq.push(['trackEvent', 'Interesting InPost Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect Table of contents click
	$('.table-of-contents li a').click(function() {
		_paq.push(['trackEvent', 'Table of contents', 'Click', 'Jump to: "' + $(this).html() + '"']);
	});
	
	// open mobile menu
	let mobileMenuTimeout;
	$('.mobile-menu-button').click(function() {
		if (mobileMenuTimeout) return false;
		
		clearTimeout(mobileMenuTimeout);
		mobileMenuTimeout = setTimeout(function() {
			mobileMenuTimeout = null;
		}, 200);
		
		if ($(this).hasClass('open')) {
			$(this).removeClass('open');
			$(
				'.menu-hauptmenue-container, .menu-hauptmenue-en-container'
			).slideUp(200);
			$('.mobile-menu-bg-overlay').fadeOut();
		} else {
			$(this).addClass('open');
			$(
				'.menu-hauptmenue-container, .menu-hauptmenue-en-container'
			).slideDown(200);
			$('.mobile-menu-bg-overlay').fadeIn();
			$('.mobile-menu-bg-overlay')
				.off('click')
				.click(function() {
					$('.mobile-menu-button').click();
				});
				
			// open submenu
			if (
				!$('.main-menu .submenu-expand')
					.siblings('.sub-menu')
					.is(':visible')
			) {
				$('.main-menu .submenu-expand')
					// .first()
					.click();
			}
			
			_paq.push(['trackEvent', 'Menu', 'Click', 'Open mobile menu']);
		}
	});
	
	$('.main-menu .submenu-expand').click(function() {
		if ($(window).width() < 1200) {
			$(this)
				.siblings('.sub-menu')
				.slideToggle();
				
			// _paq.push(['trackEvent', 'Menu', 'Click', 'Toggle submenu']);
		}
	});
	
	// minimize code blocks
	$('.wp-block-code, .enlighter-default').each(function() {
		if ($(this).height() >= 450) {
			$(this)
				.children('code')
				.css('height', '450px');
				
			$(this)
				.children('.enlighter')
				.css('display', 'block')
				.css('height', '470px');
				
			$(this)
				.css('height', '545px');
				
			$(this).append(
				'<span class="expand-code btn btn-block btn-sm btn-outline-primary mt-2">' +
					(lang === 'de' ? 'Aufklappen' : 'Expand') +
					'</span>'
			);
		}
	});
	
	// expand code
	$('.expand-code').click(function() {
		if ($(this).hasClass('open')) {
			$(this)
				.siblings('code')
				.css('height', '450px');
			$(this)
				.siblings('.enlighter')
				.css('height', '470px');
			$(this)
				.parent('.enlighter-default')
				.css('height', '545px');
			$(this)
				.removeClass('open')
				.html(lang === 'de' ? 'Aufklappen' : 'Expand');
				
			// _paq.push(['trackEvent', 'Code', 'Click', 'Minified View']);
		} else {
			$(this)
				.siblings('code')
				.css('height', 'auto');
			$(this)
				.siblings('.enlighter')
				.css('height', 'auto');
			$(this)
				.parent('.enlighter-default')
				.css('height', 'auto');
			$(this)
				.addClass('open')
				.html(lang === 'de' ? 'Zuklappen' : 'Collapse');
				
			// _paq.push(['trackEvent', 'Code', 'Click', 'Full View']);
		}
		return false;
	});
	
	// smooth scroll on anchor click
	$('a[href^="#"]').click(function() {
		var elementName = $(this)
			.attr('href')
			.replace('#', '');
			
		if(elementName == undefined || elementName == '') return false;
		
		var element = $('#' + elementName);
		
		if (!element.length) {
			return false;
		}
		
		var elementOffset = element.offset().top - 110;
		
		$('html, body').animate({ scrollTop: elementOffset }, 'slow');
		location.replace('#' + elementName);
		return false;
	});
	
	let sidebarScrollEnabled = true;
	let windowScrollTimeout;
	$(window).scroll(() => {
		clearTimeout(windowScrollTimeout);
		sidebarScrollEnabled = false;
		windowScrollTimeout = setTimeout(() => {
			sidebarScrollEnabled = true;
		}, 1000);
	});
	
	setInterval(() => {
		if($(window).width() > 768 && sidebarScrollEnabled) {
			let offset = $(window).scrollTop();
			
			if($('.single-after-content').offset().top < offset) return false;
			
			let adHeight = 0;
			if($('.cwebdeasy-g-container').length) adHeight = $('.cwebdeasy-g-container').height() + 120;
			
			$('.sidebar-outer-box .js-to-top-container').css('margin-top', (offset - adHeight - 50) + 'px');
		}
	}, 5*1000);
	
	// lightbox
	$('figure > a > picture > img').click(function() {
		if ($(this).attr('src') != '') {
			$('.lightbox .img-container').html(
				'<div class="close">✖</div><img src="' +
					$(this).attr('src') +
					'"><p>' +
					$(this).attr('alt') +
					'</p>'
			);
			$('.lightbox').fadeIn();
			
			// _paq.push(['trackEvent', 'Lightbox', 'Click', 'Open Lightbox']);
			
			// register close event
			$('.lightbox .close, .lightbox .bg-overlay')
				.off('click')
				.click(function() {
					$('.lightbox').fadeOut();
				});
		}
		return false;
	});
	}

function initCookieClicker() {
	$('.privacy-popup .privacy-container #accept-cookies')
		.off('click')
		.click(function() {
			setCookie('cookie-state', 'all', 7);
			
			// matomo opt in
			_paq.push(['forgetUserOptOut']);
			
			// _paq.push(['trackEvent', 'Cookie Setting', 'Click', 'Accept all']);
			
			$('.privacy-popup').fadeOut(200);
			return false;
		});
	$('.privacy-popup .privacy-container #necessary-cookies')
		.off('click')
		.click(function() {
			setCookie('cookie-state', 'necessary', 7);
			
			// _paq.push([
			// 	'trackEvent',
			// 	'Cookie Setting',
			// 	'Click',
			// 	'Accept necessary'
			// ]);
			
			// matomo opt out
			_paq.push(['optUserOut']);
			
			// remove dark mode option
			// $('.dark-mode-switcher').remove();
			// setCookie('theme', '', 0);
			
			$('.privacy-popup').fadeOut(200);
			return false;
		});
	$('.privacy-popup .privacy-container #show-cookies')
		.off('click')
		.click(function() {
			$('.privacy-popup .more-cookie-infos').fadeToggle();
			return false;
		});
		}

function setImageRatio() {
	// normal preview
	let imageElements = document.querySelectorAll('.post-preview-container .header-container');
	
	if(imageElements.length) {
		let width = imageElements[0].offsetWidth;
		let height = width / 2;
		for(let i = 0; i < imageElements.length; i++) {
			imageElements[i].style.height = height + 'px';
		}
	}
	
	// // small images
	let smallImageElements = document.querySelectorAll('.post-preview-container .horizontal-look > a');
	
	if(smallImageElements.length) {
		width = smallImageElements[0].offsetWidth;
		height = width / 2;
		for(let i = 0; i < smallImageElements.length; i++) {
			smallImageElements[i].style.height = height + 'px';
		}
	}
	}

function getCookie(cname) {
	var name = cname + '=';
	var decodedCookie = decodeURIComponent(document.cookie);
	var ca = decodedCookie.split(';');
	for (var i = 0; i < ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0) == ' ') {
			c = c.substring(1);
		}
		if (c.indexOf(name) == 0) {
			return c.substring(name.length, c.length);
		}
	}
	return '';
	}

function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
	var expires = 'expires=' + d.toUTCString();
	document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
	}

Datei nach dem Umstieg (JavaScript)

let sidebarScrollEnabled = true;


ready(() => {

	// priavy container on visit begin
	if (!getCookie('cookie-state') || getCookie('cookie-state') == undefined || getCookie('cookie-state') == '') {
		openCookieMenu();
	}
	
	
	// open cookie menu
	document.querySelectorAll('.open-cookie-menu').forEach(cookieMenu => {
		cookieMenu.addEventListener('click', openCookieMenu);
	});
	
	
	// set perfect image ratio
	setImageRatio();
	
	
	// position share buttons
	positionSocialIcons();
	
	
	// set perfect image ratio on resize
	let resizeTimeout;
	window.addEventListener('resize', () => {
		clearTimeout(resizeTimeout);
		resizeTimeout = setTimeout(() => {
			setImageRatio();
			positionSocialIcons();
		}, 200);
	});
	
	
	// toggle mobile submenus
	document.querySelectorAll('.main-menu .submenu-expand').forEach(expander => {
		expander.addEventListener('click', toggleMobileSubMenus);
	});
	
	
	// toggle mobile menu
	document.querySelector('.mobile-menu-button').addEventListener('click', toggleMobileMenu);
	
	
	// remove ad containers
	setTimeout(checkAdblock, 1500);
	
	
	// show shadow in header
	window.addEventListener('scroll', () => {
		toggleHeaderShadow();
	}, {passive: true});
	
	
	// sidebar scroll actions: TODO
	let windowScrollTimeout;
	window.addEventListener('scroll', () => {
		clearTimeout(windowScrollTimeout);
		sidebarScrollEnabled = false;
		windowScrollTimeout = setTimeout(() => {
			sidebarScrollEnabled = true;
		}, 1000);
	}, {passive: true});
	
	setInterval(() => {
		execSidebarMovementActions();
	}, 7*1000);
	
	
	// lightbox
	document.querySelectorAll('figure > a > picture > img, figure > a > img').forEach(lightboxLink => {
		lightboxLink.addEventListener('click', openLightbox);
	});
	
	
	// show social icons
	showSocialIcons(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) <= 768);
	
	
	// collect matomo data
	registerMatomoEventListeners();
	
	
	// minimize code blocks
	document.querySelectorAll('.wp-block-code, .enlighter-default').forEach(codeblock => {
		minimizeCodeblocks(codeblock);
	});
	
	
	// scroll to (with offset)
	document.querySelectorAll('a[href^="#"').forEach(anchorLink => {
		anchorLink.addEventListener('click', anchorClick);
	});
	
	
	// smooth scroll on page load
	setTimeout(() => {
		if(location.hash) {
			window.scrollTo(0, 0);
			let target = location.hash.split('#');
			customScrollTo(document.getElementById(target[1]));
		}
	}, 200);
	
	});


/* FUNCTION AREA */
function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
  }

function positionSocialIcons() {
	let iconWrapper = document.querySelector('.social-icons-fixed .social-icons');
	
	if(!iconWrapper) return false;
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) < 768) {
		iconWrapper.style.left = 'inherit';
		iconWrapper.style.top = 'inherit';
		iconWrapper.style.bottom = '1rem';
		iconWrapper.style.right = '1rem';
	} else {
		let blogpost = document.getElementsByClassName('post')[0];
		iconWrapper.style.right = 'inherit';
		iconWrapper.style.bottom = 'inherit';
		iconWrapper.style.left = (blogpost.offsetLeft - 60) + 'px';
		iconWrapper.style.top = '100px';
	}
	}

function anchorClick(event) {
	event.preventDefault();
	let hrefSplit = event.target.href.split('#');
	let elementID = hrefSplit[1];
	
	if(elementID == undefined || elementID == '') return false;
	
	let element = document.getElementById(elementID);
	
	customScrollTo(element);
	}

function customScrollTo(element) {
	location.replace('#' + element.id);
	
	if (element == null) return false;
	
	var elementOffset = element.getBoundingClientRect().top + window.pageYOffset - 110
	
	window.scrollTo({
		top: elementOffset,
		behavior: 'smooth'
	});
	
	}

function expandCode(event) {
	event.preventDefault();
	
	if(event.target.classList.contains('open')) {	// minimize code
		event.target.parentNode.querySelector('.enlighter').style.height = '470px';
		event.target.parentNode.style.height = '534px';
		
		event.target.classList.remove('open');
		event.target.innerHTML = (lang === 'de' ? 'Aufklappen' : 'Expand');
	} else {	// maximize code
		event.target.parentNode.querySelector('.enlighter').style.height = 'auto';
		event.target.parentNode.style.height = 'auto';
		
		event.target.classList.add('open');
		event.target.innerHTML = (lang === 'de' ? 'Zuklappen' : 'Collapse');
	}
	}

function minimizeCodeblocks(codeblock) {
	if(codeblock.offsetHeight >= 450) {
		codeblock.querySelector('.enlighter').style.height = '470px';
		codeblock.querySelector('.enlighter').style.display = 'block';
		codeblock.style.height = '534px';
		
		let expandButton = document.createElement('span');
		expandButton.classList.add('expand-code');
		expandButton.classList.add('btn');
		expandButton.classList.add('btn-block');
		expandButton.classList.add('btn-sm');
		expandButton.classList.add('btn-primary');
		expandButton.classList.add('mt-2');
		expandButton.innerHTML = (lang === 'de' ? 'Aufklappen' : 'Expand');
		expandButton.onclick = expandCode;
		codeblock.appendChild(expandButton);
	}
	}



function registerMatomoEventListeners() {
	// collect menu data
	document.querySelectorAll('.menu-hauptmenue-container .sub-menu .menu-item a, .menu-hauptmenue-en-container .sub-menu .menu-item a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Desktop Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect sidebar click
	document.querySelectorAll('.menu-sidebar-tutorials-de-container li a, .menu-sidebar-tutorials-en-container li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Sidebar Tutorials Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect sidebar click
	document.querySelectorAll('.sidebar-categories a, sidebar-categories a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Sidebar Categories Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect InPost Menu click
	document.querySelectorAll('.interesting-container li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Interesting InPost Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect Table of contents click
	document.querySelectorAll('.table-of-contents li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Table of contents', 'Click', 'Jump to: "' + elem.innerHTML + '"']);
		});
	});
	
	// collect logo click
	document.querySelectorAll('.custom-logo-link').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Link', 'Click', 'Logo Click']);
		});
	});
	}

function showSocialIcons(mobile) {
	if (mobile) {
		document.querySelectorAll('.social-icons.vertical .share-icon').forEach(icon => {
			icon.classList.add('wd-show');
			icon.addEventListener('click', () => {
				document.querySelectorAll('.social-icons.vertical a').forEach(iconElement => {
				
					if(iconElement.classList.contains('wd-show')) {
						iconElement.classList.remove('wd-show');
					} else {
						iconElement.classList.add('wd-show');
					}
					
				});
			});
		});
	} else {
		setTimeout(function() {
			document.querySelectorAll('.social-icons.vertical a').forEach(icon => {
				icon.classList.add('wd-show');
			});
		}, 5000);
	}
	}

function openLightbox(event) {
	event.preventDefault();
	
	if(event.target.src != '') {
		let lightboxContent = '<div class="close">✖</div><img src="' + event.target.src + '"><p>' + event.target.alt + '</p>';
		let lightboxContainer = document.querySelector('.lightbox .img-container');
		
		lightboxContainer.innerHTML = lightboxContent;
		document.querySelector('.lightbox').classList.add('wd-show');
		
		// _paq.push(['trackEvent', 'Lightbox', 'Click', 'Open Lightbox']);
		
		let closeElements = document.querySelectorAll('.lightbox .close, .lightbox .bg-overlay');
		closeElements.forEach(closeElement => {
			closeElement.removeEventListener('click', closeLightboxEvent);
			closeElement.addEventListener('click', closeLightboxEvent);
		})
	}
	}

function closeLightboxEvent() {
	document.querySelector('.lightbox').classList.remove('wd-show');
	}

function execSidebarMovementActions() {
	let jsToTopContainer = document.querySelector('.sidebar-outer-box .js-to-top-container');
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) > 1200 && sidebarScrollEnabled) {
		let offset = window.pageYOffset;
		let singleAfterContent = document.querySelector('.single-after-content');
		let singleAfterContentViewport = singleAfterContent.getBoundingClientRect();
		let singleAfterContentOffset = singleAfterContentViewport.top + window.scrollY;
		let margin = 110;
		let sidebarAd = document.querySelector('.sidebar-box.cwebdeasy-g-container');
		
		if(sidebarAd) {
		
			let sidebarAdHeight = sidebarAd.offsetHeight;
			let sidebarAdOffsetBottom = sidebarAd.getBoundingClientRect().top + sidebarAdHeight;
			if(sidebarAd) margin += sidebarAdHeight;
			
			if(window.pageYOffset < margin) {
				jsToTopContainer.style.marginTop = '1rem';
			} else {
				jsToTopContainer.style.marginTop = (window.pageYOffset - margin) + 'px';
			}
			
		} else {
			jsToTopContainer.style.marginTop = (window.pageYOffset - margin) + 'px';
		}
		
	} else if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) <= 1200) {
		jsToTopContainer.style.marginTop = '0px';
	}
	}

function toggleHeaderShadow() {
	let offset = window.pageYOffset;
	let header = document.querySelector('header#masthead');
	
	if(offset > header.offsetHeight) {
		header.classList.add('header-box-shadow');
	} else {
		header.classList.remove('header-box-shadow');
	}
	}

function checkAdblock() {
	let adblockEnabled = false;
	
	let adCheckElement = document.createElement('div');
	adCheckElement.classList.add('adBanner');
	document.querySelector('body').appendChild(adCheckElement);
	
	let adElement = document.getElementsByClassName('adBanner')[0];
  	let adElementStyle = getComputedStyle(adElement, null);
  	
  	if(adElementStyle.display === 'none') {   // Adblock enabled
  		document.querySelectorAll('.cwebdeasy-g-container').forEach(adElement => {
  			adElement.remove();
  		});
  		document.querySelectorAll('.webd-f-container').forEach(adElement => {
  			adElement.remove();
  		});
  	}
  	}

function openCookieMenu() {
	document.querySelector('.privacy-popup').classList.add('wd-show');
	initCookieClicker();
	}

function initCookieClicker() {
	let acceptCookiesButton = document.querySelector('.privacy-popup .privacy-container #accept-cookies');
	let necessaryCookiesButton = document.querySelector('.privacy-popup .privacy-container #necessary-cookies');
	let showCookiesButton = document.querySelector('.privacy-popup .privacy-container #show-cookies');
	
	acceptCookiesButton.removeEventListener('click', acceptCookiesButtonAction);
	acceptCookiesButton.addEventListener('click', acceptCookiesButtonAction);
	
	necessaryCookiesButton.removeEventListener('click', necessaryCookiesButtonAction);
	necessaryCookiesButton.addEventListener('click', necessaryCookiesButtonAction);
	
	showCookiesButton.removeEventListener('click', showCookiesButtonAction);
	showCookiesButton.addEventListener('click', showCookiesButtonAction);
	}

function acceptCookiesButtonAction() {
	setCookie('cookie-state', 'all', 7);
	
	_paq.push(['forgetUserOptOut']);
	
	document.querySelector('.privacy-popup').classList.remove('wd-show');
	}

function necessaryCookiesButtonAction() {
	setCookie('cookie-state', 'necessary', 7);
	
	_paq.push(['optUserOut'])
	
	document.querySelector('.privacy-popup').classList.remove('wd-show');
	}

function showCookiesButtonAction() {
	let cookieInfos = document.querySelector('.privacy-popup .more-cookie-infos');
	if(cookieInfos.classList.contains('wd-show')) {
		cookieInfos.classList.remove('wd-show');
	} else {
		cookieInfos.classList.add('wd-show');
	}
	}

function setImageRatio() {
	// normal preview
	let imageElements = document.querySelectorAll('.post-preview-container .header-container');
	
	if(imageElements.length) {
		let width = imageElements[0].offsetWidth;
		let height = width / 2;
		for(let i = 0; i < imageElements.length; i++) {
			imageElements[i].style.height = height + 'px';
		}
	}
	
	// // small images
	let smallImageElements = document.querySelectorAll('.post-preview-container .horizontal-look > a');
	
	if(smallImageElements.length) {
		width = smallImageElements[0].offsetWidth;
		height = width / 2;
		for(let i = 0; i < smallImageElements.length; i++) {
			smallImageElements[i].style.height = height + 'px';
		}
	}
	}

function getCookie(cname) {
	var name = cname + '=';
	var decodedCookie = decodeURIComponent(document.cookie);
	var ca = decodedCookie.split(';');
	for (var i = 0; i < ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0) == ' ') {
			c = c.substring(1);
		}
		if (c.indexOf(name) == 0) {
			return c.substring(name.length, c.length);
		}
	}
	return '';
	}

function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
	var expires = 'expires=' + d.toUTCString();
	document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
	}

function toggleMobileSubMenus(event) {
	event.preventDefault();
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) < 1200) {
	
		let childs = event.target.parentNode.parentNode.children;
		
		for(let i = 0; i < childs.length; i++) {
		
			if(childs[i].classList.contains('sub-menu')) {
			
				if(childs[i].classList.contains('wd-show')) {
					childs[i].classList.remove('wd-show');
				} else {
					childs[i].classList.add('wd-show');
				}
				
			}
			
		}
		
	}
	}

function toggleMobileMenu(event) {
	event.preventDefault();
	let button = document.querySelector('.mobile-menu-button');
	let mobileMenuOverlay = document.querySelector('.mobile-menu-bg-overlay');
	
	
	if(button.classList.contains('open')) {	// close menu
		button.classList.remove('open');
		
		document.querySelectorAll('.menu-hauptmenue-container, .menu-hauptmenue-en-container').forEach(menu => {
			menu.classList.remove('wd-show');
		});
		
		mobileMenuOverlay.classList.remove('wd-show');
		mobileMenuOverlay.removeEventListener('click', mobileMenuOverlayClick);
		
	} else {	// open menu
		button.classList.add('open');
		
		document.querySelectorAll('.menu-hauptmenue-container, .menu-hauptmenue-en-container').forEach(menu => {
			menu.classList.add('wd-show');
		});
		
		mobileMenuOverlay.classList.add('wd-show');
		mobileMenuOverlay.addEventListener('click', mobileMenuOverlayClick);
		
		_paq.push(['trackEvent', 'Menu', 'Click', 'Open mobile menu']);
		
	}
	}

function mobileMenuOverlayClick() {
	var event = document.createEvent('HTMLEvents');
	event.initEvent('click', true, false);
	document.querySelector('.mobile-menu-button').dispatchEvent(event);
	}

Ich glaube es wird auch deutlich, was ich mit Aufräumen von Code meine.

Natürlich sollte immer das Ziel sein, Code möglichst wartbar zu entwickeln. Solche Dateien wachsen aber historisch und ich bin natürlich auch selber schuld, dass so ein Chaos entsteht…

Lohnt sich der Aufwand überhaupt?

In meinen Augen: Ja! Neben dem Clean-Up meines Codes habe ich unnötige Funktionen direkt entfernt. Das freut auch die Besucher Deiner Seite.

Ich dachte, dass es ohne jQuery nicht geht. Aber wenn Du wirklich alles aus Deiner Seite rausholen willst, ist das ein guter Schritt.

Ähnliche Beiträge
Beteilige dich an der Unterhaltung

7 Kommentare

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

bold italic underline strikeThrough
insertOrderedList insertUnorderedList outdent indent
removeFormat
createLink unlink
code

Das könnte dich auch interessieren