Advertisement
codex23

mini-cart source code

Jun 10th, 2025
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 11.87 KB | Source Code | 0 0
  1. /* mini_cart_actions.js */
  2. export default class MiniCartActions {
  3.     'use strict';
  4.  
  5.     constructor(uiBody) {
  6.        
  7.         //Properties
  8.         this.body = document.querySelector(uiBody);
  9.         if (!this.body) {
  10.             console.error(`Element with selector '${uiBody}' not found.`);
  11.         }
  12.        
  13.         this.sidebar = this.body.querySelector('.sidebar');
  14.         this.shopping_menu = this.body.querySelector('.shopping-menu-wrapper .shopping-menu');
  15.        
  16.         //mini cart and mini cart icon
  17.         //this.mini_cart = this.findMiniCart();
  18.         //this.cart_icon = this.findCartIcon();
  19.        
  20.         //mini cart
  21.         const mobile_mini_cart = this.sidebar.querySelector('.actionsWrapper .widget_shopping_cart_content');
  22.         const default_mini_cart = this.shopping_menu.querySelector('.widget_shopping_cart_content');
  23.         this.mini_cart = mobile_mini_cart
  24.         ? mobile_mini_cart
  25.         : default_mini_cart;
  26.        
  27.         //mini cart icon
  28.         const mobile_cart_icon = this.sidebar.querySelector('.actionsWrapper .shop-icons #cart-icon');
  29.         const default_cart_icon = this.shopping_menu.querySelector('.shop-icons #cart-icon');
  30.         this.cart_icon = mobile_cart_icon
  31.         ? mobile_cart_icon
  32.         : default_cart_icon;
  33.        
  34.         this.cart_items = this.shopping_menu.querySelectorAll('.woocommerce-mini-cart-item');
  35.        
  36.         //mini cart counter
  37.         this.mini_cart_counter = this.findMiniCartCounter();
  38.        
  39.         this.p_add_to_cart = this.shopping_menu.querySelectorAll('.product-actions .add_to_cart_button');
  40.        
  41.         //close mini cart
  42.         this.close_mini_cart = this.mini_cart.querySelector('#close-container');
  43.        
  44.         console.log('mini-cart classlist (constructor): ', this.mini_cart);
  45.         console.log('cart_icon classlist (constructor): ', this.cart_icon);
  46.        
  47.         /*
  48.         this.miniCartSelector = '.shopping-menu .widget_shopping_cart_content';
  49.         this.miniCartIconSelector = '.shop-icons #cart-icon';
  50.         this.close_mini_cartSelector = '#close-container';
  51.         this.cartItemsSelector = '.shopping-menu .woocommerce-mini-cart-item';
  52.         this.miniCartCounterSelector = '.mini_cart_counter';
  53.         this.p_add_to_cartSelector = '.product-actions .add_to_cart_button';
  54.         */
  55.        
  56.         //Methods
  57.         //this.initElements();
  58.         //this.initializeContainer(this.mini_cart);
  59.         this.miniCartActivator();
  60.        
  61.     }
  62.     /*
  63.     initElements() {
  64.         // Query within this.body, not global document
  65.         this.miniCart = this.body.querySelector(this.miniCartSelector);
  66.         this.miniCartIcon = this.body.querySelector(this.miniCartIconSelector);
  67.         this.close_mini_cart = this.body.querySelector(this.close_mini_cartSelector);
  68.  
  69.    
  70.         this.cartItems = document.querySelectorAll(this.cartItemsSelector);
  71.         this.miniCartCounter = document.querySelector(this.miniCartCounterSelector);
  72.         this.p_add_to_cart = document.querySelectorAll(this.p_add_to_cartSelector);
  73.        
  74.         console.log('this is miniCartIcon from initElements: ', this.miniCartIcon);
  75.        
  76.         // Add null checks
  77.         if (!this.miniCartIcon) {
  78.             throw new Error('Mini cart icon not found');
  79.         }
  80.        
  81.         if (!this.miniCart) {
  82.             throw new Error(`Cart container not found with selector: ${this.miniCartSelector}`);
  83.         }
  84.        
  85.         //this.miniCart.classList.add('inactive');     
  86.     }
  87.     */
  88.    
  89.     findMiniCart() {
  90.         /**
  91.         * Finds the mini-cart container element in the DOM.
  92.         * Searches first in the mobile sidebar's actionsWrapper, then falls back
  93.         * to the desktop shopping-menu container.
  94.         *
  95.         * @returns {HTMLElement|null} The mini-cart container element (.widget_shopping_cart_content)
  96.         *                            or null if not found in either location
  97.         */
  98.        
  99.         let miniCart = null;
  100.        
  101.         if (this.sidebar) {
  102.             miniCart = this.sidebar.querySelector('.actionsWrapper .widget_shopping_cart_content');
  103.         }
  104.        
  105.         if (!miniCart && this.shopping_menu) {
  106.             miniCart = this.shopping_menu.querySelector('.widget_shopping_cart_content');
  107.         }
  108.         console.log('findMiniCart(): ', miniCart);
  109.         return miniCart;
  110.     }
  111.    
  112.     findCartIcon() {
  113.         /**
  114.         * Finds the cart icon element in the DOM.
  115.         * Searches first in the mobile sidebar's actionsWrapper, then falls back
  116.         * to the desktop shopping-menu container.
  117.         *
  118.         * @returns {HTMLElement|null} The cart icon element (#cart-icon)
  119.         *                            or null if not found in either location
  120.         */
  121.        
  122.         let cartIcon = null;
  123.         console.log('findCartIcon() (sidebar): ', cartIcon);
  124.         if (this.sidebar) {
  125.             cartIcon = this.sidebar.querySelector('.actionsWrapper .shop-icons #cart-icon');
  126.            
  127.         }
  128.        
  129.         if (!cartIcon && this.shopping_menu) {
  130.             cartIcon = this.shopping_menu.querySelector('.shop-icons #cart-icon');
  131.            
  132.         }
  133.         console.log('findCartIcon() (shopping_menu): ', cartIcon);
  134.         return cartIcon;
  135.     }
  136.    
  137.     findMiniCartCounter() {
  138.         /**
  139.         * Finds the mini-cart counter element in the DOM.
  140.         * Searches first in the mobile sidebar's actionsWrapper, then falls back
  141.         * to the desktop shopping-menu container.
  142.         *
  143.         * @returns {HTMLElement|null} The mini-cart counter element (.mini_cart_counter)
  144.         *                            or null if not found in either location
  145.         */
  146.        
  147.         let counter = null;
  148.        
  149.         if (this.sidebar) {
  150.             counter = this.sidebar.querySelector('.actionsWrapper .mini_cart_counter');
  151.         }
  152.        
  153.         if (!counter && this.shopping_menu) {
  154.             counter = this.shopping_menu.querySelector('.mini_cart_counter');
  155.         }
  156.         console.log('findMiniCartCounter(): ', counter);
  157.         return counter;
  158.     }
  159.    
  160.     initializeContainer(container) {
  161.         /**
  162.         * Initializes the mini-cart to its default inactive state.
  163.         * Removes any 'active' class and adds 'inactive' class to ensure
  164.         * the mini-cart starts hidden when the page loads or reloads.
  165.         *
  166.         * @returns {void}
  167.         */
  168.         if (!container) {
  169.             console.error('Cannot initialize mini cart - element not found');
  170.             return;
  171.         }
  172.        
  173.         // Remove all state classes first
  174.         //this.mini_cart.classList.remove('cart_active', 'cart_inactive');
  175.        
  176.         // Add inactive class
  177.         container.classList.add('cart_inactive');
  178.        
  179.         console.log('Mini cart initialized as inactive. Classes: ', container.classList.toString());
  180.        
  181.         // Force a reflow to ensure the class is applied
  182.         this.mini_cart.offsetHeight;
  183.     }
  184.    
  185.     stateSetter(element, off, on) {
  186.         /**
  187.         * stateSetter
  188.         * Toggles the class state of a given element by removing an "off" state and adding an "on" state.
  189.         *
  190.         * @param {HTMLElement} element - The element to update.
  191.         * @param {string} off - The class name representing the "off" state.
  192.         * @param {string} on - The class name representing the "on" state.
  193.         * @returns {HTMLElement} - The updated element.
  194.         */
  195.         element.classList.remove(off);
  196.         element.classList.add(on);
  197.         console.log('stateSetter(): ', element.classList);
  198.         return element;
  199.     }
  200.    
  201.     stateControl(trigger, element) {
  202.         /**
  203.         * stateControl
  204.         * Binds a click event listener to the trigger element. When clicked, it toggles
  205.         * the state (active/inactive) of the target element.
  206.         *
  207.         * @param {HTMLElement} trigger - The element that triggers the state change.
  208.         * @param {HTMLElement} element - The target element whose state is toggled.
  209.         */
  210.         console.log('stateControl() trigger: ', trigger);
  211.         console.log('stateControl() element: ', element);
  212.         trigger.addEventListener('click', () => {
  213.             if (element.classList.contains('cart_inactive')) {
  214.                 this.stateSetter(element, 'cart_inactive', 'cart_active');
  215.                
  216.                 return element;
  217.             } else if(element.classList.contains('cart_active')) {
  218.                 this.stateSetter(element, 'cart_active', 'cart_inactive');
  219.                
  220.                 return element;
  221.             } else {
  222.                 return;
  223.             }
  224.         });
  225.     }
  226.        
  227.     closeMiniCart(container, closeToggle) {
  228.         if (!container || !closeToggle) {
  229.             console.error('closeMiniCart: Missing container or closeToggle');
  230.             return;
  231.         }
  232.        
  233.         console.log('Setting up close mini cart listener');
  234.        
  235.         closeToggle.addEventListener('click', (event) => {
  236.             event.preventDefault();
  237.             event.stopPropagation();
  238.             console.log('Close button clicked');
  239.             this.stateSetter(container, 'cart_active', 'cart_inactive');
  240.         });
  241.        
  242.         return container;
  243.     }
  244.    
  245.     appendElem(trigger, element) {
  246.         /**
  247.         * appendElem
  248.         * Appends a given element to the trigger element.
  249.         *
  250.         * @param {HTMLElement} trigger - The parent element where the element should be appended.
  251.         * @param {HTMLElement} element - The element to append.
  252.         * @returns {HTMLElement} - The appended element.
  253.         */
  254.         if (!trigger || !element) {
  255.             console.error('appendElem: Missing trigger or element');
  256.             return null;
  257.         }
  258.        
  259.         const appended = trigger.appendChild(element);
  260.        
  261.         return appended;
  262.     }
  263.    
  264.    
  265.     activateCounter() {
  266.         /**
  267.         * activateCounter
  268.         * Updates the mini-cart counter state from inactive to active.
  269.         *
  270.         * @returns {HTMLElement|undefined} - The updated mini cart counter, if updated.
  271.         */
  272.         if (!this.mini_cart_counter) {
  273.             return;
  274.         }
  275.        
  276.         if (this.mini_cart_counter.classList.contains('counter_inactive')) {
  277.             this.stateSetter(this.mini_cart_counter, 'counter_inactive', 'counter_active');
  278.             return this.mini_cart_counter;
  279.         }
  280.     }
  281.    
  282.     buttonHandler(buttons) {
  283.         /**
  284.         * buttonHandler
  285.         * Attaches a click event listener to each add-to-cart button, triggering the counter activation.
  286.         *
  287.         * @param {NodeList|Array} buttons - A collection of add-to-cart button elements.
  288.         * @returns {NodeList|Array} - The collection of buttons with event listeners attached.
  289.         */
  290.         if (!buttons || buttons.length === 0) {
  291.             return buttons;
  292.         }
  293.        
  294.         buttons.forEach(button => {
  295.             button.addEventListener('click', () => {
  296.                 this.activateCounter(); // Fixed: was missing 'this.'
  297.             });
  298.         });
  299.        
  300.         return buttons;
  301.     }
  302.    
  303.    
  304.     closeWhenOutside(entity) {
  305.         /**
  306.         * closeWhenOutside
  307.         * Binds a click event listener to an external entity (like the document) that closes the mini-cart
  308.         * if the click occurs outside the cart icon and mini cart.
  309.         *
  310.         * @param {HTMLElement} entity - The element to listen for clicks (typically document).
  311.         */
  312.         if (!entity) {
  313.             console.error('closeWhenOutside: No entity provided');
  314.             return;
  315.         }
  316.        
  317.         if (!this.mini_cart || !this.cart_icon) {
  318.             console.error('closeWhenOutside: Required elements not found');
  319.             return;
  320.         }
  321.    
  322.         console.log('Setting up outside click handler');
  323.        
  324.         entity.addEventListener('click', (event) => {
  325.             // Only close if mini cart is currently active
  326.             if (this.mini_cart.classList.contains('cart_active')) {
  327.                 const clickedInsideCart = this.mini_cart.contains(event.target);
  328.                 const clickedInsideIcon = this.cart_icon.contains(event.target);
  329.                
  330.                 if (!clickedInsideCart && !clickedInsideIcon) {
  331.                     console.log('Clicked outside, closing mini cart');
  332.                     this.stateSetter(this.mini_cart, 'cart_active', 'cart_inactive');
  333.                 }
  334.             }
  335.         });
  336.     }
  337.    
  338.     miniCartActivator() {
  339.         /**
  340.         * miniCartActivator
  341.         * Ties all mini-cart related behaviors together:
  342.         * cartState - Binds state control to the cart icon for toggling the mini-cart.
  343.         * buttonState - Attaches event listeners to add-to-cart buttons.
  344.         * closeWhenOutside - Sets up the event listener to close the mini-cart when clicking outside.
  345.         * appendMenu - Appends the mini-cart counter to the shopping menu.
  346.         *
  347.         * @returns {object} - An object containing the activated actions.
  348.         */
  349.        
  350.         console.log('this is events (mini_cart_actions)');
  351.         console.log('this is events(): ', this.close_mini_cart);
  352.        
  353.         const actions = {
  354.             initializeState: this.initializeContainer(this.mini_cart),
  355.             cartState: this.stateControl(this.cart_icon, this.mini_cart),
  356.             buttonState: this.buttonHandler(this.p_add_to_cart),
  357.             closeWhenOutside: this.closeWhenOutside(document),
  358.             appendMenu: this.appendElem(this.shopping_menu, this.mini_cart_counter)
  359.             //closeMiniCart: this.closeMiniCart(this.mini_cart, this.cart_icon)
  360.         };
  361.        
  362.         return actions;
  363.     }  
  364.    
  365.    
  366.    
  367.  
  368. }
  369.  
  370. /* index.js */
  371.  
  372. import MiniCartActions from './/modules/mini_cart_actions.js';
  373. const miniCartActions = new MiniCartActions('body');
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement