summaryrefslogtreecommitdiff
path: root/views/mods
diff options
context:
space:
mode:
authorRoger Rehnelt <noreply@maennchen1.de>2026-10-01 20:34:26 +0200
committerRoger Rehnelt <noreply@maennchen1.de>2026-10-01 20:34:26 +0200
commitd47da4744f951937d2769045af303a032dc20755 (patch)
tree1693f4a170c508be1b2bbfcef63cc971ba11a0d6 /views/mods
parent5b9eb8d486b5c25205413cfc0f817462f07f9b37 (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.js51
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;
}