1/* 2 * @category MSP 3 * @editor Tommy Köster 4 * @copyright 2026 - MSP Medien Systempartner GmbH & Co. KG 5 * @license http://www.medien-systempartner.de/ Commercial 6 * @link www.medien-systempartner.de 7 * @updated 24.06.26, 12:52 8 */ 9 10let enableTracking = true; 11 12document.addEventListener('click', clickEvents); 13 14function clickEvents(event) { 15 let element = event.target; 16 if (Vrm.parentHasClass(element, 'faqCatTitleBox')) { 17 element = Vrm.parentHasClass(element, 'faqCatTitleBox'); 18 Vc.Externallib.triggerFaqCat(element); 19 } 20 if (Vrm.parentHasClass(element, 'faqTitleBox')) { 21 element = Vrm.parentHasClass(element, 'faqTitleBox'); 22 Vc.Externallib.triggerFaq(element); 23 } 24 if (element.id === 'reasons_submit_btn') { 25 let reason = ''; 26 let form = document.getElementById('reasons_form'); 27 reason = form.querySelector('input[name="lieferendeGrund"]:checked').value; 28 let data = Vrm.Tracking.Functions.selectReason(reason); 29 Vrm.Tracking.Functions.pageViewPush(data); 30 } 31} 32 33Vrm.Tracking = Vrm.Tracking || {}; 34Vrm.Tracking.Functions = Vrm.Tracking.Functions || { 35 36 logVirtualPageView: function (data) { 37 if (!data || data.event !== 'VirtualPageView') { 38 return; 39 } 40 41 const now = new Date(); 42 const loggingStart = new Date('2026-06-01T00:00:00+02:00'); 43 const loggingEnd = new Date('2026-06-08T00:00:00+02:00'); 44 45 if (now < loggingStart || now >= loggingEnd) { 46 return; 47 } 48 49 const payload = { 50 timestamp: new Date().toISOString(), 51 timestampLocal: now.toLocaleString('sv-SE', { 52 timeZone: 'Europe/Berlin', 53 year: 'numeric', 54 month: '2-digit', 55 day: '2-digit', 56 hour: '2-digit', 57 minute: '2-digit', 58 second: '2-digit' 59 }), 60 browserTimestamp: Date.now(), 61 pageUrl: window.location.href, 62 referrer: document.referrer, 63 userAgent: navigator.userAgent, 64 data: data 65 }; 66 67 let postData = { 68 controller: 'logVirtualPageView', 69 data: payload 70 } 71 72 try { 73 Vrm.ajax( 74 postData, 75 window.location.origin + '/vrmtemplate/ajax/log' 76 ).then(function (response) { 77 console.log('[Tracking Debug] Log response:', response.status, response.statusText); 78 if (!response.ok) { 79 console.warn('[Tracking Debug] Log request failed with HTTP status:', response.status); 80 } 81 }).catch(function (error) { 82 console.warn('[Tracking Debug] VirtualPageView log failed:', error); 83 }); 84 } catch (error) { 85 console.warn('[Tracking Debug] VirtualPageView log could not be sent:', error); 86 } 87 }, 88 89 pageViewPush: function (data) { 90 if (enableTracking) { 91 window.dataLayer = window.dataLayer || []; 92 window.dataLayer.push(data); 93 } 94 }, 95 96 getVirtualPageData: function (title = '',prevPage = '') { 97 let loginStatus = 'logged_out'; 98 if (typeof Vc !== 'undefined' && Vc.isLoggedIn) { 99 loginStatus = 'logged_in'; 100 } 101 102 if (title === '') { 103 title = document.title; 104 } 105 if (prevPage === '') { 106 prevPage = document.referrer; 107 } 108 return { 109 'event':'VirtualPageView', 110 'virtualPageURI': window.location.pathname + window.location.search, 111 'virtualPageURL': window.location.href || document.documentURI, // full URL 112 'virtualPageTitle' : title, 113 'virtualPreviousPage': prevPage, // previous page, from which user come to current page 114 'login_status': loginStatus 115 }; 116 }, 117 118 /** PRÃFEN OB ES DIESES EVENT ÃBERHAUPT GIBT */ 119 getViewOfProduct: function (product) { 120 return { 121 'event': 'view_item', 122 'ecommerce': { 123 'items': [{ 124 'item_id': product.sku, 125 'item_name': product.name, 126 'currency': "EUR", 127 'item_brand': product.pva, 128 'item_category': product.kind_of_product, 129 'item_category2': product.praemie, //Prämie, falls vorhanden 130 'price': Vrm.Tracking.Functions.roundPrice(product.price), 131 'quantity': product.quantity 132 }] 133 } 134 } 135 }, 136 137 roundPrice: function (num) { 138 if (num === 'Ohne Laufzeit') { 139 return num; 140 } 141 return (Math.round(num * 100) / 100).toFixed(2); 142 }, 143 144 getSuccessOrderData: function (data) { 145 let paymentMethod = Vrm.Tracking.Functions.mapPaymentMethod(data.paymentMethod); 146 147 let resultNew = { 148 'transaction_id': data.transactionId, 149 'email': data.email, 150 'affiliation': data.werbeaktionscodierung, 151 'value': Vrm.Tracking.Functions.roundPrice(data.transactionTotal), 152 'total_value': Vrm.Tracking.Functions.roundPrice(data.gesamtumsatz), 153 'tax': data.transactionTax, 154 'user_type': data.user_type, 155 'payment_frequent': data.paymentFrequent, 156 'payment_method': paymentMethod, 157 'currency': 'EUR', 158 'items': [ 159 { 160 'item_id': data.transactionProducts[0].sku, 161 'item_id2': data.transactionProducts[0].campaignSku, 162 'item_name': data.transactionProducts[0].name, 163 'affiliation': data.werbeaktionscodierung, 164 'currency': 'EUR', 165 'item_brand': data.transactionProducts[0].pva, 166 'item_category': data.transactionProducts[0].kind_of_product, 167 'item_catgory2': data.transactionProducts[0].praemie, 168 'price': Vrm.Tracking.Functions.roundPrice(data.transactionProducts[0].price), 169 'quantity': data.transactionProducts[0].quantity, 170 } 171 ] 172 } 173 174 if (data.transactionProducts[1] !== undefined) { 175 let tablet = { 176 'item_id': data.transactionProducts[1].sku, 177 'item_name': data.transactionProducts[1].fullname, // Voller Name inkl. Varianten 178 'affiliation': data.werbeaktionscodierung, 179 'currency': 'EUR', 180 'item_brand': data.transactionProducts[1].name, // Modell 181 'item_category': 'Tablet', // Tablet 182 'item_variant': data.transactionProducts[1].variant, // Varianten 183 'price': Vrm.Tracking.Functions.roundPrice(data.transactionProducts[1].price), 184 'quantity': data.transactionProducts[1].quantity, 185 } 186 resultNew.items.push(tablet); 187 } 188 189 if (data.hostname_herkunft) { 190 resultNew['hostname_herkunft'] = data.hostname_herkunft; 191 } 192 if (data.articleOrigin) { 193 resultNew['articleOrigin'] = data.articleOrigin; 194 } 195 196 return { 197 'event': 'purchase', 198 'ecommerce': resultNew, 199 }; 200 }, 201 202 mapPaymentMethod: function (paymentMethod) { 203 switch(paymentMethod) { 204 case 'checkmo': 205 return 'Rechnung'; 206 case 'creditcard': 207 return 'Kreditkarte'; 208 case 'debitpayment': 209 return 'Lastschrift';
210 case 'paypal': 211 return 'Paypal'; 212 case 'google_pay': 213 return 'GooglePay'; 214 case 'apple_pay': 215 return 'ApplePay'; 216 case 'free': 217 return 'Kostenlos'; 218 default: 219 return ''; 220 } 221 }, 222 223 getCheckoutSteps: function(step,product) { 224 return { 225 'event': 'checkout', 226 'ecommerce': { 227 'checkout': { 228 'actionField': { 229 'step': step 230 }, 231 'products': [{ 232 'name': product.name, 233 'id': product.id, 234 'price': Vrm.Tracking.Functions.roundPrice(product.price), 235 'category': product.category, 236 'quantity': 1 237 }] 238 } 239 } 240 } 241 }, 242 243 getPlzForPva: function () { 244 let element = document.getElementById('plz'); 245 if (element) { 246 return { 247 'event':'sucheAusgabe', 248 'plz': element.value 249 }; 250 } 251 return false; 252 }, 253 254 login: function (sso_id) { 255 return { 256 'event': 'Login', 257 'userId': sso_id, 258 } 259 }, 260 261 removeFromCart: function (data,product) { 262 if (product !== undefined) { 263 return { 264 'event': 'removeFromCart', 265 'ecommerce': { 266 'items': [{ // removing a product to a shopping cart. 267 'item_id': data.sku, 268 'item_name': data.fullname, // Voller Name inkl. Varianten 269 'affiliation': product.werbeaktionscodierung, 270 'currency': 'EUR', 271 'item_brand': data.name, // Modell 272 'item_category': 'Tablet', // Tablet 273 'item_variant': data.variant, // Varianten 274 'price': Vrm.Tracking.Functions.roundPrice(data.priceBol), 275 'quantity': 1, 276 }] 277 } 278 }; 279 } 280 }, 281 282 getProductImpressions: function (data,siteType) { 283 let items = []; 284 data.forEach(fillImpression); 285 286 function fillImpression(productObj) { 287 let item = { 288 'item_id': productObj.sku, // Name or ID is required. 289 'item_name': productObj.name, 290 'currency': 'EUR', 291 'index': productObj.pos, 292 'item_brand': productObj.pva, 293 'item_category': productObj.kind_of_product, 294 'item_category2': productObj.praemie, 295 'item_list_name': siteType, 296 'price': Vrm.Tracking.Functions.roundPrice(productObj.price), 297 'quantity': productObj.quantity 298 } 299 items.push(item); 300 } 301 302 return { 303 'event': 'view_item_list', 304 'ecommerce': { 305 'items': items 306 } 307 } 308 }, 309 310 beginCheckout: function(product) { 311 let result = { 312 'event': 'begin_checkout', 313 'ecommerce': { 314 'items': [ 315 { 316 'item_id': product.sku, 317 'item_name': product.name, 318 'affiliation': product.affiliation, // Werbeaktionscodierung 319 'currency': "EUR", 320 'item_brand': product.pva, 321 'item_category': product.kind_of_product, 322 'item_category2': product.praemie, //Prämie, falls vorhanden 323 'price': Vrm.Tracking.Functions.roundPrice(product.price), 324 'quantity': product.quantity 325 }] 326 } 327 } 328 329 if (product.reason !== undefined) { 330 result.ecommerce.items[0].reason = product.reason; 331 } 332 333 return result; 334 }, 335 336 /** VRMONLKUEN-45 - Auswahl des Kündigungsgrunds */ 337 selectReason: function(reason) { 338 return { 339 'event': 'selectReason', 340 'reason': reason, 341 } 342 }, 343 344 getProductClick: function(productObj,selPva = '') { 345 let pva = productObj.pva; 346 if (selPva !== '') { 347 pva = selPva; 348 } 349 350 return { 351 'event': 'select_item', 352 'ecommerce': { 353 'items': [{ 354 'item_id': productObj.sku, // Name or ID is required. 355 'item_name': productObj.name, 356 'currency': 'EUR', 357 'index': productObj.pos, 358 'item_brand': pva, 359 'item_category': productObj.kind_of_product, 360 'item_category2': productObj.praemie, 361 'price': Vrm.Tracking.Functions.roundPrice(productObj.price), 362 'quantity': productObj.quantity 363 }] 364 }, 365 }; 366 }, 367 368 paymentFrequent: function(val) { 369 return { 370 'event':'choosePaymentFrequent', 371 'ecommerce': { 372 'paymentFrequent': val, 373 } 374 } 375 }, 376 377 getNavigationClick: function(click) { 378 return { 379 'event': 'Navigation', 380 'eventAction': 'Klick auf Navigation', 381 'eventLabel': click, 382 }; 383 }, 384 385 getButtonClick: function(click) { 386 return { 387 'event': 'Buttons', 388 'eventAction': 'Klick auf Buttons', 389 'eventLabel': click, 390 }; 391 }, 392 393 shareInteraction: function (text,link) { 394 return { 395 'ShareButton': text, 396 'socialAction':'Teilen', 397 'event':'shareInteraction', 398 'socialTarget': link 399 }; 400 }, 401 402 getFooterClick: function (text) { 403 return { 404 'event':'footer_click', 405 'footer_link': text, 406 }; 407 }, 408 409 tradeTracker: function(data) { 410 if (Vrm.tt !== undefined && Vrm.tt.cid !== undefined && Vrm.tt.pid !== undefined) { 411 ttConversionOptions.push({ 412 type: 'sales', 413 campaignID: Vrm.tt.cid, 414 productID: Vrm.tt.pid, 415 transactionID: data.transactionId, 416 transactionAmount: Vrm.Tracking.Functions.roundPrice(data.transactionTotal), 417 quantity: '1', 418 descrMerchant: '', 419 descrAffiliate: '', 420 vc: '', 421 currency: '' 422 }); 423 (function (ttConversionOptions) { 424 let campaignID = 'campaignID' in ttConversionOptions ? ttConversionOptions.campaignID : 425 ('length' in ttConversionOptions && ttConversionOptions.length ? ttConversionOptions[0].campaignID : null) 426 427 let tt = document.createElement('script'); 428 tt.type = 'text/javascript'; 429 tt.async = true; 430 tt.src = '//tm.tradetracker.net/conversion?s=' + encodeURIComponent(campaignID) + '&t=m'; 431 let s = document.getElementsByTagName('script'); 432 s = s[s.length - 1]; 433 s.parentNode.insertBefore(tt, s); 434 })(ttConversionOptions); 435 } 436 }, 437}; 438Vrm.Tracking.Variables = Vrm.Tracking.Variables || {}; 439 440Vc.Externallib = { 441 442 addToCart: function (data) { 443 return { 444 'event': 'addToCart', 445 'ecommerce': { 446 'currencyCode': 'EUR', 447 'add': { // 'add' actionFieldObject measures. 448 'products': [{ // adding a product to a shopping cart. 449 'name': data.name, 450 'id': data.id, 451 'price': data.price, 452 'category': data.category, 453 'quantity': 1 454 }] 455 } 456 } 457 }; 458 }, 459 460 closeElement: function (box, isCategory = false) { 461 const textBox = box.querySelector(isCategory ? '.faqCatTextBox' : '.faqTextBox'); 462 const buttonId = box.getAttribute('data-id'); 463 const button = box.querySelector('button[data-id="' + buttonId + '"]'); 464 465 button.setAttribute('aria-expanded', 'false'); 466 467 // Falls noch ein alter Handler "in der Luft" hängt, sauber entfernen 468 if (textBox._onMaxHeightEnd) { 469 textBox.removeEventListener('transitionend', textBox._onMaxHeightEnd); 470 textBox._onMaxHeightEnd = null; 471 } 472 473 // Handler, der genau einmal nach Ende der max-height Transition feuert 474 textBox._onMaxHeightEnd = function (e) { 475 if (e.propertyName !== 'max-height') return; 476 textBox.style.display = 'none'; 477 478 textBox.removeEventListener('transitionend', textBox._onMaxHeightEnd); 479 textBox._onMaxHeightEnd = null; 480 }; 481 482 textBox.addEventListener('transitionend', textBox._onMaxHeightEnd); 483 484 // Transition starten 485 textBox.style.maxHeight = '0'; 486 487 box.classList.remove('active'); 488 }, 489 490 openElement: function(box, isCategory = false) { 491 const textBox = box.querySelector(isCategory ? '.faqCatTextBox' : '.faqTextBox'); 492 const buttonId = box.getAttribute('data-id'); 493 const button = box.querySelector('button[data-id="' + buttonId + '"]'); 494 button.setAttribute('aria-expanded', 'true'); 495 textBox.style.removeProperty('display'); 496 setTimeout(() => { 497 textBox.style.maxHeight = '100vh'; 498 }, 0); 499 box.classList.add('active'); 500 // if (isCategory) { 501 // box.setAttribute('tabindex', '0'); 502 // } 503 }, 504 505 closeOtherElements: function(currentId, selector) { 506 document.querySelectorAll(selector + '.active').forEach(activeBox => { 507 if (activeBox.getAttribute('data-id') !== currentId) { 508 this.closeElement(activeBox, selector === '.faqCatBox'); 509 } 510 }); 511 }, 512 513 triggerFaqCat: function(element) { 514 const faqId = element.getAttribute('data-id'); 515 this.closeOtherElements(faqId, '.faqCatBox'); 516 517 const box = document.querySelector('.faqCatBox[data-id="' + faqId + '"]'); 518 if (box.classList.contains('active')) { 519 this.closeElement(box, true); 520 } else { 521 this.openElement(box, true); 522 } 523 }, 524 525 triggerFaq: function(element) { 526 const faqId = element.getAttribute('data-id'); 527 this.closeOtherElements(faqId, '.faqBox'); 528 529 const box = document.querySelector('.faqBox[data-id="' + faqId + '"]'); 530 if (box.classList.contains('active')) { 531 this.closeElement(box); 532 } else { 533 this.openElement(box); 534 } 535 } 536}; 537 538document.addEventListener('readystatechange', function (){ 539 if (document.readyState === 'complete') { 540 let pathname = window.location.pathname.split('/'); 541 if (pathname[1] !== undefined && pathname[1] === 'abschluss') { 542 return false;
543 } else if(pathname[2] !== undefined && pathname[2] === 'abschluss') { 544 return false; 545 } 546 let data = Vrm.Tracking.Functions.getVirtualPageData(); 547 Vrm.Tracking.Functions.pageViewPush(data); 548 549 /** VRMBFSG-8 - AUDIT-36 - Fokus bei Cookie-Banner muss direkt in das Modal springen */ 550 551 let cmpID = 'cmpbox'; 552 553 let cmpElement = document.getElementById(cmpID); 554 555 if (cmpElement) { 556 if (cmpElement.classList.contains('cmpboxclosed') === false) { 557 // Sucht nach dem ersten Link (mit href) oder Button innerhalb des Elements 558 let firstInteractiveElement = cmpElement.querySelector('a[href], button'); 559 560 // Wenn ein Element gefunden wurde, Fokus setzen 561 if (firstInteractiveElement) { 562 firstInteractiveElement.focus(); 563 } 564 } 565 } 566 } 567});
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.