PageSourceSearch

https://www.anchorpackaging.com/wp-content/themes/anchor-packaging/assets/js/cart.js?ver=1.0

js anchorpackaging.com collected 2026-10-04 01:31:18 UTC 12,461 bytes, 303 lines download raw bytes

1jQuery(function ($) {
2
3  var ajaxUrl = wc_cart_params.ajax_url;
4  var nonce = typeof anchor_cart !== 'undefined' ? anchor_cart.nonce : '';
5
6  // ---------------------------------------------------------------------------
7  // Helpers
8  // ---------------------------------------------------------------------------
9
10  function replaceCart(html) {
11    var $current = $('.cart_wrapper');
12    if ($current.length) {
13      $current.replaceWith(html);
14    } else {
15      // Fallback
16      $('.cart_wrapper').first().html(html);
17    }
18  }
19
20  function updateNotices(html) {
21    $('.cart-notices').html(html);
22  }
23
24  // Always query fresh — overlay is inside .sample-cart-wrapper which gets
25  // replaced when the cart empties, so a cached reference would go stale.
26  function showOverlay() {
27    $('.cart-loading-overlay').css('display', 'flex');
28  }
29
30  function hideOverlay() {
31    $('.cart-loading-overlay').css('display', 'none');
32  }
33
34  /**
35   * Tell WooCommerce to re-fetch all cart fragments (mini-cart count bubble etc.).
36   * WC's cart-fragments.js listens for this event on document.body.
37   */
38  function refreshCartFragments() {
39    $(document.body).trigger('wc_fragment_refresh');
40  }
41
42
43  // ---------------------------------------------------------------------------
44  // REMOVE SINGLE CART ITEM
45  // ---------------------------------------------------------------------------
46
47  var removingKeys = {};
48
49  $('body').on('click', '.cart-remove-item', function (e) {
50    e.preventDefault();
51
52    var $btn = $(this);
53    var cartItemKey = $btn.data('cart-item-key');
54    var $row = $btn.closest('.cart-product-row');
55    var $categoryBlock = $row.closest('.cart-category-block');
56
57    if ($btn.hasClass('removing')) return;
58
59    removingKeys[cartItemKey] = true;
60    $btn.addClass('removing').html('<span class="cart-loader"></span>');
61    $row.addClass('removing');
62
63    $.ajax({
64      type: 'POST',
65      url: ajaxUrl,
66      data: {
67        action: 'woocommerce_remove_cart_item',
68        cart_item_key: cartItemKey,
69        nonce: nonce,
70      },
71
72      success: function (response) {
73        if (!response.success) {
74          delete removingKeys[cartItemKey];
75          $btn.removeClass('removing').html(trashIconSVG());
76          $row.removeClass('removing');
77          return;
78        }
79
80        if (response.data.notices) {
81          updateNotices(response.data.notices);
82        }
83
84        if (response.data.cart) {
85          replaceCart(response.data.cart);
86
87          // WC's cart-fragments.js triggers window.location.reload() when the
88          // cart hash from get_refreshed_fragments differs from the stored hash.
89          // It reads the hash from BOTH sessionStorage AND the woocommerce_cart_hash
90          // cookie. Clearing only sessionStorage (previous attempt) left the cookie
91          // intact → still caused a mismatch → still reloaded.
92          //
93          // Fix: clear both the sessionStorage keys AND the cookie so WC has no
94          // stored baseline. With stored_hash === '', WC's condition
95          // (stored_hash !== '' && new_hash !== stored_hash) evaluates to false
96          // → fragments update silently, no reload.
97
98          if (typeof wc_cart_fragments_params !== 'undefined') {
99            try {
100              sessionStorage.removeItem(wc_cart_fragments_params.cart_hash_key);
101              sessionStorage.removeItem(wc_cart_fragments_params.fragment_name);
102            } catch (e) { }
103          }
104
105          // Clear the cart hash cookie on all possible paths
106          var cookiePath = (typeof wc_cart_fragments_params !== 'undefined' && wc_cart_fragments_params.cookie_hash)
107            ? wc_cart_fragments_params.cookie_hash
108            : '/';
109          document.cookie = 'woocommerce_cart_hash=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=' + cookiePath + ';';
110          document.cookie = 'woocommerce_items_in_cart=0; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=' + cookiePath + ';';
111
112          // NOW it is safe to refresh fragments — WC will write the new empty
113          // hash as a fresh baseline instead of comparing against a stale one.
114          refreshCartFragments();
115
116          delete removingKeys[cartItemKey];
117          return;
118        }
119
120        // Normal case → optimistic row removal
121        refreshCartFragments();
122
123        $row.fadeOut(200, function () {
124          $row.remove();
125          delete removingKeys[cartItemKey];
126
127          var remaining = $categoryBlock.find('.cart-product-row').length;
128          $categoryBlock.find('.item-count-badge').text(remaining + ' Items');
129
130          var totalRemaining = $('.cart-product-row').length;
131          var label = totalRemaining === 1 ? 'Product Added' : 'Products Added';
132          $('.cart-total-count').text(totalRemaining + ' ' + label);
133
134          if (remaining === 0) {
135            $categoryBlock.remove();
136            // No more empty-cart AJAX here — server now handles the last-item case
137          }
138        });
139      },
140
141      error: function () {
142        delete removingKeys[cartItemKey];
143        $btn.removeClass('removing').html(trashIconSVG());
144        $row.removeClass('removing');
145      },
146    });
147  });
148
149
150  // ---------------------------------------------------------------------------
151  // RESTORE SINGLE ITEM (Undo remove)
152  // ---------------------------------------------------------------------------
153
154  $('body').on('click', '.anchor-restore-item', function (e) {
155    e.preventDefault();
156
157    var cartItemKey = $(this).data('cart-item-key');
158    var $link = $(this);
159
160    if ($link.hasClass('processing') || removingKeys[cartItemKey]) return;
161
162    $link.addClass('processing').html('Restoring… <span class="cart-loader"></span>');
163    showOverlay();
164
165    $.ajax({
166      type: 'POST',
167      url: ajaxUrl,
168      data: {
169        action: 'anchor_restore_cart_item',
170        cart_item_key: cartItemKey,
171        nonce: nonce,
172      },
173
174      success: function (response) {
175        if (response.success && response.data.cart) {
176          replaceCart(response.data.cart);
177        }
178        if (response.success && response.data.notices) {
179          updateNotices(response.data.notices);
180        }
181
182        // Give the DOM a tiny moment to settle before letting fragments run
183        setTimeout(function () {
184          refreshCartFragments();
185        }, 100);
186      },
187
188      error: function () {
189        $link.removeClass('processing').html('Undo?');
190      },
191
192      complete: function () {
193        hideOverlay();
194        $link.removeClass('processing');
195      },
196    });
197  });
198
199
200  // ---------------------------------------------------------------------------
201  // OPEN EMPTY CART MODAL
202  // ---------------------------------------------------------------------------
203
204  $('body').on('click', '.empty-cart-btn', function (e) {
205    e.preventDefault();
206    var modal = new bootstrap.Modal(document.getElementById('emptyCartModal'));
207    modal.show();
208  });
209
210
211  // ---------------------------------------------------------------------------
212  // CONFIRM EMPTY CART
213  // ---------------------------------------------------------------------------
214
215  $('body').on('click', '.confirm-empty-cart', function () {
216
217    var $btn = $(this);
218    var modalEl = document.getElementById('emptyCartModal');
219    var modal = bootstrap.Modal.getInstance(modalEl);
220
221    if ($btn.hasClass('processing')) return;
222
223    $btn.addClass('processing').text('Emptying…').prop('disabled', true);
224    showOverlay();
225
226    $.ajax({
227      type: 'POST',
228      url: ajaxUrl,
229      data: { action: 'anchor_empty_cart', nonce: nonce },
230
231      success: function (response) {
232        modal.hide();
233
234        if (response.success && response.data.cart) {
235          replaceCart(response.data.cart);
236        }
237        if (response.success && response.data.notices) {
238          updateNotices(response.data.notices);
239        }
240        refreshCartFragments();
241      },
242
243      complete: function () {
244        $btn.removeClass('processing').text('Empty Cart').prop('disabled', false);
245        hideOverlay();
246      },
247    });
248  });
249
250
251  // ---------------------------------------------------------------------------
252  // UNDO EMPTY CART
253  //
254  // The .cart-loading-overlay element does not exist in cart-empty.php, so we
255  // cannot show the full-page overlay here. Instead we give inline feedback by
256  // turning the "Undo?" link itself into a micro-spinner.
257  // ---------------------------------------------------------------------------
258
259  $('body').on('click', '.undo-empty-cart', function (e) {
260    e.preventDefault();
261
262    var $link = $(this);
263
264    if ($link.hasClass('processing')) return;
265    $link.addClass('processing').html('Restoring… <span class="cart-loader"></span>');
266
267    $.ajax({
268      type: 'POST',
269      url: ajaxUrl,
270      data: { action: 'anchor_restore_cleared_cart', nonce: nonce },
271
272      success: function (response) {
273        if (response.success && response.data.cart) {
274          replaceCart(response.data.cart);
275        }
276        if (response.success && response.data.notices) {
277          updateNotices(response.data.notices);
278        }
279        refreshCartFragments();
280      },
281
282      error: function () {
283        // Restore the link text so the user can try again.
284        $link.removeClass('processing').html('Undo?');
285      },
286    });
287  });
288
289
290  // ---------------------------------------------------------------------------
291  // Utility: trash icon SVG (restores remove button after AJAX error)
292  // ---------------------------------------------------------------------------
293
294  function trashIconSVG() {
295    return '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="24" viewBox="0 0 20 24" fill="none" aria-hidden="true">'
296      + '<path d="M15.7261 10.0234C15.5152 10.0234 15.3129 10.1072 15.1637 10.2564C15.0145 10.4056 14.9307 10.6079 14.9307 10.8189V19.7203C14.9079 20.1226 14.7271 20.4995 14.4276 20.769C14.1282 21.0385 13.7343 21.1788 13.3319 21.1592H6.98453C6.58213 21.1788 6.18831 21.0385 5.88885 20.769C5.5894 20.4995 5.40857 20.1226 5.38575 19.7203V10.8189C5.38575 10.6079 5.30195 10.4056 5.15278 10.2564C5.00361 10.1072 4.80129 10.0234 4.59034 10.0234C4.37938 10.0234 4.17706 10.1072 4.02789 10.2564C3.87872 10.4056 3.79492 10.6079 3.79492 10.8189V19.7203C3.81763 20.5446 4.16605 21.3262 4.76388 21.8941C5.36171 22.4619 6.16022 22.7697 6.98453 22.7501H13.3319C14.1562 22.7697 14.9548 22.4619 15.5526 21.8941C16.1504 21.3262 16.4988 20.5446 16.5215 19.7203V10.8189C16.5215 10.6079 16.4377 10.4056 16.2886 10.2564C16.1394 10.1072 15.9371 10.0234 15.7261 10.0234Z" fill="#014A8D"/>'
297      + '<path d="M16.522 7.6382H13.3404V6.04737C13.3404 5.83641 13.2566 5.63409 13.1074 5.48492C12.9582 5.33576 12.7559 5.25195 12.545 5.25195H7.77248C7.56153 5.25195 7.35921 5.33576 7.21004 5.48492C7.06087 5.63409 6.97707 5.83641 6.97707 6.04737V7.6382H3.79541C3.58446 7.6382 3.38214 7.722 3.23297 7.87117C3.0838 8.02034 3 8.22265 3 8.43361C3 8.64457 3.0838 8.84688 3.23297 8.99605C3.38214 9.14522 3.58446 9.22902 3.79541 9.22902H16.522C16.733 9.22902 16.9353 9.14522 17.0845 8.99605C17.2337 8.84688 17.3175 8.64457 17.3175 8.43361C17.3175 8.22265 17.2337 8.02034 17.0845 7.87117C16.9353 7.722 16.733 7.6382 16.522 7.6382ZM8.5679 7.6382V6.84278H11.7496V7.6382H8.5679Z" fill="#014A8D"/>'
298      + '<path d="M9.36231 17.9766V12.4087C9.36231 12.1977 9.27851 11.9954 9.12934 11.8463C8.98017 11.6971 8.77786 11.6133 8.5669 11.6133C8.35594 11.6133 8.15363 11.6971 8.00446 11.8463C7.85529 11.9954 7.77148 12.1977 7.77148 12.4087V17.9766C7.77148 18.1876 7.85529 18.3899 8.00446 18.539C8.15363 18.6882 8.35594 18.772 8.5669 18.772C8.77786 18.772 8.98017 18.6882 9.12934 18.539C9.27851 18.3899 9.36231 18.1876 9.36231 17.9766Z" fill="#014A8D"/>'
299      + '<path d="M12.5459 17.9766V12.4087C12.5459 12.1977 12.4621 11.9954 12.3129 11.8463C12.1638 11.6971 11.9614 11.6133 11.7505 11.6133C11.5395 11.6133 11.3372 11.6971 11.188 11.8463C11.0389 11.9954 10.9551 12.1977 10.9551 12.4087V17.9766C10.9551 18.1876 11.0389 18.3899 11.188 18.539C11.3372 18.6882 11.5395 18.772 11.7505 18.772C11.9614 18.772 12.1638 18.6882 12.3129 18.539C12.4621 18.3899 12.5459 18.1876 12.5459 17.9766Z" fill="#014A8D"/>'
300      + '</svg>';
301  }
302
303});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.