PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 7.6.0-beta.1
WooCommerce v7.6.0-beta.1
10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / assets / js / frontend / cart.js
woocommerce / assets / js / frontend Last commit date
add-payment-method.js 3 years ago add-payment-method.min.js 3 years ago add-to-cart-variation.js 3 years ago add-to-cart-variation.min.js 3 years ago add-to-cart.js 3 years ago add-to-cart.min.js 3 years ago address-i18n.js 5 years ago address-i18n.min.js 3 years ago cart-fragments.js 3 years ago cart-fragments.min.js 3 years ago cart.js 3 years ago cart.min.js 3 years ago checkout.js 3 years ago checkout.min.js 3 years ago country-select.js 5 years ago country-select.min.js 3 years ago credit-card-form.js 8 years ago credit-card-form.min.js 8 years ago geolocation.js 3 years ago geolocation.min.js 3 years ago lost-password.js 8 years ago lost-password.min.js 8 years ago password-strength-meter.js 4 years ago password-strength-meter.min.js 3 years ago price-slider.js 5 years ago price-slider.min.js 3 years ago single-product.js 4 years ago single-product.min.js 3 years ago tokenization-form.js 5 years ago tokenization-form.min.js 5 years ago woocommerce.js 5 years ago woocommerce.min.js 5 years ago
cart.js
646 lines
1 /* global wc_cart_params */
2 jQuery( function( $ ) {
3
4 // wc_cart_params is required to continue, ensure the object exists
5 if ( typeof wc_cart_params === 'undefined' ) {
6 return false;
7 }
8
9 // Utility functions for the file.
10
11 /**
12 * Perform an AJAX request that expects an HTML response.
13 *
14 * @param {Object} options
15 */
16 const ajax = options => {
17 window.fetch( options.url, {
18 method: options.type || 'GET',
19 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
20 body: options.data
21 } )
22 .then( response => {
23 if ( !response.ok ) {
24 throw new Error( response.statusText );
25 }
26 return response.text();
27 } )
28 .then( options.success )
29 .finally( () => options.complete() );
30 };
31
32 /**
33 * Gets a url for a given AJAX endpoint.
34 *
35 * @param {String} endpoint The AJAX Endpoint
36 * @return {String} The URL to use for the request
37 */
38 var get_url = function( endpoint ) {
39 return wc_cart_params.wc_ajax_url.toString().replace(
40 '%%endpoint%%',
41 endpoint
42 );
43 };
44
45 /**
46 * Check if a node is blocked for processing.
47 *
48 * @param {JQuery Object} $node
49 * @return {bool} True if the DOM Element is UI Blocked, false if not.
50 */
51 var is_blocked = function( $node ) {
52 return $node.is( '.processing' ) || $node.parents( '.processing' ).length;
53 };
54
55 /**
56 * Block a node visually for processing.
57 *
58 * @param {JQuery Object} $node
59 */
60 var block = function( $node ) {
61 if ( ! is_blocked( $node ) ) {
62 $node.addClass( 'processing' ).block( {
63 message: null,
64 overlayCSS: {
65 background: '#fff',
66 opacity: 0.6
67 }
68 } );
69 }
70 };
71
72 /**
73 * Unblock a node after processing is complete.
74 *
75 * @param {JQuery Object} $node
76 */
77 var unblock = function( $node ) {
78 $node.removeClass( 'processing' ).unblock();
79 };
80
81 /**
82 * Removes duplicate notices.
83 *
84 * @param {JQuery Object} notices
85 */
86 var remove_duplicate_notices = function( notices ) {
87 var seen = [];
88 var new_notices = notices;
89
90 notices.each( function( index ) {
91 var text = $( this ).text();
92
93 if ( 'undefined' === typeof seen[ text ] ) {
94 seen[ text ] = true;
95 } else {
96 new_notices.splice( index, 1 );
97 }
98 } );
99
100 return new_notices;
101 };
102
103 /**
104 * Update the .woocommerce div with a string of html.
105 *
106 * @param {String} html_str The HTML string with which to replace the div.
107 * @param {bool} preserve_notices Should notices be kept? False by default.
108 */
109 var update_wc_div = function( html_str, preserve_notices ) {
110 var $html = $.parseHTML( html_str );
111 var $new_form = $( '.woocommerce-cart-form', $html );
112 var $new_totals = $( '.cart_totals', $html );
113 var $notices = remove_duplicate_notices( $( '.woocommerce-error, .woocommerce-message, .woocommerce-info', $html ) );
114
115 // No form, cannot do this.
116 if ( $( '.woocommerce-cart-form' ).length === 0 ) {
117 window.location.reload();
118 return;
119 }
120
121 // Remove errors
122 if ( ! preserve_notices ) {
123 $( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
124 }
125
126 if ( $new_form.length === 0 ) {
127 // If the checkout is also displayed on this page, trigger reload instead.
128 if ( $( '.woocommerce-checkout' ).length ) {
129 window.location.reload();
130 return;
131 }
132
133 // No items to display now! Replace all cart content.
134 var $cart_html = $( '.cart-empty', $html ).closest( '.woocommerce' );
135 $( '.woocommerce-cart-form__contents' ).closest( '.woocommerce' ).replaceWith( $cart_html );
136
137 // Display errors
138 if ( $notices.length > 0 ) {
139 show_notice( $notices );
140 }
141
142 // Notify plugins that the cart was emptied.
143 $( document.body ).trigger( 'wc_cart_emptied' );
144 } else {
145 // If the checkout is also displayed on this page, trigger update event.
146 if ( $( '.woocommerce-checkout' ).length ) {
147 $( document.body ).trigger( 'update_checkout' );
148 }
149
150 $( '.woocommerce-cart-form' ).replaceWith( $new_form );
151 $( '.woocommerce-cart-form' ).find( ':input[name="update_cart"]' ).prop( 'disabled', true ).attr( 'aria-disabled', true );
152
153 if ( $notices.length > 0 ) {
154 show_notice( $notices );
155 }
156
157 update_cart_totals_div( $new_totals );
158 }
159
160 $( document.body ).trigger( 'updated_wc_div' );
161 };
162
163 /**
164 * Update the .cart_totals div with a string of html.
165 *
166 * @param {String} html_str The HTML string with which to replace the div.
167 */
168 var update_cart_totals_div = function( html_str ) {
169 $( '.cart_totals' ).replaceWith( html_str );
170 $( document.body ).trigger( 'updated_cart_totals' );
171 };
172
173 /**
174 * Shows new notices on the page.
175 *
176 * @param {Object} The Notice HTML Element in string or object form.
177 */
178 var show_notice = function( html_element, $target ) {
179 if ( ! $target ) {
180 $target = $( '.woocommerce-notices-wrapper:first' ) ||
181 $( '.cart-empty' ).closest( '.woocommerce' ) ||
182 $( '.woocommerce-cart-form' );
183 }
184 $target.prepend( html_element );
185 };
186
187
188 /**
189 * Object to handle AJAX calls for cart shipping changes.
190 */
191 var cart_shipping = {
192
193 /**
194 * Initialize event handlers and UI state.
195 */
196 init: function( cart ) {
197 this.cart = cart;
198 this.toggle_shipping = this.toggle_shipping.bind( this );
199 this.shipping_method_selected = this.shipping_method_selected.bind( this );
200 this.shipping_calculator_submit = this.shipping_calculator_submit.bind( this );
201
202 $( document ).on(
203 'click',
204 '.shipping-calculator-button',
205 this.toggle_shipping
206 );
207 $( document ).on(
208 'change',
209 'select.shipping_method, :input[name^=shipping_method]',
210 this.shipping_method_selected
211 );
212 $( document ).on(
213 'submit',
214 'form.woocommerce-shipping-calculator',
215 this.shipping_calculator_submit
216 );
217
218 $( '.shipping-calculator-form' ).hide();
219 },
220
221 /**
222 * Toggle Shipping Calculator panel
223 */
224 toggle_shipping: function() {
225 $( '.shipping-calculator-form' ).slideToggle( 'slow' );
226 $( 'select.country_to_state, input.country_to_state' ).trigger( 'change' );
227 $( document.body ).trigger( 'country_to_state_changed' ); // Trigger select2 to load.
228 return false;
229 },
230
231 /**
232 * Handles when a shipping method is selected.
233 */
234 shipping_method_selected: function() {
235 var shipping_methods = {};
236
237 // eslint-disable-next-line max-len
238 $( 'select.shipping_method, :input[name^=shipping_method][type=radio]:checked, :input[name^=shipping_method][type=hidden]' ).each( function() {
239 shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();
240 } );
241
242 block( $( 'div.cart_totals' ) );
243
244 var data = {
245 security: wc_cart_params.update_shipping_method_nonce,
246 };
247
248 // Flatten shipping_methods for use in URLSearchParams()
249 for ( var k in shipping_methods ) {
250 data[ 'shipping_method[' + k + ']' ] = shipping_methods[ k ];
251 }
252
253 ajax( {
254 type: 'post',
255 url: get_url( 'update_shipping_method' ),
256 data: new URLSearchParams( data ).toString(),
257 dataType: 'html',
258 success: function( response ) {
259 update_cart_totals_div( response );
260 },
261 complete: function() {
262 unblock( $( 'div.cart_totals' ) );
263 $( document.body ).trigger( 'updated_shipping_method' );
264 }
265 } );
266 },
267
268 /**
269 * Handles a shipping calculator form submit.
270 *
271 * @param {Object} evt The JQuery event.
272 */
273 shipping_calculator_submit: function( evt ) {
274 evt.preventDefault();
275
276 var $form = $( evt.currentTarget );
277
278 block( $( 'div.cart_totals' ) );
279 block( $form );
280
281 // Provide the submit button value because wc-form-handler expects it.
282 $( '<input />' ).attr( 'type', 'hidden' )
283 .attr( 'name', 'calc_shipping' )
284 .attr( 'value', 'x' )
285 .appendTo( $form );
286
287 // Make call to actual form post URL.
288 ajax( {
289 type: $form.attr( 'method' ),
290 url: $form.attr( 'action' ),
291 data: new URLSearchParams( new FormData( $form[0] ) ).toString(),
292 dataType: 'html',
293 success: function( response ) {
294 update_wc_div( response );
295 },
296 complete: function() {
297 unblock( $form );
298 unblock( $( 'div.cart_totals' ) );
299 }
300 } );
301 }
302 };
303
304 /**
305 * Object to handle cart UI.
306 */
307 var cart = {
308 /**
309 * Initialize cart UI events.
310 */
311 init: function() {
312 this.update_cart_totals = this.update_cart_totals.bind( this );
313 this.input_keypress = this.input_keypress.bind( this );
314 this.cart_submit = this.cart_submit.bind( this );
315 this.submit_click = this.submit_click.bind( this );
316 this.apply_coupon = this.apply_coupon.bind( this );
317 this.remove_coupon_clicked = this.remove_coupon_clicked.bind( this );
318 this.quantity_update = this.quantity_update.bind( this );
319 this.item_remove_clicked = this.item_remove_clicked.bind( this );
320 this.item_restore_clicked = this.item_restore_clicked.bind( this );
321 this.update_cart = this.update_cart.bind( this );
322
323 $( document ).on(
324 'wc_update_cart added_to_cart',
325 function() { cart.update_cart.apply( cart, [].slice.call( arguments, 1 ) ); } );
326 $( document ).on(
327 'click',
328 '.woocommerce-cart-form :input[type=submit]',
329 this.submit_click );
330 $( document ).on(
331 'keypress',
332 '.woocommerce-cart-form :input[type=number]',
333 this.input_keypress );
334 $( document ).on(
335 'submit',
336 '.woocommerce-cart-form',
337 this.cart_submit );
338 $( document ).on(
339 'click',
340 'a.woocommerce-remove-coupon',
341 this.remove_coupon_clicked );
342 $( document ).on(
343 'click',
344 '.woocommerce-cart-form .product-remove > a',
345 this.item_remove_clicked );
346 $( document ).on(
347 'click',
348 '.woocommerce-cart .restore-item',
349 this.item_restore_clicked );
350 $( document ).on(
351 'change input',
352 '.woocommerce-cart-form .cart_item :input',
353 this.input_changed );
354
355 $( '.woocommerce-cart-form :input[name="update_cart"]' ).prop( 'disabled', true ).attr( 'aria-disabled', true );
356 },
357
358 /**
359 * After an input is changed, enable the update cart button.
360 */
361 input_changed: function() {
362 $( '.woocommerce-cart-form :input[name="update_cart"]' ).prop( 'disabled', false ).attr( 'aria-disabled', false );
363 },
364
365 /**
366 * Update entire cart via ajax.
367 */
368 update_cart: function( preserve_notices ) {
369 var $form = $( '.woocommerce-cart-form' );
370
371 block( $form );
372 block( $( 'div.cart_totals' ) );
373
374 // Make call to actual form post URL.
375 ajax( {
376 type: $form.attr( 'method' ),
377 url: $form.attr( 'action' ),
378 data: new URLSearchParams( new FormData( $form[0] ) ).toString(),
379 dataType: 'html',
380 success: function( response ) {
381 update_wc_div( response, preserve_notices );
382 },
383 complete: function() {
384 unblock( $form );
385 unblock( $( 'div.cart_totals' ) );
386 $.scroll_to_notices( $( '[role="alert"]' ) );
387 }
388 } );
389 },
390
391 /**
392 * Update the cart after something has changed.
393 */
394 update_cart_totals: function() {
395 block( $( 'div.cart_totals' ) );
396
397 ajax( {
398 url: get_url( 'get_cart_totals' ),
399 dataType: 'html',
400 success: function( response ) {
401 update_cart_totals_div( response );
402 },
403 complete: function() {
404 unblock( $( 'div.cart_totals' ) );
405 }
406 } );
407 },
408
409 /**
410 * Handle the <ENTER> key for quantity fields.
411 *
412 * @param {Object} evt The JQuery event
413 *
414 * For IE, if you hit enter on a quantity field, it makes the
415 * document.activeElement the first submit button it finds.
416 * For us, that is the Apply Coupon button. This is required
417 * to catch the event before that happens.
418 */
419 input_keypress: function( evt ) {
420
421 // Catch the enter key and don't let it submit the form.
422 if ( 13 === evt.keyCode ) {
423 var $form = $( evt.currentTarget ).parents( 'form' );
424
425 try {
426 // If there are no validation errors, handle the submit.
427 if ( $form[0].checkValidity() ) {
428 evt.preventDefault();
429 this.cart_submit( evt );
430 }
431 } catch( err ) {
432 evt.preventDefault();
433 this.cart_submit( evt );
434 }
435 }
436 },
437
438 /**
439 * Handle cart form submit and route to correct logic.
440 *
441 * @param {Object} evt The JQuery event
442 */
443 cart_submit: function( evt ) {
444 var $submit = $( document.activeElement ),
445 $clicked = $( ':input[type=submit][clicked=true]' ),
446 $form = $( evt.currentTarget );
447
448 // For submit events, currentTarget is form.
449 // For keypress events, currentTarget is input.
450 if ( ! $form.is( 'form' ) ) {
451 $form = $( evt.currentTarget ).parents( 'form' );
452 }
453
454 if ( 0 === $form.find( '.woocommerce-cart-form__contents' ).length ) {
455 return;
456 }
457
458 if ( is_blocked( $form ) ) {
459 return false;
460 }
461
462 if ( $clicked.is( ':input[name="update_cart"]' ) || $submit.is( 'input.qty' ) ) {
463 evt.preventDefault();
464 this.quantity_update( $form );
465
466 } else if ( $clicked.is( ':input[name="apply_coupon"]' ) || $submit.is( '#coupon_code' ) ) {
467 evt.preventDefault();
468 this.apply_coupon( $form );
469 }
470 },
471
472 /**
473 * Special handling to identify which submit button was clicked.
474 *
475 * @param {Object} evt The JQuery event
476 */
477 submit_click: function( evt ) {
478 $( ':input[type=submit]', $( evt.target ).parents( 'form' ) ).removeAttr( 'clicked' );
479 $( evt.target ).attr( 'clicked', 'true' );
480 },
481
482 /**
483 * Apply Coupon code
484 *
485 * @param {JQuery Object} $form The cart form.
486 */
487 apply_coupon: function( $form ) {
488 block( $form );
489
490 var cart = this;
491 var $text_field = $( '#coupon_code' );
492 var coupon_code = $text_field.val();
493
494 var data = {
495 security: wc_cart_params.apply_coupon_nonce,
496 coupon_code: coupon_code
497 };
498
499 ajax( {
500 type: 'POST',
501 url: get_url( 'apply_coupon' ),
502 data: new URLSearchParams( data ).toString(),
503 dataType: 'html',
504 success: function( response ) {
505 $( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
506 show_notice( response );
507 $( document.body ).trigger( 'applied_coupon', [ coupon_code ] );
508 },
509 complete: function() {
510 unblock( $form );
511 $text_field.val( '' );
512 cart.update_cart( true );
513 }
514 } );
515 },
516
517 /**
518 * Handle when a remove coupon link is clicked.
519 *
520 * @param {Object} evt The JQuery event
521 */
522 remove_coupon_clicked: function( evt ) {
523 evt.preventDefault();
524
525 var cart = this;
526 var $wrapper = $( evt.currentTarget ).closest( '.cart_totals' );
527 var coupon = $( evt.currentTarget ).attr( 'data-coupon' );
528
529 block( $wrapper );
530
531 var data = {
532 security: wc_cart_params.remove_coupon_nonce,
533 coupon: coupon
534 };
535
536 ajax( {
537 type: 'POST',
538 url: get_url( 'remove_coupon' ),
539 data: new URLSearchParams( data ).toString(),
540 dataType: 'html',
541 success: function( response ) {
542 $( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
543 show_notice( response );
544 $( document.body ).trigger( 'removed_coupon', [ coupon ] );
545 unblock( $wrapper );
546 },
547 complete: function() {
548 cart.update_cart( true );
549 }
550 } );
551 },
552
553 /**
554 * Handle a cart Quantity Update
555 *
556 * @param {JQuery Object} $form The cart form.
557 */
558 quantity_update: function( $form ) {
559 block( $form );
560 block( $( 'div.cart_totals' ) );
561
562 // Provide the submit button value because wc-form-handler expects it.
563 $( '<input />' ).attr( 'type', 'hidden' )
564 .attr( 'name', 'update_cart' )
565 .attr( 'value', 'Update Cart' )
566 .appendTo( $form );
567
568 // Make call to actual form post URL.
569 ajax( {
570 type: $form.attr( 'method' ),
571 url: $form.attr( 'action' ),
572 data: new URLSearchParams( new FormData( $form[0] ) ).toString(),
573 dataType: 'html',
574 success: function( response ) {
575 update_wc_div( response );
576 },
577 complete: function() {
578 unblock( $form );
579 unblock( $( 'div.cart_totals' ) );
580 $.scroll_to_notices( $( '[role="alert"]' ) );
581 }
582 } );
583 },
584
585 /**
586 * Handle when a remove item link is clicked.
587 *
588 * @param {Object} evt The JQuery event
589 */
590 item_remove_clicked: function( evt ) {
591 evt.preventDefault();
592
593 var $a = $( evt.currentTarget );
594 var $form = $a.parents( 'form' );
595
596 block( $form );
597 block( $( 'div.cart_totals' ) );
598
599 ajax( {
600 type: 'GET',
601 url: $a.attr( 'href' ),
602 dataType: 'html',
603 success: function( response ) {
604 update_wc_div( response );
605 },
606 complete: function() {
607 unblock( $form );
608 unblock( $( 'div.cart_totals' ) );
609 $.scroll_to_notices( $( '[role="alert"]' ) );
610 }
611 } );
612 },
613
614 /**
615 * Handle when a restore item link is clicked.
616 *
617 * @param {Object} evt The JQuery event
618 */
619 item_restore_clicked: function( evt ) {
620 evt.preventDefault();
621
622 var $a = $( evt.currentTarget );
623 var $form = $( 'form.woocommerce-cart-form' );
624
625 block( $form );
626 block( $( 'div.cart_totals' ) );
627
628 ajax( {
629 type: 'GET',
630 url: $a.attr( 'href' ),
631 dataType: 'html',
632 success: function( response ) {
633 update_wc_div( response );
634 },
635 complete: function() {
636 unblock( $form );
637 unblock( $( 'div.cart_totals' ) );
638 }
639 } );
640 }
641 };
642
643 cart_shipping.init( cart );
644 cart.init();
645 } );
646