summaryrefslogtreecommitdiff
path: root/views/mods/mod_productview/productview.js
diff options
context:
space:
mode:
Diffstat (limited to 'views/mods/mod_productview/productview.js')
-rw-r--r--views/mods/mod_productview/productview.js148
1 files changed, 148 insertions, 0 deletions
diff --git a/views/mods/mod_productview/productview.js b/views/mods/mod_productview/productview.js
new file mode 100644
index 0000000..5879d68
--- /dev/null
+++ b/views/mods/mod_productview/productview.js
@@ -0,0 +1,148 @@
+/**
+ * wpShopGermany, Modul Produktansichten: Seiten, Sortierung, Ansicht und Filter ohne Neuladen
+ *
+ * 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.
+ */
+
+( function() {
+
+ 'use strict';
+
+ function flatten( prefix, value, params ) {
+
+ if ( value !== null && typeof value === 'object' ) {
+
+ Object.keys( value ).forEach( function( k ) { flatten( prefix + '[' + k + ']', value[ k ], params ); } );
+
+ } else if ( value !== undefined && value !== null ) {
+
+ params.append( prefix, String( value ) );
+
+ }
+
+ return params;
+
+ }
+
+ function filterValues() {
+
+ const form = document.getElementById( 'wpsg_mod_productview_filter' );
+ const values = {};
+
+ if ( !form ) return values;
+
+ new FormData( form ).forEach( function( v, name ) {
+
+ const m = name.match( /^pvf\[(\w+)\](?:\[(\d+)\])?/ );
+ if ( !m || v === '' ) return;
+
+ if ( m[ 2 ] ) {
+
+ values[ m[ 1 ] ] = values[ m[ 1 ] ] || {};
+ values[ m[ 1 ] ][ m[ 2 ] ] = values[ m[ 1 ] ][ m[ 2 ] ] ? values[ m[ 1 ] ][ m[ 2 ] ] + ',' + v : v;
+
+ } else values[ m[ 1 ] ] = v;
+
+ } );
+
+ return values;
+
+ }
+
+ function refresh( box, change, url ) {
+
+ const field = box.querySelector( 'input[name="wpsg_atts"]' );
+ if ( !field ) return false;
+
+ const atts = JSON.parse( field.value );
+ Object.assign( atts, change );
+
+ const params = flatten( 'wpsg_atts', atts, new URLSearchParams( { wpsg_mod: 'wpsg_mod_productview', wpsg_action: 'refresh' } ) );
+
+ box.classList.add( 'is-loading' );
+ box.setAttribute( 'aria-busy', 'true' );
+
+ fetch( box.getAttribute( 'data-wpsg-pv-url' ) + ( box.getAttribute( 'data-wpsg-pv-url' ).indexOf( '?' ) === -1 ? '?' : '&' ) + params.toString(), { credentials: 'same-origin' } )
+ .then( function( r ) { if ( !r.ok ) throw new Error( r.status ); return r.text(); } )
+ .then( function( html ) {
+
+ const tmp = document.createElement( 'div' );
+ tmp.innerHTML = html;
+
+ const fresh = tmp.querySelector( '.wpsg_productview' );
+ if ( !fresh ) throw new Error( 'leer' );
+
+ fresh.querySelectorAll( '.wpsg-pv__order-submit' ).forEach( function( b ) { b.hidden = true; } );
+ box.replaceWith( fresh );
+ if ( url ) history.pushState( { wpsgPv: true }, '', url );
+
+ } )
+ .catch( function() { if ( url ) location.href = url; } );
+
+ return true;
+
+ }
+
+ document.addEventListener( 'click', function( e ) {
+
+ const a = e.target.closest( '.wpsg-pv__pager a, .wpsg-pv__modes a' );
+ if ( !a ) return;
+
+ const box = a.closest( '.wpsg_productview' );
+ const change = a.hasAttribute( 'data-page' ) ? { page: a.getAttribute( 'data-page' ) } : { mode: a.getAttribute( 'data-mode' ) };
+
+ if ( refresh( box, change, a.href ) ) e.preventDefault();
+
+ } );
+
+ document.addEventListener( 'change', function( e ) {
+
+ const select = e.target.closest( '.wpsg-pv__order select' );
+
+ if ( select ) {
+
+ const form = select.form;
+ const url = form.action + ( form.action.indexOf( '?' ) === -1 ? '?' : '&' ) + new URLSearchParams( new FormData( form ) ).toString();
+
+ refresh( select.closest( '.wpsg_productview' ), { order: select.value, page: 1 }, url );
+ return;
+
+ }
+
+ if ( e.target.closest( '#wpsg_mod_productview_filter' ) ) applyFilter();
+
+ } );
+
+ document.addEventListener( 'submit', function( e ) {
+
+ if ( e.target.id !== 'wpsg_mod_productview_filter' ) return;
+
+ if ( applyFilter() ) e.preventDefault();
+
+ } );
+
+ function applyFilter() {
+
+ const form = document.getElementById( 'wpsg_mod_productview_filter' );
+ const box = document.querySelector( '.wpsg_productview' );
+ if ( !form || !box ) return false;
+
+ const params = new URLSearchParams();
+ new FormData( form ).forEach( function( v, name ) { if ( v !== '' && !/^pv-/.test( name ) ) params.append( name, v ); } );
+
+ // 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() );
+
+ }
+
+ // Zurück und Vor: den Stand aus der Adresse neu laden
+ window.addEventListener( 'popstate', function( e ) { if ( e.state && e.state.wpsgPv ) location.reload(); } );
+
+ // Mit JavaScript sortiert die Auswahl sofort
+ document.querySelectorAll( '.wpsg-pv__order-submit' ).forEach( function( b ) { b.hidden = true; } );
+
+} )();