1var AEC = (function() 2{ 3 return { 4 debug: false, 5 eventCallback: true, 6 ajax: function(context, dataLayer) 7 { 8 let element = context, qty = 1, variant = [], variant_attribute_option = [], products = []; 9 10 document.querySelectorAll('input[name=qty]:checked, [name=qty]').forEach(element => 11 { 12 qty = element.value; 13 }); 14 15 qty = Math.abs(qty); 16 17 if (isNaN(qty)) 18 { 19 qty = 1; 20 } 21 22 if (!AEC.gtm()) 23 { 24 /** 25 * Invoke original click event(s) 26 */ 27 if (element.dataset.click) 28 { 29 /** 30 * Track time 31 */ 32 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 33 34 eval(element.dataset.click); 35 } 36 37 return true; 38 } 39 40 if(element.dataset.configurable) 41 { 42 var variants = []; 43 44 document.querySelectorAll('[name^="super_attribute"]').forEach(attribute => 45 { 46 if (attribute.matches('select')) 47 { 48 var name = attribute.getAttribute('name'), id = name.substring(name.indexOf('[') + 1, name.lastIndexOf(']')); 49 50 if (attribute.selectedIndex) 51 { 52 var option = attribute.options[attribute.selectedIndex]; 53 54 if (option) 55 { 56 variants.push( 57 { 58 id: id, 59 option: option.label, 60 text: option.text 61 });
62 } 63 } 64 } 65 }); 66 67 68 /** 69 * Colour Swatch support 70 */ 71 if (!variants.length) 72 { 73 Object.entries(AEC.SUPER).forEach(([key, attribute]) => 74 { 75 var swatch = document.querySelectorAll('div[attribute-code="' + attribute.code + '"], div[data-attribute-code="' + attribute.code + '"]'); 76 77 swatch.forEach(element => 78 { 79 let variant = 80 { 81 id: attribute.id, 82 text: '', 83 option: null 84 }; 85 86 var select = element.querySelector('select'); 87 88 if (select) 89 { 90 if (select.selectedIndex) 91 { 92 var option = select.options[select.selectedIndex]; 93 94 if (option) 95 { 96 variant.text = option.text; 97 variant.option = option.value; 98 } 99 } 100 } 101 else 102 { 103 var span = element.querySelector('span.swatch-attribute-selected-option'); 104 105 if (span) 106 { 107 variant.text = span.innerHTML; 108 variant.option = span.parentNode.dataset.optionSelected 109 } 110 } 111 112 variants.push(variant); 113 }); 114 }); 115 } 116 117 if (!variants.length) 118 { 119 AEC.EventDispatcher.trigger('ec.variants', variants); 120 } 121 122 var SUPER_SELECTED = []; 123 124 for (i = 0, l = variants.length; i < l; i++) 125 { 126 for (a = 0, b = AEC.SUPER.length; a < b; a++) 127 { 128 if (AEC.SUPER[a].id == variants[i].id) 129 { 130 var text = variants[i].text; 131 132 if (AEC.useDefaultValues) 133 { 134 AEC.SUPER[a].options.forEach((index, option) => 135 { 136 if (parseInt(option.value_index) == parseInt(variants[i].option)) 137 { 138 text = option.admin_label; 139 } 140 });
141 } 142 143 variant.push([AEC.SUPER[a].label,text].join(AEC.Const.VARIANT_DELIMITER_ATT)); 144 145 /** 146 * Push selected options 147 */ 148 variant_attribute_option.push( 149 { 150 attribute: variants[i].id, 151 option: variants[i].option 152 }) 153 } 154 } 155 } 156 157 if (!variant.length) 158 { 159 /** 160 * Invoke original click event(s) 161 */ 162 if (element.dataset.click) 163 { 164 /** 165 * Track time 166 */ 167 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 168 169 eval(element.dataset.click); 170 } 171 172 return true; 173 } 174 } 175 176 if (element.dataset.grouped) 177 { 178 for (u = 0, y = window.G.length; u < y; u++) 179 { 180 let field = document.querySelector('[name="super_group[' + window.G[u].id + ']"]'); 181 182 if (field) 183 { 184 (qty => 185 { 186 if (qty) 187 { 188 products.push( 189 { 190 'name': window.G[u].name, 191 'id': window.G[u].sku, 192 'price': window.G[u].price, 193 'category': window.G[u].category, 194 'brand': window.G[u].brand, 195 'quantity': qty 196 });
197 } 198 })(Math.abs(field.value)); 199 } 200 } 201 } 202 else 203 { 204 products.push( 205 { 206 'name': element.dataset.name, 207 'id': 1 === parseInt(element.dataset.useSimple) ? element.dataset.simpleId : element.dataset.id, 208 'price': element.dataset.price, 209 'category': element.dataset.category, 210 'brand': element.dataset.brand, 211 'variant': variant.join(AEC.Const.VARIANT_DELIMITER), 212 'quantity': qty 213 }); 214 } 215 216 for (i = 0, l = products.length; i < l; i++) 217 { 218 (function(product) 219 { 220 Object.entries(AEC.parseJSON(element.dataset.attributes)).forEach(([key, value]) => 221 { 222 product[key] = value; 223 }); 224 225 })(products[i]); 226 } 227 228 var data = 229 { 230 'event': 'addToCart', 231 'eventLabel': element.dataset.name, 232 'ecommerce': 233 { 234 'currencyCode': AEC.currencyCode, 235 'add': 236 { 237 'actionField': 238 { 239 'list': element.dataset.list 240 }, 241 'products': products 242 }, 243 'options': variant_attribute_option 244 }, 245 'eventCallback': function() 246 { 247 if (AEC.eventCallback) 248 { 249 if (element.dataset.event) 250 { 251 element.trigger(element.dataset.event); 252 } 253 254 if (element.dataset.click) 255 { 256 eval(element.dataset.click); 257 } 258 } 259 }, 260 'currentStore': element.dataset.store 261 }; 262 263 if (AEC.useDefaultValues) 264 { 265 data['currentStore'] = AEC.storeName; 266 } 267 268 /** 269 * Notify listeners 270 */ 271 this.EventDispatcher.trigger('ec.add.data', data); 272 273 /** 274 * Track event 275 */ 276 AEC.Cookie.add(data).push(dataLayer); 277 278 /** 279 * Save backreference 280 */ 281 if (AEC.localStorage) 282 { 283 (function(products) 284 { 285 for (var i = 0, l = products.length; i < l; i++) 286 { 287 AEC.Storage.reference().set( 288 { 289 id: products[i].id, 290 category: products[i].category 291 }); 292 } 293 })(products); 294 } 295 296 /** 297 * Track time 298 */ 299 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 300 301 if (AEC.facebook) 302 { 303 if ("undefined" !== typeof fbq) 304 { 305 (function(product, products, fbq) 306 { 307 var content_ids = [], price = 0; 308 309 for (i = 0, l = products.length; i < l; i++) 310 { 311 content_ids.push(products[i].id); 312 313 price += parseFloat(products[i].price); 314 } 315 316 (function(callback) 317 { 318 if (AEC.Const.COOKIE_DIRECTIVE) 319 { 320 AEC.CookieConsent.queue(callback).process(); 321 } 322 else 323 { 324 callback.apply(window,[]); 325 } 326 }) 327 ( 328 (function(product, content_ids, price) 329 { 330 return function() 331 { 332 if ('undefined' === typeof variants) 333 { 334 variants = []; 335 } 336 337 fbq('track', 'AddToCart', 338 { 339 content_name: product, 340 content_ids: content_ids, 341 content_type: !variants.length ? 'product' : 'product_group', 342 value: price, 343 currency: AEC.currencyCode 344 }, 345 { eventID: AEC.UUID.generate({ event: 'AddToCart'}) }); 346 } 347 })(product, content_ids, price) 348 ); 349 350 })(element.dataset.name, products, fbq); 351 } 352 } 353 354 /** 355 * Invoke original click event(s) 356 */ 357 if (element.dataset.click) 358 { 359 eval(element.dataset.click); 360 } 361 362 return true; 363 }, 364 ajaxSwatch: function(context,dataLayer) 365 { 366 var element = context; 367 368 if (window.jQuery) 369 { 370 jQuery(document).on('ajax:addToCart', function() 371 { 372 var attributes = []; 373 374 Object.entries(AEC.parseJSON(element.dataset.swatch)).forEach(([key, value]) => 375 { 376 attributes.push(value); 377 }); 378 379 var option = document.querySelector('.swatch-option.selected'); 380 381 if (!option) 382 { 383 return true; 384 } 385 386 var variant = [[attributes[0].attribute_label, option.getAttribute('aria-label')].join(AEC.Const.VARIANT_DELIMITER_ATT)].join(AEC.Const.VARIANT_DELIMITER); 387 388 var products = 389 [ 390 { 391 'name': element.dataset.name, 392 'id': element.dataset.id, 393 'price': element.dataset.price, 394 'category': element.dataset.category, 395 'brand': element.dataset.brand, 396 'variant': variant, 397 'quantity': 1 398 } 399 ]; 400 401 var data = 402 { 403 'event': 'addToCart', 404 'eventLabel': element.dataset.name, 405 'ecommerce': 406 { 407 'currencyCode': AEC.currencyCode, 408 'add': 409 { 410 'actionField': 411 { 412 'list': element.dataset.list 413 }, 414 'products': products 415 } 416 }, 417 'currentStore': element.dataset.store 418 }; 419 420 AEC.EventDispatcher.trigger('ec.add.swatch.data', data); 421 422 /** 423 * Track event 424 */ 425 AEC.Cookie.add(data).push(dataLayer); 426 427 /** 428 * Track time 429 */ 430 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 431 }); 432 } 433 434 return true; 435 }, 436 ajaxList:function(context,dataLayer) 437 { 438 var element = context, products = []; 439
440 if (!AEC.gtm()) 441 { 442 /** 443 * Invoke original click event(s) 444 */ 445 if (element.dataset.click) 446 { 447 /** 448 * Track time 449 */ 450 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 451 452 eval(element.dataset.click); 453 } 454 455 return true; 456 } 457 458 products.push( 459 { 460 'name': element.dataset.name, 461 'id': element.dataset.id, 462 'price': element.dataset.price, 463 'category': element.dataset.category, 464 'brand': element.dataset.brand, 465 'position': element.dataset.position, 466 'quantity': 1 467 }); 468 469 /** 470 * Affiliation attributes 471 */ 472 for (i = 0, l = products.length; i < l; i++) 473 { 474 (product => 475 { 476 477 Object.entries(AEC.parseJSON(element.dataset.attributes)).forEach(([key, value]) => 478 { 479 product[key] = value; 480 }); 481 482 })(products[i]); 483 } 484 485 var data = 486 { 487 'event': 'addToCart', 488 'eventLabel': element.dataset.name, 489 'ecommerce': 490 { 491 'currencyCode': AEC.currencyCode, 492 'add': 493 { 494 'actionField': 495 { 496 'list': element.dataset.list 497 }, 498 'products': products 499 } 500 }, 501 'eventCallback': function() 502 { 503 if (AEC.eventCallback) 504 { 505 if (element.dataset.event) 506 { 507 element.trigger(element.dataset.event); 508 } 509 510 if (element.dataset.click) 511 { 512 eval(element.dataset.click); 513 } 514 } 515 }, 516 'currentStore': element.dataset.store 517 }; 518 519 this.EventDispatcher.trigger('ec.add.list.data', data); 520 521 /** 522 * Track event 523 */ 524 AEC.Cookie.add(data).push(dataLayer); 525 526 /** 527 * Save backreference 528 */ 529 if (AEC.localStorage) 530 { 531 (function(products) 532 { 533 for (var i = 0, l = products.length; i < l; i++) 534 { 535 AEC.Storage.reference().set( 536 { 537 id: products[i].id, 538 category: products[i].category 539 }); 540 } 541 })(products); 542 } 543 544 /** 545 * Track time 546 */ 547 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.dataset.name, element.dataset.category); 548 549 if (AEC.facebook) 550 { 551 if ("undefined" !== typeof fbq) 552 { 553 (function(product, products, fbq) 554 { 555 var content_ids = [], price = 0; 556 557 for (i = 0, l = products.length; i < l; i++) 558 { 559 content_ids.push(products[i].id); 560 561 price += parseFloat(products[i].price); 562 } 563 564 (function(callback) 565 { 566 if (AEC.Const.COOKIE_DIRECTIVE) 567 { 568 AEC.CookieConsent.queue(callback).process(); 569 } 570 else 571 { 572 callback.apply(window,[]); 573 } 574 }) 575 ( 576 (function(product, content_ids, price) 577 { 578 return function() 579 { 580 fbq('track', 'AddToCart', 581 { 582 content_name: product, 583 content_ids: content_ids, 584 content_type: 'product', 585 value: price, 586 currency: AEC.currencyCode 587 }, 588 { eventID: AEC.UUID.generate({ event: 'AddToCart'}) }); 589 } 590 })(product, content_ids, price) 591 ); 592 593 })(element.dataset.name, products, fbq); 594 } 595 } 596 597 /** 598 * Invoke original click event(s) 599 */ 600 if (element.dataset.click) 601 { 602 eval(element.dataset.click); 603 } 604 605 return true; 606 }, 607 click: function(context,dataLayer) 608 { 609 var element = context; 610
611 if (!AEC.gtm()) 612 { 613 /** 614 * Track time 615 */ 616 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.dataset.name, element.dataset.category); 617 618 return true; 619 } 620 621 var item = 622 { 623 'name': element.dataset.name, 624 'id': element.dataset.id, 625 'price': element.dataset.price, 626 'category': element.dataset.category, 627 'brand': element.dataset.brand, 628 'quantity': element.dataset.quantity, 629 'position': element.dataset.position 630 }; 631 632 Object.entries(AEC.parseJSON(element.dataset.attributes)).forEach(([key, value]) => 633 { 634 item[key] = value; 635 }); 636 637 var data = 638 { 639 'event': 'productClick', 640 'eventLabel': element.dataset.name, 641 'ecommerce': 642 { 643 'click': 644 { 645 'actionField': 646 { 647 'list': element.dataset.list 648 }, 649 'products': 650 [ 651 item 652 ] 653 } 654 }, 655 'eventCallback': function() 656 { 657 if (AEC.eventCallback) 658 { 659 if (element.dataset.event) 660 { 661 element.trigger(element.dataset.event); 662 } 663 664 if (element.dataset.click) 665 { 666 eval(element.dataset.click); 667 } 668 else if (element.matches('a')) 669 { 670 document.location = element.getAttribute('href'); 671 } 672 else if (element.matches('img') && element.parentNode.matches('a')) 673 { 674 document.location = element.parentNode.getAttribute('href'); 675 } 676 else 677 { 678 return true; 679 } 680 } 681 }, 682 'eventTarget': (function(element) 683 { 684 /** 685 * Default target 686 */ 687 var target = 'Default'; 688 689 /** 690 * Check if element is anchor 691 */ 692 if (element.matches('a')) 693 { 694 target = 'Link'; 695 696 if (element.querySelector('img')) 697 { 698 target = 'Image'; 699 } 700 } 701 702 if (element.matches('button')) 703 { 704 target = 'Button'; 705 } 706 707 return target; 708 709 })(element), 'currentStore': element.dataset.store 710 }; 711 712 AEC.EventDispatcher.trigger('ec.click.data', data); 713 714 /** 715 * Push data 716 */ 717 AEC.Cookie.click(data).push(dataLayer); 718 719 /** 720 * Track time 721 */ 722 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.dataset.name, element.dataset.category); 723 724 if (element.dataset.click) 725 { 726 eval(element.dataset.click); 727 } 728 729 if (AEC.eventCallback) 730 { 731 return false; 732 } 733 734 return true; 735 }, 736 /** 737 * Track "Remove From Cart" event 738 * 739 * @param (domelement) context 740 * @param (object) dataLayer 741 * @return boolean 742 */ 743 remove: function(context, dataLayer) 744 { 745 var element = context; 746
747 if (!AEC.gtm()) 748 { 749 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.dataset.name, element.dataset.category); 750 } 751 752 var item = 753 { 754 'name': element.dataset.name, 755 'id': element.dataset.id, 756 'price': element.dataset.price, 757 'category': element.dataset.category, 758 'brand': element.dataset.brand, 759 'quantity': element.dataset.quantity 760 }; 761 762 Object.entries(AEC.parseJSON(element.dataset.attributes)).forEach(([key, value]) => 763 { 764 item[key] = value; 765 }); 766 767 var data = 768 { 769 'event': 'removeFromCart', 770 'eventLabel': element.dataset.name, 771 'ecommerce': 772 { 773 'remove': 774 { 775 'actionField': 776 { 777 'list': element.dataset.list 778 }, 779 'products': 780 [ 781 item 782 ] 783 } 784 } 785 }; 786 787 AEC.EventDispatcher.trigger('ec.remove.data', data); 788 789 if (AEC.Message.confirm) 790 { 791 require(['Magento_Ui/js/modal/confirm'], function(confirmation) 792 { 793 confirmation( 794 { 795 title: AEC.Message.confirmRemoveTitle, 796 content: AEC.Message.confirmRemove, 797 actions: 798 { 799 confirm: function() 800 { 801 /** 802 * Track event 803 */ 804 AEC.Cookie.remove(data).push(dataLayer); 805 806 /** 807 * Track time 808 */ 809 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.dataset.name); 810 811 /** 812 * Execute standard data-post 813 */ 814 jQuery(document).dataPost('postData', AEC.parseJSON(element.dataset.postAction)); 815 }, 816 cancel: function() 817 { 818 return false; 819 }, 820 always: function() 821 { 822 return false; 823 } 824 } 825 }); 826 }); 827 } 828 else 829 { 830 /** 831 * Track event 832 */ 833 AEC.Cookie.remove(data).push(dataLayer); 834 835 /** 836 * Track time 837 */ 838 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.dataset.name); 839 } 840 841 return false; 842 }, 843 wishlist: function(context, dataLayer) 844 { 845 var element = context; 846 847 if (!AEC.gtm()) 848 { 849 /** 850 * Track time 851 */ 852 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_WISHLIST, element.dataset.name,'Wishlist'); 853 854 return true; 855 } 856 857 let data = 858 { 859 event: element.dataset.event, 860 eventLabel: element.dataset.eventLabel 861 }; 862 863 AEC.EventDispatcher.trigger('ec.add.wishlist', data, { attributes: element.dataset.eventAttributes }); 864 865 /** 866 * Push data 867 */ 868 dataLayer.push(data); 869 870 return true; 871 }, 872 compare: function(context, dataLayer) 873 { 874 var element = context; 875 876 if (!AEC.gtm()) 877 { 878 /** 879 * Track time 880 */ 881 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_COMPARE, element.dataset.name,'Compare'); 882 883 return true; 884 } 885 886 let data = 887 { 888 event: element.dataset.event, 889 eventLabel: element.dataset.eventLabel 890 }; 891 892 AEC.EventDispatcher.trigger('ec.add.compare', data, { attributes: element.dataset.eventAttributes } ); 893 894 /** 895 * Push data 896 */ 897 dataLayer.push(data); 898 899 return true; 900 }, 901 Bind: (function() 902 { 903 return { 904 apply: function(parameters) 905 { 906 /** 907 * Merge persistent storage 908 */ 909 AEC.Persist.merge(); 910 911 /** 912 * Push private data 913 */ 914 AEC.Cookie.pushPrivate(); 915 916 document.addEventListener('DOMContentLoaded',() => 917 { 918 document.body.addEventListener('catalogCategoryAddToCartRedirect', () => 919 { 920 dataLayer.push( 921 { 922 event: AEC.Const.CATALOG_CATEGORY_ADD_TO_CART_REDIRECT_EVENT 923 }); 924 }); 925 }); 926 927 if (parameters) 928 { 929 if (parameters.performance) 930 { 931 if (window.performance) 932 { 933 window.onload = function() 934 { 935 setTimeout(function() 936 { 937 var time = performance.timing.loadEventEnd - performance.timing.responseEnd; 938 939 var timePayload = 940 { 941 'event':'performance', 942 'performance': 943 { 944 'timingCategory': 'Load times', 945 'timingVar': 'load', 946 'timingValue': (time % 60000) 947 } 948 }; 949 950 switch(window.google_tag_params.ecomm_pagetype) 951 { 952 case 'home': 953 954 timePayload.performance.timingLabel = 'Home'; 955 956 AEC.CookieConsent.queue(() => 957 { 958 dataLayer.push(timePayload); 959 }).process(); 960 961 break; 962 case 'product': 963 964 timePayload.performance.timingLabel = 'Product'; 965 966 AEC.CookieConsent.queue(() => 967 { 968 dataLayer.push(timePayload); 969 }).process(); 970 971 break; 972 973 case 'category': 974 975 timePayload.performance.timingLabel = 'Category'; 976 977 AEC.CookieConsent.queue(() => 978 { 979 dataLayer.push(timePayload); 980 }).process(); 981 982 break; 983 } 984 985 }, 0); 986 } 987 } 988 } 989 } 990 991 return this; 992 } 993 } 994 })(), 995 Time: (function() 996 { 997 var T =
998 { 999 event: 'trackTime', 1000 timingCategory: '', 1001 timingVar: '', 1002 timingValue: -1, 1003 timingLabel: '' 1004 }; 1005 1006 var time = new Date().getTime(); 1007 1008 return { 1009 track: function(dataLayer, category, variable, label) 1010 { 1011 T.timingValue = (new Date().getTime()) - time; 1012 1013 if (category) 1014 { 1015 T.timingCategory = category; 1016 } 1017 1018 if (variable) 1019 { 1020 T.timingVar = variable; 1021 } 1022 1023 if (label) 1024 { 1025 T.timingLabel = label; 1026 } 1027 1028 (function(callback) 1029 { 1030 if (AEC.Const.COOKIE_DIRECTIVE) 1031 { 1032 AEC.CookieConsent.queue(callback).process(); 1033 } 1034 else 1035 { 1036 callback.apply(window,[]); 1037 } 1038 }) 1039 ( 1040 (function(dataLayer, T) 1041 { 1042 return function() 1043 { 1044 dataLayer.push(T); 1045 } 1046 })(dataLayer, T) 1047 ); 1048 }, 1049 trackContinue: function(dataLayer, category, variable, label) 1050 { 1051 this.track(dataLayer, category, variable, label); 1052 1053 /** 1054 * Reset time 1055 */ 1056 time = new Date().getTime(); 1057 } 1058 } 1059 })(), 1060 Persist:(function() 1061 { 1062 var DATA_KEY = 'persist'; 1063 1064 var proto = 'undefined' != typeof Storage ? 1065 { 1066 push: function(key, entity) 1067 { 1068 /** 1069 * Get data 1070 */ 1071 var data = this.data(); 1072 1073 /** 1074 * Push data 1075 */ 1076 data[key] = entity; 1077 1078 /** 1079 * Save to local storage 1080 */ 1081 localStorage.setItem(DATA_KEY, JSON.stringify(data)); 1082 1083 return this; 1084 }, 1085 data: function() 1086 { 1087 var data = localStorage.getItem(DATA_KEY); 1088 1089 if (null !== data) 1090 { 1091 return JSON.parse(data); 1092 } 1093 1094 return {}; 1095 }, 1096 merge: function() 1097 { 1098 var data = this.data(); 1099 var push = 1100 { 1101 persist: {} 1102 }; 1103 1104 for (var i in data) 1105 { 1106 push.persist[i] = data[i]; 1107 } 1108 1109 dataLayer.push(push); 1110 1111 return this; 1112 }, 1113 clear: function() 1114 { 1115 /** 1116 * Reset private local storage 1117 */ 1118 localStorage.setItem(DATA_KEY,JSON.stringify({})); 1119 1120 return this; 1121 } 1122 } : { 1123 push: function(){}, 1124 merge: function(){}, 1125 clear: function(){} 1126 }; 1127 1128 /** 1129 * Constants 1130 */ 1131 proto.CONST_KEY_PROMOTION = 'persist_promotion'; 1132 1133 return proto; 1134 1135 })(), 1136 Checkout: (function() 1137 { 1138 return { 1139 data: {}, 1140 tracked: {}, 1141 step: function(previous, current, currentCode) 1142 { 1143 if (this.data && this.data.hasOwnProperty('ecommerce')) 1144 { 1145 this.data.ecommerce.checkout.actionField.step = ++current; 1146 1147 /** 1148 * Notify listeners 1149 */ 1150 AEC.EventDispatcher.trigger('ec.checkout.step.data', this.data); 1151 1152 /** 1153 * Track checkout step 1154 */ 1155 AEC.Cookie.checkout(this.data).push(dataLayer); 1156 } 1157 1158 return this; 1159 }, 1160 stepOption: function(step, option) 1161 { 1162 if (!option) 1163 { 1164 return this; 1165 } 1166 1167 if (!option.toString().length) 1168 { 1169 return this; 1170 } 1171 1172 var data = 1173 { 1174 'event': 'checkoutOption', 1175 'ecommerce': 1176 { 1177 'checkout_option': 1178 { 1179 'actionField': 1180 { 1181 'step': step, 1182 'option': option 1183 } 1184 } 1185 } 1186 }; 1187 1188 /** 1189 * Notify listeners 1190 */ 1191 AEC.EventDispatcher.trigger('ec.checkout.step.option.data', data); 1192 1193 /** 1194 * Track checkout option 1195 */ 1196 AEC.Cookie.checkoutOption(data).push(dataLayer); 1197 1198 return this; 1199 } 1200 } 1201 })(), 1202 Cookie: (function() //This is an experimental feature to overcome FPC (Full Page Cache) related issues (beta) 1203 { 1204 return { 1205 data: null, 1206 privateData: null, 1207 reset: function() 1208 { 1209 return dataLayer; 1210 }, 1211 push: function(dataLayer, consent) 1212 { 1213 consent = typeof consent !== 'undefined' ? consent : true; 1214 1215 if (this.data) 1216 { 1217 if (consent) 1218 { 1219 if (AEC.Const.COOKIE_DIRECTIVE) 1220 { 1221 if (AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED) 1222 { 1223 this.reset().push(this.data); 1224 } 1225 } 1226 else 1227 { 1228 this.reset().push(this.data); 1229 } 1230 } 1231 else 1232 { 1233 this.reset().push(this.data); 1234 } 1235 1236 /** 1237 * Reset data to prevent further push 1238 */ 1239 this.data = null; 1240 } 1241 1242 return this; 1243 }, 1244 pushPrivate: function() 1245 { 1246 var data = this.getPrivateData(); 1247 1248 if (data) 1249 { 1250 dataLayer.push( 1251 { 1252 privateData: data 1253 });
1254 } 1255 1256 return this; 1257 }, 1258 /** 1259 * Augment products array [] and map category with localStorage reference 1260 */ 1261 augment: function(products) 1262 { 1263 /** 1264 * Parse data & apply local reference 1265 */ 1266 var reference = AEC.Storage.reference().get(); 1267 1268 if (reference) 1269 { 1270 for (var i = 0, l = products.length; i < l; i++) 1271 { 1272 for (var a = 0, b = reference.length; a < b; a++) 1273 { 1274 if (products[i].id.toString().toLowerCase() === reference[a].id.toString().toLowerCase()) 1275 { 1276 products[i].category = reference[a].category; 1277 } 1278 } 1279 } 1280 } 1281 1282 return products; 1283 }, 1284 click: function(data) 1285 { 1286 AEC.EventDispatcher.trigger('ec.cookie.click.data', data); 1287 1288 this.data = data; 1289 1290 return this; 1291 }, 1292 add: function(data) 1293 { 1294 AEC.EventDispatcher.trigger('ec.cookie.add.data', data); 1295 1296 this.data = data; 1297 1298 return this; 1299 }, 1300 remove: function(data) 1301 { 1302 AEC.EventDispatcher.trigger('ec.cookie.remove.item.data', data); 1303 1304 this.data = data; 1305 1306 if (AEC.localStorage) 1307 { 1308 this.data.ecommerce.remove.products = this.augment(this.data.ecommerce.remove.products); 1309 } 1310 1311 return this; 1312 }, 1313 update: function(data) 1314 { 1315 AEC.EventDispatcher.trigger('ec.cookie.update.item.data', data); 1316 1317 this.data = data; 1318 1319 return this; 1320 }, 1321 visitor: function(data) 1322 { 1323 AEC.EventDispatcher.trigger('ec.cookie.visitor.data', data); 1324 1325 this.data = (function(data, privateData) 1326 { 1327 if (privateData) 1328 { 1329 if (privateData.hasOwnProperty('visitor')) 1330 { 1331 data.visitorId = privateData.visitor.visitorId; 1332 data.visitorLoginState = privateData.visitor.visitorLoginState; 1333 } 1334 } 1335 1336 return data; 1337 1338 })(data, AEC.Cookie.getPrivateData()); 1339 1340 return this; 1341 }, 1342 detail: function(data) 1343 { 1344 AEC.EventDispatcher.trigger('ec.cookie.detail.data', data); 1345 1346 this.data = data; 1347 1348 return this; 1349 }, 1350 purchase: function(data) 1351 { 1352 AEC.EventDispatcher.trigger('ec.cookie.purchase.data', data); 1353 1354 this.data = data; 1355 1356 if (AEC.localStorage) 1357 { 1358 this.data.ecommerce.purchase.products = this.augment(this.data.ecommerce.purchase.products); 1359 } 1360 1361 return this; 1362 }, 1363 impressions: function(data) 1364 { 1365 AEC.EventDispatcher.trigger('ec.cookie.impression.data', data); 1366 1367 this.data = data; 1368 1369 return this; 1370 }, 1371 checkout: function(data) 1372 { 1373 AEC.EventDispatcher.trigger('ec.cookie.checkout.step.data', data); 1374 1375 this.data = data; 1376 1377 if (AEC.localStorage) 1378 { 1379 this.data.ecommerce.checkout.products = this.augment(this.data.ecommerce.checkout.products); 1380 } 1381 1382 return this; 1383 }, 1384 checkoutOption: function(data) 1385 { 1386 AEC.EventDispatcher.trigger('ec.cookie.checkout.step.option.data', data); 1387 1388 this.data = data; 1389 1390 return this; 1391 }, 1392 promotion: function(data) 1393 { 1394 AEC.EventDispatcher.trigger('ec.cookie.promotion.data', data); 1395 1396 this.data = data; 1397 1398 return this; 1399 }, 1400 promotionClick: function(data) 1401 { 1402 AEC.EventDispatcher.trigger('ec.cookie.promotion.click', data); 1403 1404 this.data = data; 1405 1406 return this; 1407 }, 1408 remarketing: function(data) 1409 { 1410 AEC.EventDispatcher.trigger('ec.cookie.remarketing.data', data); 1411 1412 this.data = data; 1413 1414 return this; 1415 }, 1416 getPrivateData: function() 1417 { 1418 if (!this.privateData) 1419 { 1420 var cookie = this.get('privateData'); 1421 1422 if (cookie) 1423 { 1424 this.privateData = this.parse(cookie); 1425 } 1426 } 1427 1428 return this.privateData; 1429 }, 1430 set: function(name, value, days) 1431 { 1432 if (!days) 1433 { 1434 days = 30; 1435 } 1436 1437 let date = new Date(); 1438 1439 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 1440 1441 document.cookie = name + "=" + value + "; expires=" + date.toGMTString() + "; path=/"; 1442 1443 return this; 1444 }, 1445 get: function(name) 1446 { 1447 var start = document.cookie.indexOf(name + "="), len = start + name.length + 1; 1448 1449 if ((!start) && (name != document.cookie.substring(0, name.length))) 1450 { 1451 return null; 1452 } 1453 1454 if (start == -1) 1455 { 1456 return null; 1457 } 1458 1459 var end = document.cookie.indexOf(String.fromCharCode(59), len); 1460 1461 if (end == -1) 1462 { 1463 end = document.cookie.length; 1464 } 1465 1466 return decodeURIComponent(document.cookie.substring(len, end)); 1467 }, 1468 unset: function(name) 1469 { 1470 document.cookie = name + "=" + "; path=/; expires=" + (new Date(0)).toUTCString(); 1471 1472 return this; 1473 }, 1474 parse: function(json) 1475 { 1476 var json = decodeURIComponent(json.replace(/\+/g, ' ')); 1477 1478 return JSON.parse(json); 1479 } 1480 } 1481 })(), 1482 CookieConsent: (function() 1483 { 1484 return { 1485 chain: {}, 1486 queue: function(callback, event) 1487 { 1488 event = typeof event !== 'undefined' ? event : AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT; 1489 1490 if (!this.chain.hasOwnProperty(event)) 1491 { 1492 this.chain[event] = []; 1493 } 1494 1495 this.chain[event].push(callback); 1496 1497 return this; 1498 }, 1499 dispatch: function(consent) 1500 { 1501 /** 1502 * Essential cookies 1503 */ 1504 AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED = true; 1505 1506 /** 1507 * Push consent to dataLayer 1508 */ 1509 dataLayer.push(consent); 1510 1511 return this.process(consent.event); 1512 }, 1513 process: function(event) 1514 { 1515 event = typeof event !== 'undefined' ? event : AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT; 1516 1517 if (this.chain.hasOwnProperty(event) && 1 == AEC.Cookie.get(event)) 1518 { 1519 for (a = 0, b = this.chain[event].length; a < b; a++) 1520 { 1521 this.chain[event][a].apply(this,[]); 1522 } 1523 1524 this.chain[event] = []; 1525 } 1526 1527 return this; 1528 }, 1529 acceptConsent: function(event) 1530 { 1531 return this.dispatch({ event:event }); 1532 }, 1533 declineConsent: function(event) 1534 { 1535 return this.dispatch({ event:event }); 1536 }, 1537 getConsentDialog: function(dataLayer, endpoints) 1538 { 1539 if (1 == AEC.Cookie.get(AEC.Const.COOKIE_DIRECTIVE_CONSENT_DECLINE_EVENT)) 1540 { 1541 return true; 1542 } 1543 1544 if (1 != AEC.Cookie.get(AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT)) 1545 { 1546 AEC.Request.get(endpoints.cookieContent, {}, (response) => 1547 { 1548 var directive = (body => 1549 { 1550 body.insertAdjacentHTML('beforeend', response.cookieContent); 1551 1552 return body.lastElementChild; 1553 1554 })(document.body); 1555 1556 directive.querySelectorAll('a.ec-gtm-cookie-directive-note-toggle').forEach(element => 1557 { 1558 element.addEventListener('click', event => 1559 { 1560 event.target.nextElementSibling.style.display = 'block' === event.target.nextElementSibling.style.display ? 'none' : 'block'; 1561 });
1562 }); 1563 1564 directive.querySelectorAll('a.accept').forEach(element => 1565 { 1566 element.addEventListener('click', event => 1567 { 1568 event.target.text = event.target.dataset.confirm; 1569 1570 var grant = [...directive.querySelectorAll('[name="cookie[]"]:checked')].map(element => { return element.value }); 1571 1572 AEC.Request.post(endpoints.cookie, { cookie: grant }, response => 1573 { 1574 Object.keys(response).forEach(event => 1575 { 1576 AEC.CookieConsent.acceptConsent(event); 1577 }); 1578 1579 directive.remove(); 1580 }); 1581 }); 1582 }); 1583 1584 directive.querySelectorAll('a.accept-all').forEach(element => 1585 { 1586 element.addEventListener('click', event => 1587 { 1588 event.target.text = event.target.dataset.confirm; 1589 1590 [...directive.querySelectorAll('[name="cookie[]"]')].forEach(element => 1591 { 1592 element.checked = true; 1593 }); 1594 1595 element.parentNode.removeChild(element.previousElementSibling); 1596 1597 var grant = [...directive.querySelectorAll('[name="cookie[]"]:checked')].map(element => { return element.value }); 1598 1599 AEC.Request.post(endpoints.cookie, { cookie: grant }, response => 1600 { 1601 Object.keys(response).forEach(event => 1602 { 1603 AEC.CookieConsent.acceptConsent(event); 1604 }); 1605 1606 directive.remove(); 1607 }); 1608 });
1609 }); 1610 1611 directive.querySelectorAll('a.decline').forEach(element => 1612 { 1613 element.addEventListener('click', event => 1614 { 1615 AEC.Request.post(endpoints.cookie, { decline: true }, response => 1616 { 1617 Object.keys(response).forEach(event => 1618 { 1619 AEC.CookieConsent.declineConsent(event); 1620 }); 1621 1622 directive.remove(); 1623 }); 1624 }); 1625 }); 1626 }); 1627 } 1628 else 1629 { 1630 if (AEC.Const.COOKIE_DIRECTIVE_SEGMENT_MODE) 1631 { 1632 (segments => 1633 { 1634 for (i = 0, l = segments.length; i < l;i++) 1635 { 1636 if (1 == AEC.Cookie.get(segments[i])) 1637 { 1638 AEC.CookieConsent.acceptConsent(segments[i]); 1639 } 1640 } 1641 1642 })(AEC.Const.COOKIE_DIRECTIVE_SEGMENT_MODE_EVENTS); 1643 } 1644 else 1645 { 1646 AEC.CookieConsent.acceptConsent(AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT); 1647 } 1648 } 1649 } 1650 } 1651 })(), 1652 Storage: (function(api) 1653 { 1654 return { 1655 set: function(property, value) 1656 { 1657 if ('undefined' !== typeof(Storage)) 1658 { 1659 localStorage.setItem(property, JSON.stringify(value)); 1660 } 1661 1662 return this; 1663 1664 }, 1665 get: function(property) 1666 { 1667 if ('undefined' !== typeof(Storage)) 1668 { 1669 return JSON.parse(localStorage.getItem(property)); 1670 } 1671 1672 return null; 1673 }, 1674 reference: function() 1675 { 1676 return (function(storage) 1677 { 1678 return { 1679 set: function(reference) 1680 { 1681 var current = storage.get('category.add') || []; 1682 1683 var exists = (function(current, reference) 1684 { 1685 for (i = 0, l = current.length; i < l; i++) 1686 { 1687 if (current[i].id.toString().toLowerCase() === reference.id.toString().toLowerCase()) 1688 { 1689 /** 1690 * Update category 1691 */ 1692 current[i].category = reference.category; 1693 1694 return true; 1695 } 1696 } 1697 1698 return false; 1699 1700 })(current, reference); 1701 1702 if (!exists) 1703 { 1704 current.push(reference); 1705 } 1706 1707 storage.set('category.add', current); 1708 1709 return this; 1710 }, 1711 get: function() 1712 { 1713 return storage.get('category.add'); 1714 } 1715 } 1716 })(this); 1717 } 1718 } 1719 })(), 1720 gtm: function() 1721 { 1722 if ("undefined" === typeof google_tag_manager) 1723 { 1724 /** 1725 * Log error to console 1726 */ 1727 console.log('Unable to detect Google Tag Manager. Please verify if GTM install snippet is available.'); 1728 1729 return false; 1730 } 1731 1732 return true; 1733 }, 1734 parseJSON: function(content) 1735 { 1736 if ('object' === typeof content) 1737 { 1738 return content; 1739 } 1740 1741 if ('string' === typeof content) 1742 { 1743 try 1744 { 1745 return JSON.parse(content); 1746 } 1747 catch (e){} 1748 } 1749 1750 return {}; 1751 }, 1752 getPayloadSize: function(object) 1753 { 1754 var objects = [object]; 1755 var size = 0; 1756 1757 for (var index = 0; index < objects.length; index++) 1758 { 1759 switch (typeof objects[index]) 1760 { 1761 case 'boolean': 1762 size += 4; 1763 break; 1764 case 'number': 1765 size += 8; 1766 break; 1767 case 'string': 1768 size += 2 * objects[index].length; 1769 break; 1770 case 'object': 1771 if (Object.prototype.toString.call(objects[index]) != '[object Array]') 1772 { 1773 for (var key in objects[index]) size += 2 * key.length; 1774 } 1775 for (var key in objects[index]) 1776 { 1777 var processed = false; 1778 1779 for (var search = 0; search < objects.length; search++) 1780 { 1781 if (objects[search] === objects[index][key]) { 1782 processed = true; 1783 break; 1784 } 1785 } 1786 if (!processed) objects.push(objects[index][key]); 1787 } 1788 } 1789 } 1790 return size; 1791 }, 1792 getPayloadChunks: function(arr, len) 1793 { 1794 var chunks = [],i = 0, n = arr.length; 1795 1796 while (i < n) 1797 { 1798 chunks.push(arr.slice(i, i += len)); 1799 } 1800 1801 return chunks; 1802 }, 1803 EventDispatcher: (function() 1804 { 1805 return { 1806 events: {}, 1807 on: function(event, callback) 1808 { 1809 var handlers = this.events[event] || []; 1810 1811 handlers.push(callback); 1812 1813 this.events[event] = handlers; 1814 }, 1815 trigger: function() 1816 { 1817 /** 1818 * Cast arguments to array 1819 */ 1820 let args = [...arguments]; 1821 1822 /** 1823 * Get event 1824 */ 1825 let event = args ? args.shift() : null; 1826 1827 /** 1828 * Get handlers 1829 */ 1830 let handlers = this.events[event] || []; 1831 1832 /** 1833 * Get data 1834 */ 1835 let data = args ? args.shift() : {}; 1836 1837 /** 1838 * Get options 1839 */ 1840 let options = args ? args.shift() : {}; 1841 1842 /** 1843 * Quit if no handler 1844 */ 1845 if (!handlers || handlers.length < 1) 1846 { 1847 return; 1848 } 1849 1850 console.log(event + '(' + handlers.length + ' listeners)'); 1851
1852 handlers.forEach(function(handler) 1853 { 1854 handler(data, options); 1855 }); 1856 } 1857 } 1858 })(), 1859 Request: (function() 1860 { 1861 return { 1862 get: function(url, params, callback) 1863 { 1864 this.execute('GET', [url,this.serialize(params)].join('?'), callback).send(null); 1865 }, 1866 post: function(url, params, callback) 1867 { 1868 this.execute('POST', url, callback).send(this.serialize(params)); 1869 }, 1870 execute: function(method, url, callback) 1871 { 1872 try 1873 { 1874 var request = new XMLHttpRequest(); 1875 1876 request.open(method, url, true); 1877 1878 request.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 1879 request.setRequestHeader('X-Requested-With','XMLHttpRequest'); 1880 1881 request.addEventListener('load', () => 1882 { 1883 let response; 1884 1885 if ('application/json' === request.getResponseHeader("Content-Type")) 1886 { 1887 response = JSON.parse(request.responseText); 1888 } 1889 else 1890 { 1891 response = request.responseText; 1892 } 1893 1894 if ('function' === typeof callback) 1895 { 1896 callback(response); 1897 } 1898 }); 1899 } 1900 catch (e) 1901 { 1902 console.log(e.message); 1903 1904 return null; 1905 } 1906 1907 1908 return request; 1909 }, 1910 serialize: function(entity, prefix) 1911 { 1912 var query = []; 1913 1914 Object.keys(entity).map(key => 1915 { 1916 var k = prefix ? prefix + "[" + key + "]" : key, value = entity[key]; 1917 1918 query.push((value !== null && typeof value === "object") ? this.serialize(value, k) : encodeURIComponent(k) + "=" + encodeURIComponent(value)); 1919 }); 1920 1921 return query.join("&"); 1922 } 1923 } 1924 })(), 1925 UUID: (() => 1926 { 1927 return { 1928 generate: event => 1929 { 1930 event = event || {}; 1931 1932 if (-1 == ['AddToCart'].indexOf(event)) 1933 { 1934 try 1935 { 1936 let current = AEC.Cookie.get('facebook_latest_uuid'); 1937 1938 if (current) 1939 { 1940 current = JSON.parse(current); 1941 1942 if (current.hasOwnProperty('uuid') && current.hasOwnProperty('event')) 1943 { 1944 if (event.event === current.event) 1945 { 1946 return current.uuid; 1947 } 1948 } 1949 } 1950 } 1951 catch (e){} 1952 } 1953 1954 let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) 1955 { 1956 var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); 1957 return v.toString(16); 1958 }); 1959 1960 event['uuid'] = uuid; 1961 1962 /** 1963 * Set facebook uuid cookie 1964 */ 1965 if (AEC.Const.COOKIE_DIRECTIVE) 1966 { 1967 if (AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED) 1968 { 1969 AEC.Cookie.set('facebook_latest_uuid', JSON.stringify(event)); 1970 } 1971 } 1972 else 1973 { 1974 AEC.Cookie.set('facebook_latest_uuid', JSON.stringify(event)); 1975 } 1976 1977 return uuid; 1978 } 1979 } 1980 })() 1981 } 1982})();
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.