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