summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--views/blocks/product-list.phtml7
-rw-r--r--views/css/frontend.css3
-rw-r--r--views/css/wpsg-theme.css3
-rw-r--r--views/mods/mod_productview/productview.js51
4 files changed, 57 insertions, 7 deletions
diff --git a/views/blocks/product-list.phtml b/views/blocks/product-list.phtml
index 55c229c..a58b364 100644
--- a/views/blocks/product-list.phtml
+++ b/views/blocks/product-list.phtml
@@ -5,7 +5,7 @@
*
* Standard ist der Link „Zum Produkt“. Den Knopf „In den Warenkorb“ zeigt die Liste nur, wenn er am Block eingeschaltet
* ist und das Produkt in der Liste gekauft werden darf ($p['buy'], \wpsg\Blocks::canBuyInList(), in eigenen Vorlagen
- * auch wpsg_buy_in_list()).
+ * auch wpsg_buy_in_list()). Mit Produktfilter auf der Seite sagt die Statuszeile die Anzahl an.
* @version 4.6.1
*/
@@ -16,8 +16,11 @@
$hint_id = \wpsg\Blocks::kleinunternehmerHintID();
?>
+<?php if ($arBlock['bFilter']??false) { ?>
+<p class="wpsg-product-list__count" role="status"><?php if ($arBlock['bFiltered']) echo esc_html(sprintf(_n('%d Produkt gefunden', '%d Produkte gefunden', sizeof($arBlock['arProducts']), 'wpsg'), sizeof($arBlock['arProducts']))); ?></p>
+<?php } ?>
<?php if (sizeof($arBlock['arProducts']) === 0) { ?>
-<p class="wpsg-product-list__empty"><?php echo esc_html__('Keine Produkte gefunden.', 'wpsg'); ?></p>
+<p class="wpsg-product-list__empty"><?php echo esc_html((($arBlock['bFiltered']??false)?__('Keine Produkte für diese Filter.', 'wpsg'):__('Keine Produkte gefunden.', 'wpsg'))); ?></p>
<?php } else { ?>
<ul class="wpsg-product-list__items">
<?php foreach ($arBlock['arProducts'] as $p) { $oProduct = $p['oProduct']; $product_id = intval($oProduct->id); $name = $oProduct->getProductName(); ?>
diff --git a/views/css/frontend.css b/views/css/frontend.css
index 4ca386f..4ba7a0f 100644
--- a/views/css/frontend.css
+++ b/views/css/frontend.css
@@ -707,6 +707,8 @@ html body .wpsg_product_garan_wrap a.wpsg_product_garan img { display:block; max
.wpsg_mod_prepayment_qrrechnung_left_amount { display:flex; flex-direction:column; }
/* Blöcke: Produktliste, Mini-Warenkorb, Kundenkonto (seit 4.6.1, nur neue Klassen) */
+.wpsg-block-product-list .wpsg-product-list__count { margin:0 0 1rem; }
+.wpsg-block-product-list .wpsg-product-list__count:empty { display:none; }
.wpsg-block-product-list .wpsg-product-list__items { display:grid; grid-template-columns:repeat(var(--wpsg-columns, 3), minmax(0, 1fr)); gap:2rem 1rem; list-style:none; margin:0; padding:0; }
.wpsg-block-product-list .wpsg-product-list__item { display:flex; flex-direction:column; gap:0.5em; min-width:0; margin:0; padding:0; }
.wpsg-block-product-list .wpsg-product-list__image img { display:block; width:100%; height:auto; }
@@ -765,6 +767,7 @@ html body .wpsg_product_garan_wrap a.wpsg_product_garan img { display:block; max
.wpsg-pvf .wpsg-pvf__price { display:flex; flex-wrap:wrap; align-items:center; gap:0.5em; }
.wpsg-pvf .wpsg-pvf__price label { display:flex; align-items:center; gap:0.35em; }
.wpsg-pvf .wpsg-pvf__price input { width:7em; }
+.wpsg-pvf .wpsg-pvf__price label > span { min-width:1.75em; }
.wpsg-pvf .wpsg-pvf__option { display:flex; align-items:center; gap:0.5em; margin:0.25em 0; }
.wpsg-pvf .wpsg-pvf__color { display:inline-block; width:1.2em; height:1.2em; border:1px solid #CCCCCC; border-radius:3px; }
.wpsg-pvf .wpsg-pvf__actions { display:flex; flex-wrap:wrap; align-items:center; gap:1rem; }
diff --git a/views/css/wpsg-theme.css b/views/css/wpsg-theme.css
index 9df1d8a..80a8279 100644
--- a/views/css/wpsg-theme.css
+++ b/views/css/wpsg-theme.css
@@ -574,6 +574,8 @@ html body .wpsg_product_garan_wrap a.wpsg_product_garan img { display:block; max
.wpsg_overview :where(.garan_label_popup .garan_label_popup_confirm) { flex:0 0 auto; margin-top:1rem; cursor:pointer; }
/* Blöcke: Produktliste, Mini-Warenkorb, Kundenkonto */
+.wpsg-block-product-list :where(.wpsg-product-list__count) { margin:0 0 var(--wpsg-gap); }
+.wpsg-block-product-list :where(.wpsg-product-list__count:empty) { display:none; }
.wpsg-block-product-list :where(.wpsg-product-list__items) { display:grid; grid-template-columns:repeat(var(--wpsg-columns, 3), minmax(0, 1fr)); gap:calc(var(--wpsg-gap) * 2) var(--wpsg-gap); list-style:none; margin:0; padding:0; }
.wpsg-block-product-list :where(.wpsg-product-list__item) { display:flex; flex-direction:column; gap:0.5em; min-width:0; margin:0; padding:0; }
.wpsg-block-product-list :where(.wpsg-product-list__image img) { display:block; width:100%; height:auto; }
@@ -626,6 +628,7 @@ html body .wpsg_product_garan_wrap a.wpsg_product_garan img { display:block; max
.wpsg-pvf :where(.wpsg-pvf__price) { display:flex; flex-wrap:wrap; align-items:center; gap:0.5em; }
.wpsg-pvf :where(.wpsg-pvf__price label) { display:flex; align-items:center; gap:0.35em; }
.wpsg-pvf :where(.wpsg-pvf__price input) { width:7em; }
+.wpsg-pvf :where(.wpsg-pvf__price label > span) { min-width:1.75em; }
.wpsg-pvf :where(.wpsg-pvf__option) { display:flex; align-items:center; gap:0.5em; margin:0.25em 0; }
.wpsg-pvf :where(.wpsg-pvf__color) { display:inline-block; width:1.2em; height:1.2em; border:1px solid var(--wpsg-color-line); border-radius:var(--wpsg-radius); }
.wpsg-pvf :where(.wpsg-pvf__actions) { display:flex; flex-wrap:wrap; align-items:center; gap:var(--wpsg-gap); }
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;
}