PageSourceSearch

https://marktplatz.kommunalnet.at/wp-content/plugins/KN%20Product%20Variation/assets/js/frontend.js?ver=1.0.0

js kommunalnet.at collected 2026-10-03 22:55:52 UTC 8,566 bytes, 216 lines download raw bytes

1/**
2 * KN Product Variation Frontend Scripts
3 *
4 * @package  KN Product Variation
5 * @category Frontend
6 * @author   IP Austria
7 */
8
9(function($) {
10	'use strict';
11
12	// Get the add-to-cart form for a product (works with default WooCommerce and Elementor).
13	function getCartFormForProduct(productId) {
14		if (!productId) return $();
15		// Form containing add-to-cart hidden input for this product
16		var $input = $('input[name="add-to-cart"][value="' + productId + '"]');
17		if ($input.length) return $input.closest('form');
18		// Form inside same product block as our variations wrapper
19		var $wrapper = $('#kn-product-variations-' + productId);
20		if ($wrapper.length) {
21			var $form = $wrapper.closest('.product').find('form');
22			if ($form.length) return $form.first();
23		}
24		// Fallback: any form.cart
25		return $('form.cart').first();
26	}
27
28	// Put or remove kn_variation_index in the product's add-to-cart form so cart receives it (price + variation name).
29	function syncVariationToCartForm(productId, variationIndex) {
30		var $form = getCartFormForProduct(productId);
31		var $existing = $form.find('input[name="kn_variation_index"], #kn_variation_index_input');
32		if ($existing.length) {
33			$existing.val(variationIndex !== undefined && variationIndex !== null && variationIndex >= 0 ? variationIndex : '');
34		} else {
35			$form.find('input[name="kn_variation_index"]').remove();
36			if (variationIndex !== undefined && variationIndex !== null && variationIndex >= 0) {
37				$form.append($('<input>').attr({ type: 'hidden', name: 'kn_variation_index', value: variationIndex }));
38			}
39		}
40	}
41
42	// Helper: get variation index from radio (data-variation-index or value).
43	function getRadioVariationIndex($radio) {
44		var index = $radio.data('variation-index');
45		if (index === undefined || index === null) {
46			var val = $radio.val();
47			if (val !== undefined && val !== '') index = parseInt(val, 10);
48		}
49		return (index >= 0) ? index : null;
50	}
51
52	// Ensure at least one variation is selected (run on ready, after delay, and on load so we win over late scripts that uncheck).
53	function ensureFirstVariationSelected() {
54		// Sync any already-checked variation to the form.
55		$('.kn-variation-radio:checked').each(function() {
56			var productId = $(this).data('product-id');
57			var index = getRadioVariationIndex($(this));
58			if (productId !== undefined && index !== null) {
59				syncVariationToCartForm(productId, index);
60			}
61		});
62		// If a wrapper has no checked radio, select the first one.
63		$('.kn-product-variations-wrapper').each(function() {
64			var $wrap = $(this);
65			var productId = $wrap.data('product-id');
66			var $checked = $wrap.find('.kn-variation-radio:checked');
67			if (!$checked.length) {
68				var $first = $wrap.find('.kn-variation-radio').first();
69				if ($first.length) {
70					$first.prop('checked', true);
71					$first.closest('.kn-variation-item').addClass('selected');
72					$first.closest('.kn-variation-label').addClass('selected');
73					var index = getRadioVariationIndex($first);
74					if (productId !== undefined && index !== null) {
75						syncVariationToCartForm(productId, index);
76					}
77					$first.trigger('change');
78				}
79			}
80		});
81	}
82
83	$(document).ready(function() {
84		ensureFirstVariationSelected();
85		// Re-apply after short delay (in case DOM was not fully ready or widgets render late).
86		setTimeout(ensureFirstVariationSelected, 100);
87		setTimeout(ensureFirstVariationSelected, 500);
88		// Re-apply on window load so we win over any script that unchecks after full load (e.g. Elementor).
89		$(window).on('load', ensureFirstVariationSelected);
90
91		// Handle radio button selection/deselection
92		$(document).on('change', '.kn-variation-radio', function() {
93			const $radio = $(this);
94			const productId = $radio.data('product-id');
95			const variationIndex = getRadioVariationIndex($radio);
96			const $label = $radio.closest('.kn-variation-label');
97			const $item = $radio.closest('.kn-variation-item');
98			const $info = $('.kn-selected-variation-info');
99
100			// If radio is checked, select it
101			if ($radio.is(':checked') && variationIndex !== null) {
102				// Update selected state visually (support both plugin template and add-to-cart widget)
103				$('.kn-variation-label').removeClass('selected');
104				$('.kn-variation-item').removeClass('selected');
105				$label.addClass('selected');
106				$item.addClass('selected');
107
108				// Get variation data via AJAX
109				$.ajax({
110					url: knProductVariationFrontend.ajax_url,
111					type: 'POST',
112					data: {
113						action: 'kn_get_variation_data',
114						nonce: knProductVariationFrontend.nonce,
115						product_id: productId,
116						index: variationIndex
117					},
118					success: function(response) {
119						if (response.success && response.data) {
120							const variation = response.data.variation;
121							
122							// Show selected variation info
123							$info.find('.kn-selected-variation-name').text(variation.name);
124							$info.find('.kn-selected-variation-price').html(response.data.price_html);
125							$info.fadeIn(300);
126
127							// Trigger custom event for other scripts
128							$(document).trigger('kn_variation_selected', [variation, response.data]);
129
130							// Keep variation in add-to-cart form so it is sent (normal and AJAX add to cart)
131							syncVariationToCartForm(productId, variationIndex);
132
133							// Update add to cart button if exists
134							const $addToCart = $('button.single_add_to_cart_button, .single_add_to_cart_button');
135							if ($addToCart.length) {
136								$addToCart.data('variation-index', variationIndex);
137								$addToCart.data('variation-price', response.data.price);
138							}
139						} else {
140							console.error('Error loading variation data');
141						}
142					},
143					error: function() {
144						console.error('Error loading variation data');
145					}
146				});
147			} else {
148				// Radio is unchecked, deselect
149				$label.removeClass('selected');
150				$info.fadeOut(300);
151				syncVariationToCartForm(productId, null);
152
153				// Trigger custom event for deselection
154				$(document).trigger('kn_variation_deselected');
155
156				// Clear add to cart button data
157				const $addToCart = $('button.single_add_to_cart_button, .single_add_to_cart_button');
158				if ($addToCart.length) {
159					$addToCart.removeData('variation-index');
160					$addToCart.removeData('variation-price');
161				}
162			}
163		});
164
165		// Before ANY add-to-cart form submits (including "Kaufe jetzt" / Buy now), add variation so cart gets name + price.
166		$(document).on('submit', 'form', function() {
167			var $form = $(this);
168			if (!$form.find('input[name="add-to-cart"]').length) return;
169			var productId = $form.find('input[name="add-to-cart"]').val();
170			var $checked = $form.closest('.product').find('.kn-variation-radio:checked');
171			if (!$checked.length && productId) $checked = $('#kn-product-variations-' + productId).find('.kn-variation-radio:checked');
172			if ($checked.length) {
173				var index = getRadioVariationIndex($checked);
174				if (index !== null) syncVariationToCartForm(productId, index);
175			}
176		});
177
178		// On click of add-to-cart / buy-now button (including "Kaufe jetzt für"), sync variation into form so cart gets name + price.
179		$(document).on('click', 'form:has(input[name="add-to-cart"]) button[type="submit"], form:has(input[name="add-to-cart"]) input[type="submit"], .single_add_to_cart_button', function() {
180			var $btn = $(this);
181			var $form = $btn.closest('form');
182			if (!$form.length || !$form.find('input[name="add-to-cart"]').length) return;
183			var productId = $form.find('input[name="add-to-cart"]').val();
184			if (!productId) productId = $form.closest('.product').find('.kn-product-variations-wrapper').attr('data-product-id');
185			if (!productId) return;
186			var $checked = $('#kn-product-variations-' + productId).find('.kn-variation-radio:checked');
187			if ($checked.length) {
188				var index = getRadioVariationIndex($checked);
189				if (index !== null) syncVariationToCartForm(productId, index);
190			}
191		});
192
193		// Handle label click (for better UX - allow toggle)
194		$(document).on('click', '.kn-variation-label', function(e) {
195			// Don't interfere with radio button clicks
196			if ($(e.target).is('input[type="radio"]')) {
197				return;
198			}
199
200			const $label = $(this);
201			const $radio = $label.find('input[type="radio"]');
202			
203			if ($radio.length) {
204				// If already checked, uncheck it (allow deselection)
205				if ($radio.is(':checked')) {
206					$radio.prop('checked', false).trigger('change');
207				} else {
208					// Uncheck all others first, then check this one
209					$('.kn-variation-radio').not($radio).prop('checked', false);
210					$radio.prop('checked', true).trigger('change');
211				}
212			}
213		});
214	});
215
216})(jQuery);

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.