So, ich habe endlich eine funktionierende, einigermaßen zufriedenstellende Lösung gefunden. Die Schwierigkeit bei der changePage-Funktion war, die einzelnen Seiten sowohl über die Pfeile als auch über diese runden Positionsmarkierungen unten steuern zu können.
Jetzt habe ich eine einzige Funktion, die sich um alles kümmert und dabei auf keine anderen Funktionen angewiesen ist (weder innenerhalb noch außerhalb):
const changePage = ( currentPage, reset ) => {
console.log( '%crun function: ' + '%cchangePage', 'font-family: "JetBrains Mono";', 'font-family: "JetBrains Mono"; color: red;' );
const page = document.querySelectorAll( '.page' );
const pos = document.querySelector( '.pos' );
const posMarker = pos.childNodes;
const arrowLeft = document.querySelector( '.arrow:first-child' );
const arrowRight = document.querySelector( '.arrow:last-child' );
let i = 1;
// P R E P A R A T I O N
if ( reset === true ) {
currentPage = document.querySelector( '.page[aria-selected="true"]' ).id;
// a d d - p o s M a r k e r s
pos.replaceChildren();
page.forEach ( () => {
const el = `<button type="button" data-ref="${i++}"><span class="sr">Positionsmarkierung</span></button>`;
pos.insertAdjacentHTML( 'beforeend', el );
});
// a d d - E v e n t L i s t e n e r s
arrowLeft.addEventListener( 'click', () => { changePage( 'previous', false ); });
arrowRight.addEventListener( 'click', () => { changePage( 'next', false ); });
document.querySelector( '.change-page' ).addEventListener( 'keydown', ( e ) => {
let key = e.keyCode;
if ( key === 37 ) { changePage( 'previous', false ); arrowLeft.focus(); }
if ( key === 39 ) { changePage( 'next', false ); arrowRight.focus(); }
});
// p o s M a r k e r
posMarker.forEach( node => {
node.addEventListener( 'click', function() {
for ( let sibling of node.parentNode.children ) // s e l e c t - a l l - p o s M a r k e r s
if ( sibling === this ) sibling.setAttribute( 'aria-current', 'location' ); // a d d - h i g h l i g h t i n g
else sibling.removeAttribute( 'aria-current' ); // r e m o v e - h i g h l i g h t i n g
// s e l e c t - c u r r e n t P a g e
currentPage = this.dataset.ref;
changePage( currentPage, false );
});
// i n i t i a l - h i g h l i g h t i n g
if ( node.dataset.ref !== currentPage ) return;
else node.setAttribute( 'aria-current', 'location' );
});
} else {
// C H A N G E - P A G E
let currentPosMarker = document.querySelector( '.pos button[aria-current="location"]' );
if ( currentPage === 'previous' ) {
currentPage = document.querySelector( '.page[aria-selected="true"]' );
if ( currentPage.previousElementSibling ) {
// s e l e c t - c u r r e n t P a g e
currentPage = currentPage.previousElementSibling.id;
// h i g h l i g h t - c u r r e n t P o s M a r k e r
currentPosMarker.previousElementSibling.setAttribute( 'aria-current', 'location' );
currentPosMarker.removeAttribute( 'aria-current' );
currentPosMarker = currentPosMarker.previousElementSibling;
} else return; // s t o p - o n - m i n
} else if ( currentPage === 'next' ) {
currentPage = document.querySelector( '.page[aria-selected="true"]' );
if ( currentPage.nextElementSibling ) {
// s e l e c t - c u r r e n t P a g e
currentPage = currentPage.nextElementSibling.id;
// h i g h l i g h t - c u r r e n t P o s M a r k e r
currentPosMarker.nextElementSibling.setAttribute( 'aria-current', 'location' );
currentPosMarker.removeAttribute( 'aria-current' );
currentPosMarker = currentPosMarker.nextElementSibling;
} else return; // s t o p - o n - m a x
}
// A D D - A N I M A T I O N
page.forEach( node => { node.classList.add( 'on' ); });
}
// S H O W - C U R R E N T - P A G E
page.forEach( node => {
if ( node.id == currentPage )
node.setAttribute( 'aria-selected', true );
else node.removeAttribute( 'aria-selected' );
});
// D E A C T I V A T E - A R R O W - O N - M I N - O R - M A X
if ( currentPage == 1 ) { arrowLeft.classList.add( 'off' ); arrowLeft.tabIndex = -1; }
else if ( currentPage >= 1 ) { arrowLeft.classList.remove( 'off' ); arrowLeft.tabIndex = 0; }
if ( currentPage == page.length ) { arrowRight.classList.add( 'off' ); arrowRight.tabIndex = -1; }
else if ( currentPage < page.length ) { arrowRight.classList.remove( 'off' ); arrowRight.tabIndex = 0; }
// --> P R E V E N T : P R E P A R A T I O N
reset = false;
};
Ein weiteres Problem bestand jedoch, das mich einige Zeit gekostet hat, bis ich eine passable Lösung gefunden habe, und zwar die Tatsache, dass die HTML-Elemente mit den EventListeners „resettet“ werden mussten (der Grund dafür wurde ja schon festgestellt). Hier habe ich nun gelernt, dass man mehrere fetch requests nacheinander ausführen kann. Also wird der ganze HTML-Teil, der für die Navigation zwischen den Seiten zuständig ist, beim Wechsel der „Kartenpakete“ ebenfalls neu geladen:
fetch( 'includes/' + href )
.then( ( response ) => {
if ( !response.ok ) throw 'Seite nicht gefunden.';
else return response.text();
})
.then( ( html ) => {
mapsGroup.innerHTML = html;
// s e c o n d - f e t c h - r e q u e s t
return fetch( '/includes/change-page.php' );
})
.then( response => {
if ( !response.ok ) throw 'Seite nicht gefunden.';
else return response.text();
})
.then( html => {
document.querySelector( '.change-page' ).outerHTML = html;
changePage( undefined, true );
})
.catch( ( error ) => { console.log( error ); });
Ich glaube, sonst habe ich hier aber nichts mehr übersehen, außer vermutlich noch ein paar Redundanzen im Code. Promise.all
gibt es ja auch noch. Keine Ahnung, ob das geeignet ist, um fetch()
bei mehreren Anfragen zu ersetzen.