PageSourceSearch

https://www.jacquesflamenteditions.com/wp-content/plugins/wp-express-checkout/assets/js/public.js?ver=2.3.11

js jacquesflamenteditions.com collected 2026-10-02 11:08:10 UTC 24,341 bytes, 660 lines download raw bytes

1var ppecHandler = function( data ) {	
2	this.data = data;
3	this.actions = {};
4
5	var parent = this;
6
7	this.processPayment = function( payment, action ) {
8		jQuery.post( ppecFrontVars.ajaxUrl, {
9				'action': action,
10				wp_ppdg_payment: payment,
11				data: parent.data,
12				nonce: parent.data.nonce
13			} )
14			.done( function( data ) {
15				parent.completePayment( data );
16			} );
17	};
18
19	this.completePayment = function( data ) {
20		var ret = true;
21		var dlgTitle = ppecFrontVars.str.paymentCompleted;
22		var dlgMsg = ppecFrontVars.str.redirectMsg;
23		if ( data.redirect_url ) {
24			var redirect_url = data.redirect_url;
25		} else {
26			dlgTitle = ppecFrontVars.str.errorOccurred;
27			dlgMsg = data;
28			ret = false;
29		}
30		jQuery( '.wp-ppec-overlay[data-ppec-button-id="' + parent.data.id + '"]' ).hide();
31		var dialog = jQuery( '<div id="wp-ppdg-dialog-message" title="' + dlgTitle + '"><p id="wp-ppdg-dialog-msg">' + dlgMsg + '</p></div>' );
32		jQuery( '#' + parent.data.id ).before( dialog ).fadeIn();
33		if ( redirect_url ) {
34			location.href = redirect_url;
35		}
36		return ret;
37	};
38
39	this.ValidatorTos = function( input ) {
40		return input.prop( 'checked' ) !== true ? ppecFrontVars.str.acceptTos : null;
41	};
42
43	this.ValidatorBilling = function( input ) {
44		var val = input.attr( 'type' ) === 'checkbox' ? input.prop( 'checked' ) === true : input.val();
45		return input.is( ':visible' ) && !val ? ppecFrontVars.str.required : null;
46	};
47
48	this.isValidTotal = function() {
49		parent.calcTotal();
50		return !!parent.data.total;
51	};
52
53	this.ValidatorQuantity = function( input ) {
54		var val_orig = input.val();
55		var val = parseInt( val_orig );
56		var error = false;
57		if ( isNaN( val ) || ( val_orig % 1 !== 0 ) || val <= 0 ) {
58			error = ppecFrontVars.str.enterQuantity;
59		} else if ( parent.data.stock_enabled && val > parent.data.stock_items ) {
60			error = ppecFrontVars.str.stockErr.replace( '%d', parent.data.stock_items );
61		} else {
62			parent.data.quantity = val;
63		}
64		return error;
65	};
66
67	this.ValidatorAmount = function( input ) {
68		var val_orig = input.val();
69		var val = parseFloat( val_orig );
70		var min_val = input.attr( 'min' );
71		var error = false;
72		var errMsg = ppecFrontVars.str.enterAmount;
73		if ( !isNaN( val ) && min_val <= val ) {
74			parent.data.orig_price = val;
75			parent.data.price = parent.applyVariations( val );
76		} else {
77			error = errMsg;
78		}
79		return error;
80	};
81
82	if ( this.data.btnStyle.layout === 'horizontal' ) {
83		this.data.btnStyle.tagline = false;
84	}
85
86	this.clientVars = {};
87
88	this.clientVars[ this.data.env ] = this.data.client_id;
89
90	this.inputs = [];
91
92	this.validateInput = function( input, validator ) {
93		if ( 1 > input.length ) {
94			return false;
95		}
96
97		this.inputs.push( [ input, validator ] );
98
99		input.change( function() {
100			parent.displayInputError( jQuery( this ), validator );
101			parent.validateOrder();
102		} );
103	};
104
105	this.validateOrder = function() {
106		var enable_actions = true;
107
108		jQuery( '#wpec_billing_' + parent.data.id + ', #place-order-' + parent.data.id ).toggle( !parent.isValidTotal() );
109		jQuery( '#' + parent.data.id ).toggle( !jQuery( '#place-order-' + parent.data.id ).is( ':visible' ) );
110
111		parent.inputs.forEach( function( inputArr ) {
112			var input = inputArr[ 0 ];
113			var validator = inputArr[ 1 ];
114			if ( validator( input ) ) {
115				enable_actions = false;
116			}
117		} );
118
119		if ( !parent.isValidTotal() ) {
120			enable_actions = false;
121		}
122
123		if ( enable_actions ) {
124			parent.actions.enable();
125		} else {
126			parent.actions.disable();
127		}
128
129		parent.updateAllAmounts();
130		jQuery( document ).trigger( 'wpec_validate_order', [ parent ] );
131	};
132
133	this.displayInputError = function( input, validator ) {
134		var error = validator( input );
135		var errMsgCont = input.is( ':checkbox' ) || input.attr( 'type' ) === 'number' ? input.parent().siblings( '.wp-ppec-form-error-msg' ) : input.siblings( '.wp-ppec-form-error-msg' );
136		input.toggleClass( 'hasError', !!error );
137		errMsgCont.html( error );
138		if ( error && errMsgCont.length ) {
139			errMsgCont.fadeIn( 'slow' );
140		} else {
141			errMsgCont.fadeOut( 'fast' );
142		}
143	};
144
145	this.displayErrors = function() {
146		parent.inputs.forEach( function( input ) {
147			parent.displayInputError( input[ 0 ], input[ 1 ] );
148		} );
149	};
150
151	this.scCont = jQuery( '.wp-ppec-shortcode-container[data-ppec-button-id="' + parent.data.id + '"]' );
152
153	this.buttonArgs = {
154		env: parent.data.env,
155		client: parent.clientVars,
156		style: parent.data.btnStyle,
157		commit: true,
158		onInit: function( data, actions ) {
159			parent.actions = actions;
160			parent.validateInput( jQuery( '#wpec-tos-' + parent.data.id ), parent.ValidatorTos );
161			parent.validateInput( jQuery( '#wp-ppec-custom-quantity[data-ppec-button-id="' + parent.data.id + '"]' ), parent.ValidatorQuantity );
162			parent.validateInput( jQuery( '#wp-ppec-custom-amount[data-ppec-button-id="' + parent.data.id + '"]' ), parent.ValidatorAmount );
163			jQuery( '#wpec_billing_' + parent.data.id + ' .wpec_required' ).each( function() {
164				parent.validateInput( jQuery( this ), parent.ValidatorBilling );
165			} );
166			parent.data.orig_price = parseFloat( parent.data.price );
167			parent.scCont.find( 'select.wpec-product-variations-select, input.wpec-product-variations-select-radio' ).change( function() {
168				var grpId = jQuery( this ).data( 'wpec-variations-group-id' );
169				var varId = jQuery( this ).val();
170				if ( Object.getOwnPropertyNames( parent.data.variations ).length !== 0 ) {
171					if ( !parent.data.variations.applied ) {
172						parent.data.variations.applied = [];
173					}
174					parent.data.variations.applied[ grpId ] = varId;
175					parent.data.price = parent.applyVariations( parent.data.orig_price );
176					parent.validateOrder();
177				}
178			} );
179			parent.scCont.find( 'select.wpec-product-variations-select, input.wpec-product-variations-select-radio:checked' ).change();
180
181			parent.scCont.find( '.wpec_product_shipping_enable' ).change( function() {
182				parent.scCont.find( '.wpec_shipping_address_container' ).toggle();
183				parent.scCont.find( '.wpec_address_wrap' ).toggleClass( 'shipping_enabled' );
184			} );
185
186			jQuery( '#place-order-' + parent.data.id ).click( function() {				
187				parent.buttonArgs.onClick();
188			} );
189
190			jQuery( '#wpec-redeem-coupon-btn-' + parent.data.id ).click( function( e ) {
191				e.preventDefault();
192				var couponCode = jQuery( this ).siblings( '#wpec-coupon-field-' + parent.data.id ).val();
193				if ( couponCode === '' ) {
194					return false;
195				}
196				var wpecCouponBtn = jQuery( this );
197				var wpecCouponSpinner = wpecCouponBtn.find( 'svg' );
198				wpecCouponBtn.prop( 'disabled', true );
199				wpecCouponSpinner.show();
200				var ajaxData = {
201					'action': 'wpec_check_coupon',
202					'product_id': parent.data.product_id,
203					'coupon_code': couponCode,
204					'curr': parent.data.currency,
205					/*'amount': parent.data.item_price,
206					'tax': parent.data.tax,
207					'shipping': parent.data.shipping*/
208				};
209				jQuery.post( ppecFrontVars.ajaxUrl, ajaxData, function( response ) {
210					if ( response.success ) {
211						parent.data.discount = response.discount;
212						parent.data.discountType = response.discountType;
213						parent.data.couponCode = response.code;
214
215						jQuery( '#wpec-coupon-info-' + parent.data.id ).html( '<span class="wpec_coupon_code">' + response.discountStr + '</span> <button class="wpec_coupon_apply_btn" id="wpec-remove-coupon-' + parent.data.id + '" title="' + ppecFrontVars.str.strRemoveCoupon + '">' + ppecFrontVars.str.strRemove + '</button>' );
216						jQuery( '#wpec-redeem-coupon-btn-' + parent.data.id ).hide();
217						jQuery( '#wpec-coupon-field-' + parent.data.id ).hide();
218						var totalCont = parent.getPriceContainer();
219						var totCurr;
220						var totNew;
221						var priceCurr;
222						var priceNew;
223						if ( totalCont.find( '.wpec_price_full_total' ).length !== 0 ) {
224							totCurr = totalCont.children().find( 'span.wpec_tot_current_price' ).addClass( 'wpec_line_through' );
225							totNew = totalCont.children().find( 'span.wpec_tot_new_price' );
226						} else {
227							totCurr = totalCont.find( 'span.wpec_price_amount' ).addClass( 'wpec_line_through' );
228							totNew = totalCont.find( 'span.wpec_new_price_amount' );
229						}
230						priceCurr = totalCont.find( 'span.wpec-price-amount' ).addClass( 'wpec_line_through' );
231						priceNew = totalCont.find( 'span.wpec-new-price-amount' );
232						parent.validateOrder();
233						jQuery( '#wpec-remove-coupon-' + parent.data.id ).on( 'click', function( e ) {
234							e.preventDefault();
235							jQuery( '#wpec-coupon-info-' + parent.data.id ).html( '' );
236							jQuery( '#wpec-coupon-field-' + parent.data.id ).val( '' );
237							jQuery( '#wpec-coupon-field-' + parent.data.id ).show();
238							jQuery( '#wpec-redeem-coupon-btn-' + parent.data.id ).show();
239							totCurr.removeClass( 'wpec_line_through' );
240							priceCurr.removeClass( 'wpec_line_through' );
241							totNew.html( '' );
242							priceNew.html( '' );
243							delete parent.data.discount;
244							delete parent.data.discountType;
245							delete parent.data.couponCode;
246							delete parent.data.discountAmount;
247							delete parent.data.newPrice;
248							parent.validateOrder();
249						} );
250					} else {
251						jQuery( '#wpec-coupon-info-' + parent.data.id ).html( response.msg );
252					}
253					wpecCouponSpinner.hide();
254					wpecCouponBtn.prop( 'disabled', false );
255				} );
256			} );
257
258			jQuery( '#wpec-coupon-field-' + parent.data.id ).keydown( function( e ) {
259				if ( e.keyCode === 13 ) {
260					e.preventDefault();
261					jQuery( '#wpec-redeem-coupon-btn-' + parent.data.id ).click();
262					return false;
263				}
264			} );
265
266			parent.validateOrder();
267
268			if ( parent.data.errors ) {
269				var errorEl = jQuery( '<div class="wp-ppec-form-error-msg">' + parent.data.errors + '</div>' );
270				parent.scCont.append( errorEl );
271				errorEl.show();
272			}
273
274			jQuery( '.wpec-button-placeholder' ).remove();
275		},
276		onClick: function() {
277			jQuery("#place-order-"+parent.data.id).find("button>svg").show();
278			jQuery("#place-order-"+parent.data.id).find("button").attr("disabled",true);
279			
280			parent.displayErrors();
281			var errInput = parent.scCont.find( '.hasError' ).first();
282			if ( errInput.length > 0 ) {
283
284				
285				errInput.focus();
286				errInput.trigger( 'change' );
287
288				jQuery("#place-order-"+parent.data.id).find("button>svg").hide();
289				jQuery("#place-order-"+parent.data.id).find("button").attr("disabled",false);
290			} else if ( !parent.data.total ) {
291			
292				parent.processPayment( {
293					payer: {
294						name: {
295							given_name: jQuery( '#wpec_billing_first_name-' + parent.data.id ).val(),
296							surname: jQuery( '#wpec_billing_last_name-' + parent.data.id ).val()
297						},
298						email_address: jQuery( '#wpec_billing_email-' + parent.data.id ).val(),
299						address: {
300							address_line_1: jQuery( '#wpec_billing_address-' + parent.data.id ).val(),
301							admin_area_1: jQuery( '#wpec_billing_state-' + parent.data.id ).val(),
302							admin_area_2: jQuery( '#wpec_billing_city-' + parent.data.id ).val(),
303							postal_code: jQuery( '#wpec_billing_postal_code-' + parent.data.id ).val(),
304							country_code: jQuery( '#wpec_billing_country-' + parent.data.id ).val()
305						},
306						shipping_address: {
307							address_line_1: jQuery( '#wpec_shipping_address-' + parent.data.id ).val(),
308							admin_area_1: jQuery( '#wpec_shipping_state-' + parent.data.id ).val(),
309							admin_area_2: jQuery( '#wpec_shipping_city-' + parent.data.id ).val(),
310							postal_code: jQuery( '#wpec_shipping_postal_code-' + parent.data.id ).val(),
311							country_code: jQuery( '#wpec_shipping_country-' + parent.data.id ).val()
312						}
313					}
314				}, 'wpec_process_empty_payment' );
315			}
316		},
317		createOrder: async function( data, actions ) {
318			parent.calcTotal();
319
320			//We need to round to 2 decimal places to make sure that the API call will not fail.
321			let itemTotalValueRounded = (parent.data.price * parent.data.quantity).toFixed(2);
322			let itemTotalValueRoundedAsNumber = parseFloat(itemTotalValueRounded);
323			//console.log('Item total value rounded: ' + itemTotalValueRoundedAsNumber);
324			//console.log(parent.data);
325
326			// Checking if shipping will be required
327			let shipping_pref = 'NO_SHIPPING'; // Default value
328			if (parent.data.shipping !== "" || parent.data.shipping_enable === true) {
329				console.log("The physical product checkbox is enabled or there is shipping value has been configured. Setting the shipping preference to collect shipping.");
330				shipping_pref = 'GET_FROM_FILE';
331			}
332
333			// Create order_data object to be sent to the server.
334			var order_data = {
335				intent: 'CAPTURE',
336				payment_source: {
337					paypal: {
338						experience_context: {
339							payment_method_preference: 'IMMEDIATE_PAYMENT_REQUIRED',
340							shipping_preference: shipping_pref,
341							user_action: 'PAY_NOW',
342						}
343					}
344				},
345				purchase_units: [ {
346					amount: {
347						value: parent.data.total,
348						currency_code: parent.data.currency,
349						breakdown: {
350							item_total: {
351								currency_code: parent.data.currency,
352								value: itemTotalValueRoundedAsNumber
353							}
354						}
355					},
356					items: [ {
357						name: parent.data.name,
358						quantity: parent.data.quantity,
359						unit_amount: {
360							value: parent.data.price,
361							currency_code: parent.data.currency
362						}
363					} ]
364				} ]
365			};
366
367			if ( parent.data.tax ) {
368				order_data.purchase_units[ 0 ].amount.breakdown.tax_total = {
369					currency_code: parent.data.currency,
370					value: parent.PHP_round( parent.data.tax_amount * parent.data.quantity, parent.data.dec_num )
371				};
372				order_data.purchase_units[ 0 ].items[ 0 ].tax = {
373					currency_code: parent.data.currency,
374					value: parent.data.tax_amount
375				};
376			}
377			if ( parent.data.shipping ) {
378				order_data.purchase_units[ 0 ].amount.breakdown.shipping = {
379					currency_code: parent.data.currency,
380					value: parent.getTotalShippingCost(),
381				};
382			}
383			if ( parent.data.discount ) {
384				order_data.purchase_units[ 0 ].amount.breakdown.discount = {
385					currency_code: parent.data.currency,
386					value: parseFloat( parent.data.discountAmount )
387				};
388			}
389			console.log('Order data: ' + JSON.stringify(order_data));
390			//End of create order_data object.
391
392			let nonce = wpec_create_order_vars.nonce;
393
394			let wpec_data_for_create = parent.data;//parent.data is the data object that was passed to the ppecHandler constructor.
395			console.log('WPEC data for create-order: ' + JSON.stringify(wpec_data_for_create));
396
397			let post_data = 'action=wpec_pp_create_order&data=' + encodeURIComponent(JSON.stringify(order_data)) + '&wpec_data=' + encodeURIComponent(JSON.stringify(wpec_data_for_create)) + '&_wpnonce=' + nonce;
398			try {
399				// Using fetch for AJAX request. This is supported in all modern browsers.
400				const response = await fetch( ppecFrontVars.ajaxUrl, {
401					method: "post",
402					headers: {
403						'Content-Type': 'application/x-www-form-urlencoded'
404					},
405					body: post_data
406				});
407
408				const response_data = await response.json();
409
410				if (response_data.order_id) {
411					console.log('Create-order API call to PayPal completed successfully.');
412					return response_data.order_id;
413				} else {
414					const error_message = response_data.err_msg
415					console.error('Error occurred during create-order call to PayPal. ' + error_message);
416					throw new Error(error_message);//This will trigger the alert in the "catch" block below.
417				}
418			} catch (error) {
419				console.error(error.message);
420				alert('Could not initiate PayPal Checkout...\n\n' + error.message);
421			}
422		},
423		onApprove: async function( data, actions ) {
424			jQuery( 'div.wp-ppec-overlay[data-ppec-button-id="' + parent.data.id + '"]' ).css( 'display', 'flex' );
425
426			console.log('Setting up the AJAX request for capture-order call.');
427			
428			// Create the data object to be sent to the server.
429			let pp_bn_data = {};
430			pp_bn_data.order_id = data.orderID;//The orderID is the ID of the order that was created in the createOrder method.
431			let wpec_data = parent.data;//parent.data is the data object that was passed to the ppecHandler constructor.
432			//console.log('WPEC data (JSON): ' + JSON.stringify(wpec_data));
433
434			let nonce = wpec_on_approve_vars.nonce;
435			let post_data = 'action=wpec_pp_capture_order&data=' + encodeURIComponent(JSON.stringify(pp_bn_data)) + '&wpec_data=' + encodeURIComponent(JSON.stringify(wpec_data)) + '&_wpnonce=' + nonce;
436			try {
437				const response = await fetch( ppecFrontVars.ajaxUrl, {
438					method: "post",
439					headers: {
440						'Content-Type': 'application/x-www-form-urlencoded'
441					},
442					body: post_data
443				});
444
445				const response_data = await response.json();
446
447				console.log('Capture-order API call to PayPal completed successfully.');
448
449				// Call the completePayment method to do any redirection or display a message to the user.
450				parent.completePayment(response_data); 
451
452			} catch (error) {
453				console.error(error);
454				alert('PayPal returned an error! Transaction could not be processed. Enable the debug logging feature to get more details...\n\n' + JSON.stringify(error));
455			}
456
457		},
458		onError: function( err ) {
459
460			jQuery("#place-order-"+parent.data.id).find("button>svg").hide();
461			jQuery("#place-order-"+parent.data.id).find("button").attr("disabled",false);
462
463			alert( err );
464		}
465	};
466
467	this.formatMoney = function( n ) {
468	var decimalPlaces = isNaN(decimalPlaces = Math.abs(parent.data.dec_num)) ? 2 : parent.data.dec_num;
469    var decimalSeparator = parent.data.dec_sep || ".";
470    var thousandSeparator = parent.data.thousand_sep || ",";
471    var sign = n < 0 ? "-" : "";
472    var integerPart = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(decimalPlaces)));
473    var integerPartLength = integerPart.length;
474    var remainderLength = integerPartLength > 3 ? integerPartLength % 3 : 0;
475
476    var formattedIntegerPart = sign +
477        (remainderLength ? integerPart.substr(0, remainderLength) + thousandSeparator : "") +
478        integerPart.substr(remainderLength).replace(/(\d{3})(?=\d)/g, "$1" + thousandSeparator) +
479        (decimalPlaces ? decimalSeparator + Math.abs(n - integerPart).toFixed(decimalPlaces).slice(2) : "");
480
481    var formats = {
482        left: '{symbol}{price}',
483        left_space: '{symbol} {price}',
484        right: '{price}{symbol}',
485        right_space: '{price} {symbol}'
486    };
487
488	var formattedPrice = formats[parent.data.curr_pos]
489        .replace('{symbol}', parent.data.currency_symbol)
490        .replace('{price}', formattedIntegerPart);
491
492    return formattedPrice;
493	};
494
495	this.getPriceContainer = function() {
496		return jQuery( '.' + parent.scCont.data( 'price-class' ) );
497	};
498
499	this.updateAllAmounts = function() {
500		parent.calcTotal();
501		var price_cont = parent.getPriceContainer();
502		if ( price_cont.length > 0 ) {
503			var price = price_cont.find( '.wpec-price-amount' );
504			if ( price.length > 0 ) {
505				price.html( parent.formatMoney( parent.data.price ) );
506			}
507			if ( parent.data.quantity > 1 ) {
508				price_cont.find( '.wpec-quantity' ).show();
509				price_cont.find( '.wpec-quantity-val' ).html( parent.data.quantity );
510			} else {
511				price_cont.find( '.wpec-quantity' ).hide();
512			}
513			var total = price_cont.find( '.wpec_tot_current_price' );
514			var tot_new = price_cont.find( '.wpec_tot_new_price' );
515			var price_new = price_cont.find( '.wpec-new-price-amount' );
516			var shipping_new = price_cont.find( '.wpec_price_shipping_amount' );
517			if ( typeof parent.data.discountAmount !== "undefined" ) {
518				price_new.html( parent.formatMoney( parent.data.newPrice ) );
519				tot_new.html( parent.formatMoney( parent.data.total ) );
520				total.html( parent.formatMoney( parent.data.subtotal ) );
521			} else if ( total.length > 0 ) {
522				total.html( parent.formatMoney( parent.data.total ) );
523			}
524	
525			// Update the total shipping cost.
526			shipping_new.html(parent.formatMoney(parent.getTotalShippingCost()));
527			
528			var tax_val = price_cont.find( '.wpec-tax-val' );
529			if ( tax_val.length > 0 ) {
530				tax_val.html( parent.formatMoney( parent.data.tax_amount * parent.data.quantity ) );
531			}
532		}
533
534		jQuery( document ).trigger( 'wpec_after_update_all_amounts', [ parent ] );
535	};
536
537	this.calcTotal = function() {
538		var itemSubt = parseFloat( parent.data.price );
539		var quantity = parseInt( parent.data.quantity );
540		var tAmount = itemSubt * quantity;
541		//We need to round to 2 decimal places to make sure that the API call will not fail.
542		let roundedTotal = tAmount.toFixed(2);//round to 2 decimal places
543		let roundedTotalAsNumber = parseFloat(roundedTotal);//convert to number
544		tAmount = roundedTotalAsNumber;
545		var subtotal = tAmount;
546
547		parent.data.newPrice = itemSubt;
548
549		if ( typeof parent.data.discount !== "undefined" ) {
550			var discountAmount = 0;
551			if ( parent.data.discountType === 'perc' ) {
552				discountAmount = parent.PHP_round( tAmount * parent.data.discount / 100, parent.data.dec_num );
553			} else {
554				discountAmount = data.discount;
555			}
556			if ( discountAmount > tAmount ) {
557				discountAmount = tAmount;
558			}
559			tAmount = tAmount - discountAmount;
560			parent.data.discountAmount = parent.PHP_round( discountAmount, parent.data.dec_num );
561			parent.data.newPrice = parent.PHP_round( itemSubt - discountAmount / quantity, parent.data.dec_num );
562		}
563
564		if ( parent.data.tax ) {
565			var tax = parent.PHP_round( tAmount / quantity * parent.data.tax / 100, parent.data.dec_num );
566			parent.data.tax_amount = tax;
567			tAmount += tax * parent.data.quantity;
568			subtotal += parent.PHP_round( subtotal / quantity * parent.data.tax / 100, parent.data.dec_num ) * parent.data.quantity;
569		}
570
571		const totalShippingCost = parent.getTotalShippingCost();
572		if ( totalShippingCost ) {
573			tAmount += parseFloat( totalShippingCost );			
574			subtotal += parseFloat( totalShippingCost );
575		}
576		parent.data.total = parent.PHP_round( tAmount, parent.data.dec_num );
577		parent.data.subtotal = parent.PHP_round( subtotal, parent.data.dec_num );
578	};
579
580	this.PHP_round = function( num, dec ) {
581		return Math.round( num * Math.pow( 10, dec ) ) / Math.pow( 10, dec );
582	};
583
584	this.applyVariations = function( amount ) {
585		var grpId;
586		if ( parent.data.variations.applied ) {
587			for ( grpId = 0; grpId < parent.data.variations.applied.length; ++grpId ) {
588				var variation = parent.data.variations[ grpId ];
589				amount = amount + parseFloat( variation.prices[ parent.data.variations.applied[ grpId ] ] );
590			}
591		}
592		return parent.PHP_round( amount, parent.data.dec_num );
593	};
594
595	/**
596	 * Calculates the total shipping cost.
597	 * It calculates the per quantity shipping cost along with the base shipping cost of that product.
598	 * 
599	 * @returns {float} The total shipping cost in float of two decimal places. 
600	 */
601	this.getTotalShippingCost = function() {
602		let total = 0;
603		const quantity = parent.data.quantity ? parseInt(parent.data.quantity) : 1;
604		const baseShipping = parent.data.shipping ? parseFloat( parent.data.shipping ) : 0;
605		const shippingPerQuantity = parent.data.shipping_per_quantity ? parseFloat( parent.data.shipping_per_quantity ) : 0;
606	
607		total = baseShipping + (shippingPerQuantity * quantity);
608		// Round to 2 decimal places.
609		total = parseFloat(total.toFixed(2))
610		return total;
611	}
612
613	jQuery( document ).trigger( 'wpec_before_render_button', [ this ] );
614
615	paypal.Buttons( this.buttonArgs ).render( '#' + parent.data.id );
616};
617
618var wpecModal = function( $ ) {
619	var openModalId = false;
620
621	$( '.wpec-modal-open, .wpec-modal-overlay, .wpec-modal-close' ).on( 'click', function( e ) {
622		e.preventDefault();
623		toggleModal( $( this ).data( 'wpec-modal' ) );
624	} );
625
626	document.onkeydown = function( evt ) {
627		evt = evt || window.event;
628		var isEscape = false;
629		if ( "key" in evt ) {
630			isEscape = ( evt.key === "Escape" || evt.key === "Esc" );
631		} else {
632			isEscape = ( evt.keyCode === 27 );
633		}
634		if ( isEscape && openModalId ) {
635			toggleModal();
636		}
637	};
638
639	function toggleModal( modalId ) {
640		modalId = modalId ? modalId : openModalId;
641		openModalId = modalId;
642		var modal = document.getElementById( modalId );
643		modal.classList.toggle( 'wpec-opacity-0' );
644		modal.classList.toggle( 'wpec-pointer-events-none' );
645	}
646
647	$( '.wpec-custom-number-input button' ).on( 'click', function() {
648		var increment = $( this ).data( 'action' ) === 'increment' ? 1 : -1;
649		var input = $( this ).parent().find( 'input' );
650		var step = input.attr( 'step' ) ? Number( input.attr( 'step' ) ) : 1;
651		input.val( Number( input.val() ) + increment * step ).change();
652	} );
653
654	//shortcode_wpec_show_all_products
655	$("#wpec-sort-by").change(function(){
656		$("#wpec-sort-by-form").submit();
657	});
658};
659
660jQuery( wpecModal );

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.