PageSourceSearch

https://www.rossmann-fotowelt.de/_assets/50274901be30f02a74e08c8b9…/Themes/custom/aimeos-custom.js?1790670970

js rossmann-fotowelt.de collected 2026-10-02 07:43:55 UTC 20,126 bytes, 417 lines download raw bytes

1$(document).ready(function() {
2
3    /* TYPO-4106: work around an Aimeos core bug in basket-standard.js. Its onSubmit()/
4       onChange() handlers swap in the AJAX-updated basket markup via $(".basket-standard").
5       html(...), but Aimeos also tags its own per-component <link>/<script> asset tags
6       with that same bare class for on-demand CSS/JS loading (AimeosBasket.updateBasket()
7       itself correctly scopes to ".aimeos.basket-standard" when parsing the response - the
8       bug is only in how the result gets applied back to the live page). That selector match
9       corrupts the DOM by inserting the new basket markup as children of those <link>/
10       <script> elements too, on every quantity/basket update. Removing the class from the
11       live page's asset tags is harmless (the browser only uses rel/href and src to load
12       them, never the class) and keeps them out of that selector's match set, without
13       touching Aimeos core. */
14    $('head link.basket-standard, head script.basket-standard').removeClass('basket-standard');
15
16    /* TYPO-4106: work around a second Aimeos core bug. AimeosBasket.updateBasket() moves
17       the <script class="basket-standard"> tag into the basket section on the FIRST AJAX
18       update (guarded by body.hasClass('basket'), evidently meant to run once), and also
19       unconditionally (every single call, no guard at all) appends any
20       <link class="basket-standard"> tags into the basket section too. The <script>
21       re-execution is the more serious of the two: when onSubmit()/onChange() insert that
22       returned markup via $(...).html(...), jQuery re-executes any <script> tags it
23       contains - redefining the global AimeosBasketStandard object and calling its init()
24       again, which binds a SECOND, permanent set of submit/click/focusin handlers
25       (confirmed via $._data(document, 'events') - handler count doubles after the first
26       AJAX update). Every basket interaction after that point fires twice. The unguarded
27       <link> append has no such functional effect (a <link> doesn't "execute" the way a
28       <script> does), but because it runs on every single update it accumulates a fresh
29       duplicate <link class="basket-standard"> DOM node in the basket section on every
30       quantity/basket change, bloating the DOM and repeating the CSS fetch each time.
31       Since our page already loads and runs basket-standard.js normally via its initial
32       <script defer> tag, and already loads the matching summary.css via its own initial
33       <link> tag in <head>, neither of updateBasket()'s re-insertions is ever needed here -
34       stripping both the script and the link from the returned fragment
35       (AimeosBasket.updateBasket is looked up by reference on every call, so patching it
36       here works no matter the relative script load order) prevents both the duplicate
37       binding and the DOM/asset bloat, without touching Aimeos core. */
38    if (typeof AimeosBasket !== 'undefined' && AimeosBasket.updateBasket) {
39        var origUpdateBasket = AimeosBasket.updateBasket.bind(AimeosBasket);
40        AimeosBasket.updateBasket = function (data) {
41            var $basket = origUpdateBasket(data);
42            $basket.find('script.basket-standard').remove();
43            $basket.find('link.basket-standard').remove();
44            return $basket;
45        };
46    }
47
48    /* TYPO-4106: the basket AJAX round-trip now completes so quickly that Aimeos's own
49       spinner (Aimeos.createSpinner()/removeSpinner(), called by basket-standard.js) can
50       be added and removed within a single frame, making it effectively invisible. Wrap
51       both so the spinner stays visible for a minimum duration regardless of how fast the
52       request actually is. Both are looked up by reference on every call inside Aimeos's
53       code, so patching them here works no matter the relative script load order.
54
55       Also use this same wrapper to disable the basket form's buttons/inputs while a
56       request is in flight - Aimeos's onSubmit()/onChange() have no re-entrancy guard at
57       all, so a second click before the first request finishes fires a second, overlapping
58       request. */
59    if (typeof Aimeos !== 'undefined' && Aimeos.createSpinner && Aimeos.removeSpinner) {
60        var origCreateSpinner = Aimeos.createSpinner.bind(Aimeos);
61        var origRemoveSpinner = Aimeos.removeSpinner.bind(Aimeos);
62        var spinnerShownAt = 0;
63        var MIN_SPINNER_MS = 400;
64        var $basketControls = null;
65
66        Aimeos.createSpinner = function () {
67            spinnerShownAt = Date.now();
68            $basketControls = $('.basket-standard button, .basket-standard input[type="submit"], .basket-standard a.change')
69                .not(':disabled').prop('disabled', true);
70            origCreateSpinner();
71        };
72
73        Aimeos.removeSpinner = function () {
74            var wait = Math.max(0, MIN_SPINNER_MS - (Date.now() - spinnerShownAt));
75            setTimeout(function () {
76                origRemoveSpinner();
77                if ($basketControls) {
78                    $basketControls.prop('disabled', false);
79                    $basketControls = null;
80                }
81            }, wait);
82        };
83    }
84
85    /* overwrite/add checkout functions */
86    if (typeof AimeosCheckoutStandard != 'undefined') {
87        AimeosCheckoutStandard.hideFeLogin = function () {
88            $('.frame-type-felogin_login').hide();
89        }
90
91        AimeosCheckoutStandard.showFeLogin = function () {
92            let fe_form = $('.frame-type-felogin_login').detach();
93            const urlSearchParams = new URL(window.location).searchParams;
94            $('#feLoginContainer').append(fe_form);
95            $('.frame-type-felogin_login').show();
96            $('.frame-type-felogin_login').css('padding-top', '0');
97            $('.frame-type-felogin_login .createNewAccount').detach();
98            if ($('.error-list').length == 0 && !urlSearchParams.get('ai[c_step]')) {
99                $('.checkout-standard-address > .button-group').removeClass('d-flex')
100            }
101        }
102    }
103
104    /* on page summary */
105    if ($('#option-account').length > 0) {
106
107        /* show / hide account inout fields */
108        $('#option-account').on('change', ev => {
109            let ele = ev.currentTarget;
110            if ($(ele).is(':checked')) {
111                $('#csOptionAccountName').show();
112            } else {
113                $('#csOptionAccountName').hide();
114            }
115        });
116
117        /* check account inputs if form is submit */
118        $('.aimeos form:first').on('submit', ev => {
119
120            if ($('#option-account').is(':checked')) {
121                $('#csOptionAccountName span').hide();
122                $('#csOptionAccountName input').removeClass('error');
123                if ($('#option-account-name').val() == '') {
124                    ev.preventDefault();
125                    $('.btn-action').removeClass('load');
126                    $('.checkout-standard-summary-option')[0].scrollIntoView();
127                    $('#csOptionAccountName span#UNAME_EMPTY').show();
128                    $('#option-account-name').addClass('error');
129                }
130                let pwdCheck = $('#option-account-password').val().match(/^[0-9a-z\;\/\(\)\&\*\?\+\-\.\!\$]{6,20}$/gi);
131
132                if (!pwdCheck || $('#option-account-password').val() != $('#option-account-password-repeat').val()) {
133                    ev.preventDefault();
134                    $('.btn-action').removeClass('load');
135                    $('.checkout-standard-summary-option')[0].scrollIntoView();
136                    $('#csOptionAccountName span#PWD_EMPTY').show();
137                    $('#option-account-password').addClass('error');
138                    if ($('#option-account-password').val() != $('#option-account-password-repeat').val()) {
139                        $('#option-account-password-repeat').addClass('error');
140                    }
141                }
142            }
143        });
144
145        /* PWD counter */
146        $('#option-account-password').on('keyup', ev => {
147            $('.password-container').attr('data-after',  $('#option-account-password').val().length+ '/20');
148        });
149
150        /* if ecce login exists */
151        if ($('.checkout-standard-summary').length > 0 && $('.error-item:first').html() == 'LOGIN_EXISTS') {
152
153            $('.error-list').detach();
154            $('#csOptionAccountName')[0].scrollIntoView();
155            $('#csOptionAccountName span').hide();
156            $('#csOptionAccountName span#UNAME_LOGIN_EXISTS').show();
157            $('#option-account-name').addClass('error');
158
159        }
160
161        $('.password-helptext-btn').on('click', ev => {
162            ev.preventDefault();
163            let ele = ev.currentTarget;
164            $(ele).parent().next().toggle('slow');
165        });
166
167    }
168
169
170    /* on address page: address layout hack */
171    $('#addressContainer').hide();
172
173    $('#guestShowAddressBtn').on('click', ev => {
174        ev.preventDefault();
175        $('#addressContainer').show()[0].scrollIntoView();
176        $('.checkout-standard-address > .button-group').addClass('d-flex')
177    })
178
179    if ($('#addressContainer').length > 0) {
180
181        const urlSearchParams = new URL(window.location).searchParams;
182        if ($('#addressContainer').hasClass('loggedin') || urlSearchParams.get('ai[c_step]') == 'address') {
183            $('#addressContainer').show()[0];
184            $('.checkout-standard-address > .button-group').addClass('d-flex');
185        }
186
187        if ($('.error-list').length > 0) {
188            let error = $('.error-list').detach();
189            $('#addressContainer .note').prepend(error);
190            $('#addressContainer').show()[0].scrollIntoView();
191            $('.checkout-standard-address > .button-group').addClass('d-flex')
192        }
193    }
194
195    /* on detail page: PDS gallery more button */
196    if ($('#moreImagesBtn').length > 0) {
197        $('#moreImagesBtn').on('click', ev => {
198            let el = ev.target
199            if ( $(el).hasClass('active')) {
200                $(el).removeClass('active');
201                $('.catalog-detail-images-small').removeClass('active');
202                $('.catalog-detail-images-small-more').removeClass('active');
203            } else {
204                $(el).addClass('active');
205                $('.catalog-detail-images-small').addClass('active');
206                $('.catalog-detail-images-small-more').addClass('active');
207            }
208        })
209    }
210
211    /* overwrite/add catalog functions */
212    if (typeof AimeosCatalogFilter != 'undefined') {
213        AimeosCatalogFilter.onMenuHover = function () {
214
215
216            $(".catalog-filter-tree .close").on('click', ev => {
217                $('.catalog-filter-tree .cat-item').removeClass('hover');
218                //$('.catalog-filter-tree .cat-item .submenu').removeClass('opened');
219            });
220
221            const $dropdowns = $('.level-1 .cat-link').not('.detailLink');
222
223            $dropdowns.on('click touchend', ev => {
224
225                let mobile = false;
226                let $this = $(ev.currentTarget.parentElement.parentElement);
227
228                if ($this.hasClass('mainnavimobile')) {
229                    mobile = true;
230                    $this = $(ev.currentTarget.parentElement);
231                }
232
233                if ($this.children('.submenu').length > 0) {
234                    ev.preventDefault();
235                } else {
236                    return;
237                }
238
239                if (mobile) {
240                    $('.submenu.opened').removeClass('opened');
241                    $this.addClass('hover');
242                    $this.children('.submenu').addClass('opened');
243
244                    var aTag = $this.children('#mainnavi-mobile .submenu');
245                    $this.children('#mainnavi-mobile .submenu').get(0).scrollIntoView();
246                    return;
247                }
248
249                if ($this.hasClass('hover')) {
250                    return;
251                }
252                if ($this.prop('hoverTimeout')) {
253                    $this.prop('hoverTimeout', clearTimeout($this.prop('hoverTimeout')));
254                }
255                $this.prop('hoverIntent', setTimeout(() => {
256                    $this.addClass('hover');
257                    $this.children('.submenu').addClass('opened');
258                }));
259
260
261            });
262            /*.on('mouseleave', ev => {
263            var $this = $(ev.currentTarget);
264            if ($this.prop('hoverIntent')){
265                $this.prop('hoverIntent', clearTimeout($this.prop('hoverIntent')));
266            }
267            $this.prop('hoverTimeout', setTimeout(() => {
268                $this.removeClass('hover');
269            }));
270        });*/
271        }
272    }
273
274    if (typeof AimeosAccountHistory != 'undefined') {
275        AimeosAccountHistory.onToggleDetail = function () {
276
277            this.renderAddress = function(adr) {
278
279                if (typeof adr == 'undefined') {
280                    return '';
281                }
282
283                return (typeof adr.title != 'object' ? adr.title : '') + ' ' + adr.firstname + ' ' + adr.lastname + '<br/>' + (typeof adr.company1 != 'object' ? adr.company1 + '<br/>' : '') + adr.street + '<br/>' + adr.zip + ' ' + adr.city + '<br/>' + adr.country + '<p>' + (typeof adr.email != 'object' ? adr.email : '') + '</p>';
284            };
285
286            this.loadedOrders = [];
287            const that = this;
288
289            this.render = function (ele, data) {
290
291                const b = data.buyer;
292                const d = data.delivery_recipient;
293
294                $('.common-summary-address .payment .content', ele).html(this.renderAddress(b));
295
296                $('.common-summary-address .delivery .content', ele).html(this.renderAddress(d));
297
298                let details = '';
299
300                $.each(data.order_lines.order_line, (key, value) => {
301
302                    details += '<tr><td data-th="Pos.">' + (key + 1) + '</td>' +
303                        '<td data-th="Bezeichnung">' + value.text + '</td>' +
304                        '<td data-th="Artikel-Nr.">' + value.product_id + '</td>' +
305                        '<td data-th="Anzahl">' + value.quantity + '</td>' +
306                        '<td data-th="Preis">' + value.price.single.replace('.', ',') + ' €</td>' +
307                        '<td data-th="Summe">' + value.price.amount.replace('.', ',') + ' €</td></tr>';
308                });
309
310                $('.common-summary-detail tbody', ele).html(details);
311                $('.common-summary-detail .sum-order-value', ele).html(data.price.amount.replace('.', ',') + ' €');
312                $('.common-summary-detail .sum-order-tax', ele).html( $('.common-summary-detail .sum-order-tax', ele).html().replace('tax-rate', data.vats.vat.vatpercent.replace('.', ',') + '%'));
313                $('.common-summary-detail .sum-order-tax-value', ele).attr('data-th', $('.common-summary-detail .sum-order-tax', ele).html().replace('tax-rate', data.vats.vat.vatpercent.replace('.', ',') + '%'));
314                $('.common-summary-detail .sum-order-tax-value', ele).html(data.vats.vat.vatamount.replace('.', ',') + ' €');
315
316            }
317
318            $(".account-history").on("click", ".history-item .action .btn-action:not(.withdrawal)", ev => {
319
320                const target = $(ev.currentTarget).closest(".history-item");
321                const details = $(".account-history-detail", target);
322                const orderId = $(ev.currentTarget).attr('data-order-id');
323                const orderLoaded = that.loadedOrders.find((_orderId) => {
324                    return _orderId == orderId
325                });
326
327                if (!orderLoaded && !$(".btn-action.show", target).hasClass('hidden')) {
328
329                    let url = new URL(window.location.origin + '/jsonapi?');
330                    url.search = 'ai%5Baction%5D=get&ai%5Bcontroller%5D=Jsonapi&ai%5Bresource%5D=history&ai%5Borderid%5D=' + orderId
331
332                    $(".order-basic", target).append('<span class="order-loader"></span>');
333
334                    fetch(url).then(response => {
335                        return response.json();
336                    }).then(data => {
337                        that.render(details[0], data.detail);
338                        that.loadedOrders.push(orderId);
339
340                        $(".btn-action.show", target).toggleClass('hidden');
341                        $(".btn-action.close", target).toggleClass('hidden');
342                        slideToggle(details[0], 300);
343
344                        const lines = data.detail && data.detail.order_lines && data.detail.order_lines.order_line;
345                        const arr = Array.isArray(lines) ? lines : (lines ? [lines] : []);
346                        const eligible = arr.some(l => l && l.producttypeid === 'thirdparty');
347                        const wbtn = $(".btn-action.withdrawal", target);
348                        if (eligible) {
349                            const inv = wbtn.attr('data-invoice-number') || '';
350                            const zip = (data.detail.buyer && data.detail.buyer.zip) || '';
351                            const email = (data.detail.buyer && data.detail.buyer.email) || '';
352                            wbtn.attr('href', '/widerruf?ordernumber=' + encodeURIComponent(inv)
353                                + '&zip=' + encodeURIComponent(zip) + '&email=' + encodeURIComponent(email));
354                            wbtn.removeClass('hidden');
355                        } else {
356                            $(".no-withdrawal-hint", target).removeClass('hidden');
357                        }
358                    }).catch(() => {}).finally(() => { $(".order-loader", target).remove(); });
359
360                } else {
361                    $(".btn-action.show", target).toggleClass('hidden');
362                    $(".btn-action.close", target).toggleClass('hidden');
363                    slideToggle(details[0], 300);
364                }
365
366
367                return false;
368            });
369
370        }
371    }
372
373    if (typeof AimeosCheckoutStandard != 'undefined') {
374        AimeosCheckoutStandard.setupAddress = function () {
375            $(".checkout-standard-address .item-address").has(".header input:not(:checked)").find(".form-list").hide();
376
377            $(".checkout-standard-address-payment .header input, .checkout-standard-address-delivery .header input").on("click", function (ev) {
378                $(".checkout-standard-address .item-address").has(".header input:not(:checked)").find(".form-list").each(function () {
379                    slideUp(this, 300);
380                });
381                $(".form-list", $(ev.currentTarget).parents(".item-address")).each(function () {
382                    slideDown(this, 300);
383                });
384            });
385        }
386        AimeosCheckoutStandard.setupAddress();
387    }
388
389    /* scrollConfig */
390    let scrollConfig = document.getElementById('scrollConfig');
391    let scrollConfigProduct = document.getElementById('scrollConfigProduct');
392    if (scrollConfig) {
393        if (scrollConfigProduct.children.length == 0 && document.getElementsByClassName('rm-btn-primary btn-action').length > 0) {
394            node = document.getElementsByClassName('price-item default')[0].cloneNode(true);
395            scrollConfigProduct.appendChild(node)
396            node = document.getElementsByClassName('rm-btn-primary btn-action')[0].cloneNode(true);
397            node.setAttribute('id','btn-action-scroll');
398            node.addEventListener('click',(ev) => {
399               ev.preventDefault();
400                document.getElementsByClassName('rm-btn-primary btn-action')[1].click()
401            });
402            scrollConfigProduct.appendChild(node)
403        }
404        document.addEventListener('scroll', (ev) => {
405            if (ev.target.scrollingElement.scrollTop > 450) {
406                scrollConfig.style.display = 'block';
407            } else {
408                scrollConfig.style.display = 'none';
409            }
410        })
411
412    }
413
414    /* mobile navi hack to add aimeos navi to the main navi of typo3/bootstrap */
415    $('.navbar-nav.mainnavimobile:first-of-type').prepend($('.aimeos-category-mobile-navi-level-1').html());
416
417});

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.