/** * CommerceKit Floating Cart – frontend script * * Responsibilities: * 1. Open the CommerceKit / Shoptimizer minicart when the floating button is clicked. * 2. Automatically open the minicart after a successful add-to-cart (AJAX or standard). * 3. Play a small badge-bump animation when the item count changes. * * All selectors and feature flags come from the `cgkitFC` object localised by PHP. */ ( function ( $ ) { 'use strict'; /* ----------------------------------------------------------------------- * Module * --------------------------------------------------------------------- */ var FloatingCart = { $btn: null, $count: null, prevCount: 0, /** Bootstrap */ init: function () { if ( typeof cgkitFC === 'undefined' ) { return; } this.$btn = $( '#cgkit-floating-cart .cgkit-floating-cart__btn' ); this.$count = $( '#cgkit-fc-count' ); if ( ! this.$btn.length ) { return; } this.prevCount = parseInt( this.$count.text(), 10 ) || 0; this.bindEvents(); }, /** Attach event listeners */ bindEvents: function () { var self = this; // --- Floating button click → open minicart ----------------------- this.$btn.on( 'click', function ( e ) { e.preventDefault(); self.openMinicart(); } ); // --- Auto-open after AJAX add-to-cart ---------------------------- if ( cgkitFC.autoOpen === 'yes' ) { $( document.body ).on( 'added_to_cart', function () { setTimeout( function () { self.openMinicart(); self.pulseBtn(); }, parseInt( cgkitFC.autoOpenDelay, 10 ) || 400 ); } ); } // --- Badge bump when WooCommerce refreshes fragments ------------- $( document.body ).on( 'wc_fragments_refreshed wc_fragments_loaded', function () { self.maybeBumpBadge(); } ); }, /** * Trigger the theme's minicart open mechanism. * * Strategy: * 1. Try clicking the first element matching the configured selector. * 2. If that element has no jQuery click handlers registered, dispatch * a native 'click' so themes that use addEventListener also fire. * 3. Last resort: navigate to the cart URL. */ openMinicart: function () { var selectors = ( cgkitFC.minicartTrigger || '' ).split( ',' ); var $trigger = null; for ( var i = 0; i < selectors.length; i++ ) { var $el = $( $.trim( selectors[ i ] ) ).first(); if ( $el.length ) { $trigger = $el; break; } } if ( $trigger && $trigger.length ) { // Fire both jQuery and native click so all listeners catch it. $trigger.trigger( 'click' ); var nativeEl = $trigger.get( 0 ); if ( nativeEl && typeof nativeEl.click === 'function' ) { nativeEl.click(); } return; } // No trigger found → fall back to cart page if ( cgkitFC.cartUrl ) { window.location.href = cgkitFC.cartUrl; } }, /** * Add a pulse ring on the button after add-to-cart. */ pulseBtn: function () { var self = this; this.$btn.addClass( 'cgkit-fc--pulse' ); setTimeout( function () { self.$btn.removeClass( 'cgkit-fc--pulse' ); }, 600 ); }, /** * If the item count increased, animate the badge. */ maybeBumpBadge: function () { var $freshCount = $( '#cgkit-fc-count' ); // Re-query in case the fragment replaced the element. if ( ! $freshCount.length ) { return; } this.$count = $freshCount; var newCount = parseInt( this.$count.text(), 10 ) || 0; if ( newCount !== this.prevCount ) { this.prevCount = newCount; this.$count.removeClass( 'cgkit-floating-cart__count--bump' ); // Force reflow so removing + re-adding the class restarts the animation. void this.$count[ 0 ].offsetWidth; // eslint-disable-line no-unused-expressions this.$count.addClass( 'cgkit-floating-cart__count--bump' ); } } }; /* ----------------------------------------------------------------------- * Boot * --------------------------------------------------------------------- */ $( document ).ready( function () { FloatingCart.init(); } ); } )( jQuery );