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.