PageSourceSearch

https://www.dieroester.at/resources/shop/js/jquery-ajax-cart.js

js dieroester.at collected 2026-10-01 16:24:32 UTC 23,064 bytes, 749 lines download raw bytes

1// events: initialized, beforeupdate, beforesubmit, afterupdate, invalidquantity, invalidform
2var AjaxCart = function () { }
3
4Number.prototype.extendedFormat = function(declen, partlen, secdelim, decdelim) {
5	var re = '\\d(?=(\\d{' + (partlen || 3) + '})+' + (declen > 0 ? '\\D' : '$') + ')',
6	num = this.toFixed(Math.max(0, ~~declen));
7
8	return (decdelim ? num.replace('.', decdelim) : num).replace(new RegExp(re, 'g'), '$&' + (secdelim || ','));
9};
10Number.prototype.format_de = function(declen) { return this.extendedFormat(declen,3,".",","); }
11Number.precisionByStep = function(step) {
12	// {{{
13	var split = step.toString().split(".");
14	var precision;
15	if (split.length > 1) {
16		precision = split[1].length;
17	} else {
18		precision = 0;
19	}
20	return precision;
21	// }}}
22}
23Number.normalize = function(strVal, strStep, strMin, inputFieldType) { 
24	// {{{
25	step 	= parseFloat(strStep);
26	min 	= parseFloat(strMin);
27
28	if (step 	== undefined || isNaN(step)) step = 1;
29	if (min 	== undefined || isNaN(step)) min 	= 1;
30
31    // for number inputs with step != 1, dots are not replaced
32    if (!(inputFieldType == "number" && step != 1)) {
33        strVal = strVal.replace(".","").replace(",",".");
34    }
35
36	if (step == 1) {
37		val = parseInt(strVal);
38	} else {
39
40		val = parseFloat(strVal);
41		/*
42		if ( strVal == parseFloat(strVal)  ) {
43			val = parseFloat(strVal);
44		} else {
45			// no "." and convert "," to "."
46			val = parseFloat(strVal.replace(".","").replace(",","."));
47		}
48		*/	
49
50		// prevent floating point problems (eg. 1.12 / 0.01 = 112.00000000000001)
51		val = Math.ceil(Math.round( val / step * 10000000)/10000000.0) * step;
52		//console.log(val);
53		// get digits after decimal sign
54		var precision = Number.precisionByStep(step);
55		precisionHelper = Math.pow(10,precision);
56		val = Math.round(val * precisionHelper) / precisionHelper;
57	}
58	
59
60	if (val < min) val = min;
61
62	if (isNaN(val)) val = null;
63
64	return val;
65	// }}}
66}
67
68ajaxCartInit = function($) {
69	AjaxCart.prototype = {
70		cartDiv: null,
71		options: {
72			identSubmits: 	'.-js-ajax-submit',
73			identSubmitAll: '.-js-ajax-submit-all',
74			identDeletes: 	'.-js-ajax-delete',
75			identForms: 		'.add-to-cart form',
76			identInputs: 		'input.num-of-items',
77			identInputViews: null,
78			identProduct: 	'input.-js-product-id',
79			// various checks
80			checkBeforeSubmit: null,
81			// end checks
82			colorHighlight: '#3F3',
83			colorHighlight2: '#3F3',
84			elem_id: 'shopping-cart-icon',
85			event: 'mouseenter',
86			hiddenOnSubmit: false,
87			initOnStart: false,
88			cartDiv: null,	
89			useReveal: false,
90			debug: false,
91			updateCartInfo: false,
92			autoMinVal: true,
93			checkFormValidity: true,
94			url: '/ecommerce/cart/dc_components/ajax-cart?',
95			urlData: {},
96			urlDelete: '/ecommerce/cart/delete',
97			redirectAfterSubmitUrl: null
98		},
99		initialize: function(options) {
100			// {{{
101			jQuery.extend(this.options,options);
102
103			//console.log(this.options);
104
105			var cart = this;
106			this.elem = $(this.options.elem_id);
107
108			if (this.options.debug) { console.log('initialize ajax cart', this.elem); }
109
110			this.initializeButtons();
111			if (this.options.cartDiv) {
112				this.cartDiv = $(this.options.cartDiv);
113			}
114
115			if (!this.options.useReveal) {
116				if (this.cartDiv == null) {
117					this.cartDiv = jQuery("<div>",{class:'ajax-cart'});
118					jQuery("body").append(this.cartDiv);
119				}
120				if (this.options.debug) { console.log('initialize ajax cart', cart.cartDiv); }
121
122				if (this.options.event && this.options.event != null) {
123
124					function closeCart() {
125						cart.cartDiv.css("opacity","0");
126						setTimeout( function(){ 
127							cart.cartDiv.css("display","none");
128						},1000);
129					}
130
131					this.cartDiv.on("mouseleave",closeCart);
132					jQuery(".ajax-cart .close-btn").on("click", closeCart);
133
134					if (this.elem) {
135						this.elem.on(this.options.event, function() {
136							cart.viewCart();
137						});
138					}
139				}
140			}
141
142			if (this.options.initOnStart) {
143				this.getCart(true);
144			}
145
146			jQuery(document).on('click','.-js-close-ajax-cart-modal',function(ev) {
147				if (parseInt(Foundation.version) >= 6) {
148					var reveal = $(this).closest(".reveal[data-reveal]");
149					reveal.foundation('close');
150				} else {
151					jQuery('#add-to-cart-popup').foundation('reveal', 'close');
152				}
153			});
154
155
156			$(document).on("blur", "input[type=text].num-of-items", function(ev) {
157				var precision = Number.precisionByStep(this.step);
158				var val = Number.normalize(this.value, this.step, this.min, this.type);
159				if (val) {
160					val = val.format_de(precision);
161				}
162				this.value = val;
163			});
164			$(document).on("change keydown click", "input[type=number][step=1]", function(ev) {
165				this.value = parseInt(this.value);
166			})
167
168			//$(document).trigger("initialized.ajax-cart");
169			$(cart).trigger("initialized");
170			// }}}
171		},
172		initializeButtons: function() {
173			// {{{
174			var cart = this;
175			$(this.options.identSubmits).prop("href","javascript:void(0);");
176			$(this.options.identSubmits).attr("onclick",null);
177			jQuery(document).on("click",this.options.identSubmits,function(ev) {
178				ev.preventDefault();
179				
180				var isValid = true;
181				let form = cart.getFormFromElem(this);
182				if (form && cart.options.checkFormValidity && !form.checkValidity()) {
183					isValid = false;
184					if (cart.options.debug) { console.log('submitItem','input quantity element', $(this).closest("form")[0], 'not valid'); }
185					$(cart).trigger("invalidquantity", [{"ok":false, "elem":$(this).closest("form")[0]}]);
186					/*
187					const invalidQuantityEvent = new CustomEvent('invalidQuantity.cart.dc', {
188						bubbles: true,
189						detail: { "cart": cart, "inputElem": elem  }
190					});
191					//console.log("dispatching event for", elem, ":", invalidQuantityEvent);
192					elem.dispatchEvent(invalidQuantityEvent);
193					*/
194
195				}
196
197				if (!isValid) { 
198					return;
199				}
200
201				// todo add configuration flag
202				let inp, closestNumItem;
203				closestNumItem = ev.target.closest(".num-of-items-outer")?.querySelector(".num-of-items");
204
205				if (!closestNumItem) {
206					closestNumItem = ev.target.closest("tr")?.querySelector(".num-of-items");
207				}
208				if (closestNumItem) {
209					inp = $(closestNumItem);
210				} else {
211					inp = jQuery("input.num-of-items");
212				}
213
214				if ( (inp.val() == undefined || inp.val() == 0) && cart.options.autoMinVal) {
215						let hasInput = false;
216						$.each(inp, function(idx,elem) {
217								if (elem.value > 0) hasInput = true;
218						});
219
220						if (!hasInput) {
221							let min = inp.prop("min");
222							if (min <= 0) min = 1;
223							inp.val(min);
224						}
225				}
226				cart.submitItem(this,cart);
227			});
228			jQuery(document).on("click",this.options.identDeletes,function(ev) {
229				cart.deleteItem(this,cart)
230					.then((data) => {
231						cart.updateCartInfo();
232					})
233					.catch((err) => {
234						console.error(err);
235					})
236			});
237			jQuery(document).on("click",this.options.identSubmitAll,function(ev) {
238				ev.preventDefault();
239				cart.submitAllItems(this,cart);
240			});
241			// }}}
242		},
243		getFormFromElem: function(elem) {
244			// {{{
245			let form;
246			//let type = elem.dataset.type;
247			let formId = elem.dataset.formId;
248			if (formId !== undefined) {
249				form = document.getElementById(formId);
250			}
251			if (form === undefined || form.length == 0) {
252				form = elem.closest("form"); 
253			}
254
255			return form;
256			// }}}
257		},
258		submitItem: function(elem,cart) {
259			// {{{
260
261			let form;
262			let type = $(elem).data('type');
263
264			form = this.getFormFromElem(elem);
265			this.form = form;
266			form = $(form);
267
268			if (this.options.checkBeforeSubmit) {
269				if (!(this.options.checkBeforeSubmit.bind(this))()) {
270					return
271				}
272			}
273
274			let resBeforeUpdate = $(this).trigger("beforeupdate", [{"form":form}]);
275			var hasAmount = false;
276
277			//var valid = form.checkValidity();
278
279			//if (!valid) {
280			// sanitize
281			var numberInputs = form.find("input.num-of-items");
282			if (numberInputs.length == 0) numberInputs = form.find("input[name=num_of_items]");
283			//console.log(numberInputs);
284			$.each(numberInputs, function(idx,elem) {
285				//console.log(idx,elem);
286				elem.value = Number.normalize(elem.value, elem.step, elem.min, elem.type);
287				if (val > 0) hasAmount = true; 
288			});
289			//}
290			
291			if (!hasAmount) {
292				if (this.options.debug) { console.log('submitItem','no items with amounts found'); }
293				return;
294			}
295
296			let productId = null;
297			if (elem.dataset.pid) {
298				productId = elem.dataset.pid;
299			}
300
301			let valid = form.get(0).checkValidity();
302			if (this.options.checkFormValidity && !valid) {
303				if (this.options.debug) { console.log('submitItem','form not valid'); }
304				$(cart).trigger("invalidform", [{"ok":false, "form":form.get(0)}]);
305				return;
306			}
307
308			let resBeforeSubmit = $(this).trigger("beforesubmit", [{"form":form}]);
309
310			if (type) {
311				let typeTag = form.find("input[name=type]");
312				if (typeTag.length > 0) typeTag.val(type);
313			}
314
315			if (this.options.debug) { console.log('submitItem', 'Form', form.get(0), 'Type', type, 'useReveal', cart.options.useReveal, 'action', form.action); }
316			let me = this;
317
318			if (cart.options.useReveal) {
319				// {{{
320				let data = form.serializeArray();
321				data.push({name:"ajax_p", value: "t"});
322
323				//console.log(data, form.prop("action"));
324				$(elem).addClass("loading");
325				jQuery.ajax({
326					"method": "POST",
327					"url":form.prop("action"), 
328					"data": data,
329					"dataType": "json"
330				})
331				.done(function(retData, txt, xhr) {
332					if (retData.ok != false) {
333						//let elems = form.find("input.num-of-items").filter(function() { return parseInt(j
333Query(this).val()) > 0 });
334						let elems = form.find("input.num-of-items").filter(function(idx, elem) { return parseInt(elem.value) > 0 });
335						elems.val("");
336						elems.trigger("change");
337
338						cart.getCart(cart.options.hiddenOnSubmit, type, [productId]);
339						if (cart.options.updateCartInfo) cart.updateCartInfo();
340
341						$(me).trigger("afterupdate", [{"ok":true, "form":form, "data":retData}]);
342						me.triggerEvent("items-submit-success.cart.dc", {"ok":true, "form":form, "elems": elems, "data":data, "result":retData});
343					} else {
344						if (retData.executeActions) {
345							cart.executeActions(retData.executeActions, retData);
346						}
347						console.log("CART ERROR", retData);
348						me.triggerEvent("items-submit-failure.cart.dc", {"ok":true, "form":form, "data":data, "result":retData});
349					}
350
351				})
352				.fail(function(xhr, txt, err) {
353					$(me).trigger("afterupdate", [{"ok":false, "form":form}]);
354					me.triggerEvent("items-submit-failure.cart.dc", {"ok":false, "form":form, "data":data});
355					console.log(txt,err);
356				})
357				.always(function(data, txt, xhr) {
358					$(elem).removeClass("loading");
359				});
360				// }}}
361			} else {
362				// {{{
363				let elems = form.find("input.num-of-items").filter(function(idx, elem) { return parseInt(elem.value) > 0 });
364				elems.addClass("cart-submitting");
365				let data = jQuery(form).serialize();  
366				data += "&ajax_p=t";
367				jQuery.ajax({
368					"method": "POST",
369					"url":form.prop("action"), 
370					"data": data,
371					"dataType": "html"
372				})
373				.done(function(data, txt, xhr) {
374					// reset the input values to "min" attribute
375					//jQuery.each(elems, function(idx,elem) { jQuery(elem).val(jQuery(elem).prop("min")); })
376					jQuery.each(elems, function(idx,elem) { 
377						//elem.value = elem.min; 
378						elem.value = ""; 
379					})
380					elems.removeClass("cart-submitting");
381
382					// get the cart 
383					cart.getCart(false, type); 
384
385					// update the cart info
386					if (cart.options.redirectAfterSubmitUrl) {
387						window.location.href = cart.options.redirectAfterSubmitUrl;
388					} else {
389						if (cart.options.updateCartInfo) cart.updateCartInfo();
390					}
391					$(me).trigger("afterupdate", [{"ok":true, "form":form, "data":data}]);
392					me.triggerEvent("items-submit-success.cart.dc", {"ok":true, "form":form, "elems": elems.toArray(), "data":data});
393
394				})
395				.fail(function(xhr, txt, err) {
396					$(me).trigger("afterupdate", [{"ok":false, "form":form}]);
397					me.triggerEvent("items-submit-failure.cart.dc", {"ok":false, "form":form, "elems": elems.toArray(), "data":data});
398					console.log(txt,err);
399				})
400				.always(function(data, txt, xhr) {
401				});
402				// }}}
403			}
404			//console.log("dispatching event for", elem, ":", invalidQuantityEvent);
405			//elem.dispatchEvent(invalidQuantityEvent);
406			// }}}
407		},
408		submitAllItems: function(elem,cart) {
409			// {{{
410			//var form = $(elem).parents("form");
411			var type = $(elem).get("type");
412			var forms = $(cart.options.identForms);
413
414			var data = "";
415			var action;
416			var quantityInputs = new Array();
417			$.each(forms, function(idx, form) {
418				if (form.checkValidity()) {
419					var quantityInput =	$(form).find(cart.options.identInputs);
420					if (quantityInput.val() != undefined) {
421						console.log(quantityInput.val());
422					}
423					quantityInput.val(Number.normalize(quantityInput.val(), quantityInput.prop("step"), quantityInput.prop("min"), quantityInput.prop("type")));
424					//console.log(quantityInput.value);
425					if (quantityInput.length > 0 && parseFloat(quantityInput.val()) > 0) {
426						data += $(form).serialize() + "&"
427						action = $(form).prop("action");
428						quantityInputs.push(quantityInput);
429						console.log("val", quantityInput.val(), "data", data);
430					}
431				} 
432			});
433			console.log(data, action, data.length);
434			
435			if (data.length == 0) return;
436
437			if (this.options.debug) { console.log('submitAllItems', type, cart.options.useReveal); }
438
439			if (cart.options.useReveal) {
440				// {{{
441				//var data = jQuery(form).serialize();  
442				data += "&ajax_p=t";
443
444				jQuery.ajax({
445					"method": "POST",
446					"url": action, 
447					"data": data,
448					"dataType": "html"
449				})
450				.done(function(data, txt, xhr) {
451					cart.getCart(cart.options.hiddenOnSubmit, type);
452					if (cart.options.updateCartInfo) cart.updateCartInfo();
453
454					$.each(quantityInputs, function(idx,elem) {
455						$(elem).val("");
456					});
457
458					$(cart).trigger("afterupdate", [{"ok":true, "form":form}]);
459				})
460				.fail(function(xhr, txt, err) {
461					console.log(txt,err);
462				})
463				.always(function(data, txt, xhr) {
464				});
465				// }}}
466			} else {
467			}
468			// }}}
469		},
470		getCart: function(hidden, type = null, pids = null) {
471			// {{{
472			if (this.options.debug) { console.log('getCart Type:', type, "URL:", this.options.url); }
473
474			if (this.options.useReveal) {
475				// REVEAL {{{
476				if (this.options.url) {
477					let revealUrl = new URL(this.options.url, window.location)
478					if ( type !== null) {
479						revealUrl.searchParams.set("type", type);
480					}
481					if (pids !== null) {
482						revealUrl.searchParams.set("product_ids", pids.join(" "));
483					}
484
485					if (!hidden) {
486						if (parseInt(Foundation.version) >= 6) {
487							let reveal = $('#add-to-cart-popup');
488							const me = this;
489							$.ajax(revealUrl.toString()).done(function(resp) {
490								reveal.html(resp).foundation("open");
491								if (me.options.debug) { console.log('getCart Cart Response:', resp); }
492								// new Foundation.Reveal($modal.html(resp.html)).open(); //.foundation('open');
493							});
494						} else {
495							if (this.options.debug) console.log('getCart URL',this.options.url);
496							jQuery('#add-to-cart-popup').foundation('reveal', 'open', {
497								"url": revealUrl.toString()
498							});
499						}
500					}
501
502				} else {
503
504					if (this.options.debug) { console.log('getCart reveal elem for type:', type); }
505
506					var reveal;
507					if (type) {
508						reveal = jQuery('#add-to-'+type+'-popup');
509					}
510					if (!reveal || reveal.length == 0) {
511						reveal = jQuery('#add-to-cart-popup');
512					}
513					if (parseInt(Foundation.version) >= 6) {
514						reveal.foundation("open");
515					} else {
516						reveal.foundation('reveal', 'open');
517					}
518
519				}
520				// }}}
521			} else {
522				// DIV {{{
523				var rnd = (new Date()).getTime();
524				var cart = this;
525
526				if (this.options.debug) console.log('getCart URL',this.options.url);
527
528				if (this.options.url !== null) {
529
530					let data = cart.options.urlData;
531					data["type"]=type;
532
533					jQuery.ajax({
534						"method": "POST",
535						"url": this.options.url,
536						"data": data,
537						"dataType": "html"
538					})
539					.done(function(html, status, xhr) {
540						if (cart.cartDiv != undefined) {
541							cart.cartDiv.html(html);
542							if (!hidden) {
543								//cart.cartDiv.fadeIn(1000);
544								cart.cartDiv.css("display","block");
545								cart.cartDiv.css("opacity","1");
546							}
547						}
548					})
549					.fail(function(xhr, txt, err) {
550						console.log(txt,err);
551					})
552					.always(function(data, txt, xhr) {
553					});
554				}
555				// }}}
556			}
557			// }}}
558		},
559		viewCart: function() {
560			// {{{
561			if (this.options.useReveal) {
562				this.getCart();
563			} else {
564				if (this.cartDiv) {
565					this.cartDiv.fadeIn(1000);
566				} else {
567					this.getCart();
568				}
569			}
570			// }}}
571		},
572		deleteItem: function(elem, cart) {
573			// {{{
574			return new Promise((resolve, reject) => {
575			/*
576			var myRequest = new Request({
577				url: cart.options.urlDelete,
578				onSuccess: function(responseTree, responseElements, responseHTML, responseJavaScript) {
579					$$('.-js-item-'+item_id).each(function(elem){elem.dispose();});
580					cart.viewCart();
581				},
582				onFailure: function(xhr) {
583					console.log(xhr.responseText);
584				}
585			}).get('item_id='+item_id);
586			*/
587
588			//var elem = $(this);
589			elem = $(elem);
590			let url = "/ecommerce/cart/delete";
591			let itemId = elem.data("item-id");
592			let cart = this;
593
594			elem.addClass("loading");
595
596			$.ajax({
597				"method": "POST",
598				"url": url,
599				"data": {
600					"item_id": itemId,
601					"type": "cart",
602				},
603				"dataType": "html"
604			})
605			.done(function(data, txt, xhr) {
606				$(cart).trigger("item-deleted", [{"itemId":itemId}]);
607				resolve(data);
608			})
609			.fail(function(xhr, txt, err) {
610				console.log(txt,err);
611				reject(err);
612			})
613			.always(function(data, txt, xhr) {
614				elem.removeClass("loading");
615			});
616		});
617
618
619			// }}}
620		},
621		updateCartInfo: function() {
622			// {{{
623			const cart = this;
624			$.ajax({
625				"method": "POST",
626				"url": "/ecommerce/ajax/cart-info",
627				"dataType": "json"
628			})
629			.done(function(data, txt, xhr) {
630				//if (cart.options.debug) { console.log(data); }
631
632				$(".-js-cart-num").html(data.num);
633				$(".-js-cart-sum").html(data.sum);
634				if (data.total_item_value != null && data.total_item_value != "")               $(".-js-cart-value").html(data.total_item_value.format_de(2));
635				if (data.total_item_value != null && data.total_net_item_value != "")           $(".-js-cart-net-value").html(data.total_net_item_value.format_de(2));
636				if (data.total_item_value != null && data.total_item_value_formatted != "")     $(".-js-cart-value-formatted").html(data.total_item_value_formatted);
637				if (data.total_item_value != null && data.total_net_item_value_formatted != "") $(".-js-cart-net-value-formatted").html(data.total_net_item_value_formatted);
638				
639				if (data.num > 0) {
640					$(".-js-cart-container").addClass("-js-cart-empty-f");
641					$(".-js-cart-container").removeClass("-js-cart-empty-t");
642				} else {
643					$(".-js-cart-container").addClass("-js-cart-empty-t");
644					$(".-js-cart-container").removeClass("-js-cart-empty-f");
645				}
646
647				if (data.billing_line1  && data.billing_line1  != null) $(".-js-cart-billing-line1").html(data.billing_line1);
648				if (data.billing_street && data.billing_street != null) $(".-js-cart-billing-street").html(data.billing_street);
649				if (data.billing_house_number && data.billing_house_number != null) $(".-js-cart-billing-house-number").html(data.billing_house_number);
650				if (data.billing_zip_code && data.billing_zip_code != null) $(".-js-cart-billing-zip-code").html(data.billing_zip_code);
651				if (data.billing_city && data.billing_city != null) $(".-js-cart-billing-city").html(data.billing_city);
652
653				if (data.shipping_line1  && data.shipping_line1  != null) $(".-js-cart-shipping-line1").html(data.shipping_line1);
654				if (data.shipping_street && data.shipping_street != null) $(".-js-cart-shipping-street").html(data.shipping_street);
655				if (data.shipping_house_number && data.shipping_house_number != null) $(".-js-cart-shipping-house-number").html(data.shipping_house_number);
656				if (data.shipping_zip_code && data.shipping_zip_code != null) $(".-js-cart-shipping-zip-code").html(data.shipping_zip_code);
657				if (data.shipping_city && data.shipping_city != null) $(".-js-cart-shipping-city").html(data.shipping_city + ",");
658
659				if (data.payment_name && data.payment_name != null) $(".-js-cart-payment-name").html(data.payment_name);
660
661				$(cart).trigger("cartinfo", [{"cartInfo": data}]);
662
663			})
664			.fail(function(xhr, txt, err) {
665				console.log(txt,err);
666			})
667			.always(function(data, txt, xhr) {
668			});
669			// }}}
670		},
671		// see /ecommerce/cart/lists/js/wishlist.js
672		/*
673		updateWishlistInfo: function() {
674			// {{{
675			const cart = this;
676			let url = new URL("/ecommerce/ajax/cart-info", window.location.protocol + "//" + window.location.host)
677			url.searchParams.set("type","wishlist");
678
679			fetch(url)
680				.then(response => { 
681					if (response.ok) {
682						return response.json() 
683					} else {
684						return "ERROR"
685					}
686				})
687				.then(data => {
688					if (cart.options.debug) { console.log(data); }
689					$(".-js-wishlist-num").html(data.num);
690					$(".-js-wishlist-sum").html(data.sum);
691					if (data.total_item_value != null && data.total_item_value != "")               $(".-js-wislist-value").html(data.total_item_value.format_de(2));
692					if (data.total_item_value != null && data.total_net_item_value != "")           $(".-js-wislist-net-value").html(data.total_net_item_value.format_de(2));
693					if (data.total_item_value != null && data.total_item_value_formatted != "")     $(".-js-wislist-value-formatted").html(data.total_item_value_formatted);
694					if (data.total_item_value != null && data.total_net_item_value_formatted != "") $(".-js-wislist-net-value-formatted").html(data.total_net_item_value_formatted);
695
696					if (data.num > 0) {
697						$(".-js-wishlist-container").addClass("-js-wishlist-empty-f");
698						$(".-js-wishlist-container").removeClass("-js-wishlist-empty-t");
699					} else {
700						$(".-js-wishlist-container").addClass("-js-wishlist-empty-t");
701						$(".-js-wishlist-container").removeClass("-js-wishlist-empty-f");
702					}
703
704					$(cart).trigger("wishlistinfo", [{"wishlistInfo": data}]);
705
706				})
707				.catch(error => {
708					console.log(error);
709				});
710			// }}}
711		},
712		*/
713		executeActions: function(actions, data) {
714			// {{{
715			if (actions.indexOf("redirect") > -1) {
716				if (data && data.redirectUrl) {
717				console.log("REDIRECT", data, data.redirectUrl)
718					window.location.href = data.redirectUrl;
719					return
720				}
721			} else if (actions.indexOf("reload") > -1) {
722				window.location.reload();
723				return
724			}
725			// }}}
726		},
727		triggerEvent: function(evName, details) {
728			const ev = new CustomEvent(evName, {"detail": details});
729			window.dispatchEvent(ev);
730		}
731	}
732};
733ajaxCartInit(jQuery);
734
735/*
736(function ($, window, undefined) {
737  'use strict';
738
739  $('[data-reveal]').on('closed.zf.reveal', function () {
740    var modal = $(this);
741		if ($("body").hasClass("is-reveal-open")) { 
742			console.log("removed is-reveal-open class from body");
743			$("body").removeClass("is-reveal-open"); 
744		}
745  });
746
747  //$(document).foundation();
748})(jQuery, this);
749*/

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.