diff options
| author | Roger Rehnelt <noreply@maennchen1.de> | 2026-10-01 20:34:26 +0200 |
|---|---|---|
| committer | Roger Rehnelt <noreply@maennchen1.de> | 2026-10-01 20:34:26 +0200 |
| commit | d47da4744f951937d2769045af303a032dc20755 (patch) | |
| tree | 1693f4a170c508be1b2bbfcef63cc971ba11a0d6 /views/mods | |
| parent | 5b9eb8d486b5c25205413cfc0f817462f07f9b37 (diff) | |
Blöcke: Produktfilter
Neuer Block Produktfilter (Preis, Varianten, Produktattribute) auf Grundlage von [wpsg_productview_filter]. Er filtert die Produktlisten und Produktansichten derselben Seite; die Auswahl steht in der Adresse, ohne JavaScript bedienbar, Anzahl für Screenreader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'views/mods')
| -rw-r--r-- | views/mods/mod_productview/productview.js | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/views/mods/mod_productview/productview.js b/views/mods/mod_productview/productview.js index 5879d68..fc03a1f 100644 --- a/views/mods/mod_productview/productview.js +++ b/views/mods/mod_productview/productview.js @@ -4,6 +4,8 @@ * Ohne JavaScript funktionieren Links und Formulare über die Adresse. Mit JavaScript holt das Skript die Ansicht per * Ajax (wpsg_mod=wpsg_mod_productview, wpsg_action=refresh) und schreibt den Zustand in die Adresse. Die Attribute des * Shortcodes kommen signiert aus dem Feld wpsg_atts; der Server übernimmt nur Seite, Sortierung, Ansicht und Filter. + * Produktlisten mit data-wpsg-filter (Block Produktliste) holt es mit der neuen Adresse als ganze Seite, wie ohne + * JavaScript, und tauscht ihren Inhalt; die Statuszeile bleibt stehen und sagt die neue Anzahl an. */ ( function() { @@ -51,7 +53,7 @@ } - function refresh( box, change, url ) { + function refresh( box, change, url, push ) { const field = box.querySelector( 'input[name="wpsg_atts"]' ); if ( !field ) return false; @@ -76,7 +78,7 @@ fresh.querySelectorAll( '.wpsg-pv__order-submit' ).forEach( function( b ) { b.hidden = true; } ); box.replaceWith( fresh ); - if ( url ) history.pushState( { wpsgPv: true }, '', url ); + if ( url && push !== false ) history.pushState( { wpsgPv: true }, '', url ); } ) .catch( function() { if ( url ) location.href = url; } ); @@ -123,11 +125,42 @@ } ); + function refreshLists( lists, url ) { + + lists.forEach( function( list ) { list.setAttribute( 'aria-busy', 'true' ); } ); + + fetch( url, { credentials: 'same-origin' } ) + .then( function( r ) { if ( !r.ok ) throw new Error( r.status ); return r.text(); } ) + .then( function( html ) { + + const fresh = new DOMParser().parseFromString( html, 'text/html' ).querySelectorAll( '[data-wpsg-filter]' ); + if ( fresh.length !== lists.length ) throw new Error( 'anders' ); + + lists.forEach( function( list, i ) { + + const status = list.querySelector( '.wpsg-product-list__count' ); + + Array.prototype.slice.call( list.children ).forEach( function( child ) { if ( child !== status ) child.remove(); } ); + Array.prototype.slice.call( fresh[ i ].children ).forEach( function( child ) { if ( !child.classList.contains( 'wpsg-product-list__count' ) ) list.appendChild( document.importNode( child, true ) ); } ); + + const freshStatus = fresh[ i ].querySelector( '.wpsg-product-list__count' ); + if ( status && freshStatus ) status.textContent = freshStatus.textContent; + + list.removeAttribute( 'aria-busy' ); + + } ); + + } ) + .catch( function() { location.href = url; } ); + + } + function applyFilter() { const form = document.getElementById( 'wpsg_mod_productview_filter' ); - const box = document.querySelector( '.wpsg_productview' ); - if ( !form || !box ) return false; + const boxes = document.querySelectorAll( '.wpsg_productview' ); + const lists = document.querySelectorAll( '[data-wpsg-filter]' ); + if ( !form || ( !boxes.length && !lists.length ) ) return false; const params = new URLSearchParams(); new FormData( form ).forEach( function( v, name ) { if ( v !== '' && !/^pv-/.test( name ) ) params.append( name, v ); } ); @@ -135,7 +168,15 @@ // Sortierung und Ansicht aus der aktuellen Adresse behalten, die Seite beginnt neu new URLSearchParams( location.search ).forEach( function( v, name ) { if ( /^pv-.*(order|mode)$/.test( name ) ) params.append( name, v ); } ); - return refresh( box, { filter: filterValues(), page: 1 }, form.action + ( form.action.indexOf( '?' ) === -1 ? '?' : '&' ) + params.toString() ); + const url = form.action + ( form.action.indexOf( '?' ) === -1 ? '?' : '&' ) + params.toString(); + const values = filterValues(); + + boxes.forEach( function( box ) { refresh( box, { filter: values, page: 1 }, url, false ); } ); + if ( lists.length ) refreshLists( lists, url ); + + history.pushState( { wpsgPv: true }, '', url ); + + return true; } |
