2026-03-05 08:01:33 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* 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();
|
2026-03-05 08:20:37 +01:00
|
|
|
|
// Stop the click bubbling to document-level handlers.
|
|
|
|
|
|
// Shoptimizer closes the cart on any click outside .shoptimizer-cart,
|
|
|
|
|
|
// so without this the cart would open then instantly close again.
|
|
|
|
|
|
e.stopPropagation();
|
2026-03-05 08:01:33 +01:00
|
|
|
|
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.
|
|
|
|
|
|
*
|
2026-03-05 08:08:18 +01:00
|
|
|
|
* Strategy (stops at the first approach that succeeds):
|
|
|
|
|
|
* 1. Find the header cart button via the configured selector list and
|
|
|
|
|
|
* fire ONE native click on it. Using native click (not jQuery trigger
|
|
|
|
|
|
* + native) avoids the double-fire / toggle-closed bug.
|
|
|
|
|
|
* 2. If no button is found, try to show the Shoptimizer cart panel
|
|
|
|
|
|
* directly by toggling the body class the theme uses.
|
2026-03-05 08:01:33 +01:00
|
|
|
|
* 3. Last resort: navigate to the cart URL.
|
2026-03-05 08:08:18 +01:00
|
|
|
|
*
|
|
|
|
|
|
* NOTE: never call both $el.trigger('click') AND el.click() — that
|
|
|
|
|
|
* fires two events and the toggle cancels itself immediately.
|
2026-03-05 08:01:33 +01:00
|
|
|
|
*/
|
|
|
|
|
|
openMinicart: function () {
|
2026-03-05 08:08:18 +01:00
|
|
|
|
// --- 1. Try clicking the configured header cart button ------------
|
2026-03-05 08:01:33 +01:00
|
|
|
|
var selectors = ( cgkitFC.minicartTrigger || '' ).split( ',' );
|
|
|
|
|
|
|
|
|
|
|
|
for ( var i = 0; i < selectors.length; i++ ) {
|
|
|
|
|
|
var $el = $( $.trim( selectors[ i ] ) ).first();
|
|
|
|
|
|
if ( $el.length ) {
|
2026-03-05 08:08:18 +01:00
|
|
|
|
// One native click – reaches both jQuery and native listeners.
|
|
|
|
|
|
$el[ 0 ].click();
|
|
|
|
|
|
return;
|
2026-03-05 08:01:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 08:08:18 +01:00
|
|
|
|
// --- 2. Shoptimizer direct panel toggle --------------------------
|
2026-03-05 08:14:08 +01:00
|
|
|
|
// Shoptimizer's cart anchor is a.cart-contents inside .shoptimizer-cart.
|
|
|
|
|
|
// If the selector loop above somehow missed it, grab it directly.
|
|
|
|
|
|
var $directBtn = $( '.shoptimizer-cart a.cart-contents' );
|
|
|
|
|
|
if ( $directBtn.length ) {
|
|
|
|
|
|
$directBtn[ 0 ].click();
|
2026-03-05 08:01:33 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 08:08:18 +01:00
|
|
|
|
// --- 3. Fall back to cart page -----------------------------------
|
2026-03-05 08:01:33 +01:00
|
|
|
|
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 );
|