PageSourceSearch

https://am-qualitaetsmatratzen.de/wp-content/plugins/amq-cross-selling/assets/js/crossSelling.js?ver=1.4.1

js am-qualitaetsmatratzen.de collected 2026-10-05 02:11:14 UTC 9,384 bytes, 235 lines download raw bytes

1jQuery(document).ready(function ($) {
2    const variationCache = new Map();
3
4    $(document).on('change', '.amq-variation-select', function () {
5        const productContainer = $(this).closest('.xoo-wsc-sp-product');
6        const selected_variations = getSelectionsAndUpdateLinks(productContainer);
7
8        if (isProductVariationFullySelected(productContainer, selected_variations)) {
9            getProductFromSelection(productContainer, selected_variations);
10        } else {
11            resetToBasePrice(productContainer);
12        }
13    });
14
15    function resetToBasePrice(productContainer) {
16        var base_price = productContainer.find('.xoo-wsc-sp-title').data('base_price');
17
18        // Disable Add to Cart button if not all variations are selected
19        productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(formatPrice(base_price));
20        productContainer.find('.add_to_cart_button').removeClass('amq_cross_sell_add_to_cart');
21        productContainer.find('.starts_at').show();
22    }
23
24    function isProductVariationFullySelected(productContainer, selected_variations) {
25        return productContainer.find('.amq-variation-select').length === Object.keys(selected_variations).length;
26    }
27
28    function formatPrice(price) {
29        const num = Number(price);
30
31        if (!Number.isFinite(num)) {
32            console.warn('Ungültiger Preiswert empfangen:', price);
33            return '';
34        }
35
36        return new Intl.NumberFormat('de-DE', {
37            style: 'currency',
38            currency: 'EUR'
39        }).format(num);
40    }
41
42    function getProductFromSelection(productContainer, selected_variations) {
43        const product_id = productContainer.find('.xoo-wsc-sp-title').data('product_id');
44        const cacheKey = generateCacheKey(product_id, selected_variations);
45
46        // Prüfen ob bereits im Cache vorhanden
47        if (variationCache.has(cacheKey)) {
48            const cachedResponse = variationCache.get(cacheKey);
49            updateProductDisplay(productContainer, cachedResponse);
50            return;
51        }
52
53        // Prüfen ob bereits ein Request für diese Variation läuft
54        if (productContainer.data('loading-variation-key') === cacheKey) {
55            return;
56        }
57
58        productContainer.find('.loading-overlay').css("display", "flex").hide().fadeIn();
59        productContainer.data('loading-variation-key', cacheKey);
60
61        const requestData = { ...selected_variations };
62        requestData['product_id'] = product_id;
63
64        $.ajax({
65            url: '/?wc-ajax=get_variation',
66            type: 'POST',
67            data: requestData,
68            success: function (response) {
69                if (response && response.variation_id) {
70                    // Response im Cache speichern
71                    variationCache.set(cacheKey, response);
72                    updateProductDisplay(productContainer, response);
73                }
74            },
75            error: function (data) {
76                console.log("not found");
77            },
78            complete: function () {
79                productContainer.find('.loading-overlay').fadeOut();
80                productContainer.removeData('loading-variation-key');
81            }
82
83        });
84    }
85
86    function generateCacheKey(product_id, selected_variations) {
87        const sortedKeys = Object.keys(selected_variations).sort();
88        const variationString = sortedKeys.map(key => `${key}:${selected_variations[key]}`).join('|');
89        return `${product_id}_${variationString}`;
90    }
91
92    function updateProductDisplay(productContainer, response) {
93        const regularPrice = formatPrice(response.display_price);
94        const addToCartButton = productContainer.find('.add_to_cart_button');
95
96        const vid = Number(response.variation_id);
97        if (Number.isInteger(vid)) {
98            addToCartButton
99                .attr('href', '?add-to-cart=' + vid)
100                .attr('data-variation_id', vid)
101                .addClass('amq_cross_sell_add_to_cart');
102        }
103
104        productContainer.find('img').attr({
105            src: response.image.full_src,
106            srcset: response.image.srcset
107        });
108        productContainer.find('.starts_at').hide();
109
110        if (response.amq_cross_selling_price) {
111            const salePrice = formatPrice(response.amq_cross_selling_price);
112            const rabattAmount = formatPrice(response.display_price - response.amq_cross_selling_price);
113
114            productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(salePrice);
115            productContainer.find('.xoo-wsc-sp-price > del .amount bdi').html(regularPrice);
116            productContainer.find('.xoo-wsc-sp-price > .amq-discount-message .amount bdi').html(rabattAmount);
117        } else {
118            productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(regularPrice);
119        }
120    }
121
122    function getSelectionsAndUpdateLinks(productContainer) {
123        const selectedVariations = {};
124
125        productContainer.find('.amq-variation-select').each(function () {
126            const attributeName = this.name;
127            const attributeValue = this.value;
128            if (attributeValue) {
129                selectedVariations[attributeName] = attributeValue;
130            }
131            toggleAmqFloatingLabel(this);
132        });
133
134        const queryString = $.param({ ...selectedVariations, source: 'side_cart-product_page' });
135        const productLink = productContainer.find('.xoo-wsc-sp-title').data('product_link').split('?')[0] + '?' + queryString;
136
137        productContainer.find('.xoo-wsc-sp-left-col a, .xoo-wsc-sp-title a').attr('href', productLink);
138        return selectedVariations;
139    }
140
141    function toggleAmqFloatingLabel(select) {
142        const container = $(select).closest('.amq-floating-label');
143        container.toggleClass('amq-active', !!$(select).val());
144    }
145
146    (function addSourceParamToProduct() {
147        const searchParams = new URLSearchParams(window.location.search);
148
149        if (searchParams.has('source')) {
150            const source = searchParams.get('source'); // No need for escape, URLSearchParams handles decoding
151            const hiddenInputSelector = '#cross_selling_source';
152
153            if (!document.querySelector(hiddenInputSelector)) {
154                const input = document.createElement('input');
155                input.type = 'hidden';
156                input.id = 'cross_selling_source';
157                input.name = 'cross_selling_source';
158                input.value = source;
159
160                document.querySelector('form.variations_form')?.appendChild(input);
161            }
162        }
163    })();
164
165    $('.amq-floating-label select').each(function () {
166        toggleAmqFloatingLabel(this);
167    });
168
169    $(document).on('change focus blur', '.amq-floating-label select', function (event) {
170        if (event.type === 'change' || (event.type === 'focus' && !$(this).val()) || (event.type === 'blur' && $(this).val())) {
171            toggleAmqFloatingLabel(this);
172        }
173    });
174
175    $(document.body).on('xoo_wsc_cart_toggled wc_fragments_refreshed xoo_wsc_cart_updated', function () {
176        $('.xoo-wsc-sp-product').each(function () {
177            const productContainer = $(this);
178            const selectedVariations = getSelectionsAndUpdateLinks(productContainer);
179
180            if (isProductVariationFullySelected(productContainer, selectedVariations)) {
181                getProductFromSelection(productContainer, selectedVariations);
182            }
183        });
184    });
185
186    $(document).on('click', '.amq-collapsible-button', function () {
187        $(this).toggleClass('active')
188            .closest('.amq-collapsible-container')
189            .find('.amq-collapsible-content, .amq-variation-container')
190            .slideToggle(() => $('ul.xoo-wsc-sp-slider').trigger('resize'));
191    });
192
193    $(document).on('click', '.amq_cross_sell_add_to_cart', function (e) {
194        e.preventDefault();
195
196        var $button = $(this);
197        var product_id = $button.data('product_id');
198        var variation_id = $button.data('variation_id');
199        var parent_product_id = $button.data('parent_product_id');
200
201        $button.addClass('loading xoo-wsc-loading');
202
203        $(document.body).trigger('adding_to_cart', [$button, []]);
204
205        $.ajax({
206            url: '/?wc-ajax=add_cross_sell_to_cart', // WooCommerce AJAX endpoint
207            type: 'POST',
208            data: {
209                product_id: product_id,
210                variation_id: variation_id,
211                parent_product_id: parent_product_id,
212            },
213            success: function (response) {
214                if (response.fragments) {
215                    // Trigger event so themes can refresh other areas.
216                    $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]);
217                } else if (response.error) {
218                    console.error(response.error);
219                }
220                else {
221                    window.location.reload();
222                }
223            },
224            error: function () {
225                console.error('An error occurred while adding the product to the cart.');
226            },
227            complete: function () {
228                $button
229                    .removeClass('loading xoo-wsc-loading')
230                    .addClass('added');
231            }
232        });
233    });
234
235});

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.