1/** 2 * Anowave Enhanced Ecommerce 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) 2018 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 = 30{ 31 textarea:null, 32 gtm: function() 33 { 34 if ("undefined" === typeof google_tag_manager) 35 { 36 /** 37 * Log error to console 38 */ 39 log('Unable to detect Google Tag Manager. Please verify if GTM install snippet is available.'); 40 41 return false; 42 } 43 44 return true; 45 }, 46 ajax: function(context,dataLayer) 47 { 48 var element = jQuery(context), qty = jQuery(':radio[name=qty]:checked, :text[name=qty], select[name=qty]').eq(0).val(), variant = []; 49 50 /** 51 * Default quantity 52 */ 53 if ('undefined' === typeof qty) 54 { 55 qty = 1; 56 } 57 58 /** 59 * Collection of products added to cart 60 */ 61 var products = []; 62 63 if (AEC.forceSelectors) 64 { 65 jQuery.each(['id','name','category','brand','price','quantity', 'attributes'], function(index, attribute) 66 { 67 element.data(attribute, element.attr('data-' + attribute)); 68 }); 69 } 70 71 var attributes = {}; 72 73 if (!AEC.gtm()) 74 { 75 /** 76 * Invoke original click event(s) 77 */ 78 if (element.data('click')) 79 { 80 /** 81 * Track time 82 */ 83 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 84 85 eval(element.data('click')); 86 } 87 88 return true; 89 } 90 91 if(element.data('configurable')) 92 { 93 var attributes = jQuery('[name^="super_attribute"]'), variants = []; 94 95 /** 96 * Load super attsibutes 97 */ 98 99 jQuery.each(attributes, function(index, attribute) 100 { 101 if (jQuery(attribute).is('select')) 102 { 103 var name = jQuery(attribute).attr('name'), id = name.substring(name.indexOf('[') + 1, name.lastIndexOf(']')); 104 105 var option = jQuery(attribute).find('option:selected'); 106 107 if (0 < parseInt(option.val())) 108 { 109 variants.push( 110 { 111 id: id, 112 text: option.text() 113 }); 114 } 115 } 116 }); 117 118 if (attributes.length == variants.length) 119 { 120 for (i = 0, l = variants.length; i < l; i++) 121 { 122 for (a = 0, b = AEC.SUPER.length; a < b; a++) 123 { 124 if (AEC.SUPER[a].id == variants[i].id) 125 { 126 variant.push([AEC.SUPER[a].label,variants[i].text].join(':')); 127 } 128 } 129 } 130 } 131 132 if (!variant.length) 133 { 134 /** 135 * Invoke original click event(s) 136 */ 137 if (element.data('click')) 138 { 139 /** 140 * Track time 141 */ 142 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 143 144 eval(element.data('click')); 145 } 146 147 return false; 148 } 149 } 150 151 /** 152 * Handle products with custom options 153 */ 154 if (element.data('options')) 155 { 156 variant = variant || [], options = element.data('options'); 157 158 var variant = (function($, variant) 159 { 160 var options = element.data('options'), current = []; 161 162 $('[name^="options"]').each(function() 163 { 164 $(this).find('option:selected').each(function() 165 { 166 current.push(parseInt($(this).attr('value'))); 167 }); 168 }); 169 170 var currentOptions = []; 171 172 for (i = 0, l = current.length; i < l; i++) 173 { 174 $.each(options, function(index, option) 175 { 176 if (parseInt(option.id) == parseInt(current[i])) 177 { 178 currentOptions.push([option.label.toString().trim(),option.value.toString().trim()].join(':')); 179 } 180 }); 181 } 182 183 variant.push(currentOptions.join('-')); 184 185 /** 186 * Return variant 187 */ 188 return variant; 189 190 })(jQuery, variant); 191 } 192 193 /** 194 * Handle grouped elements 195 */ 196 if (element.data('grouped')) 197 { 198 for (u = 0, y = window.G.length; u < y; u++) 199 { 200 var qty = Math.abs(jQuery('[name="super_group[' + window.G[u].id + ']"]').val()); 201 202 if (qty) 203 { 204 products.push( 205 { 206 'name': window.G[u].name, 207 'id': window.G[u].sku, 208 'price': window.G[u].price, 209 'category': window.G[u].category, 210 'brand': window.G[u].brand, 211 'quantity': qty 212 });
213 } 214 } 215 } 216 else 217 { 218 products.push( 219 { 220 'name': AEC.convert(element.data('name')), 221 'id': AEC.convert(element.data('id')), 222 'price': AEC.convert(element.data('price')), 223 'category': AEC.convert(element.data('category')), 224 'brand': AEC.convert(element.data('brand')), 225 'variant': variant.join('-'), 226 'quantity': qty 227 }); 228 } 229 230 /** 231 * Affiliation attributes 232 */ 233 for (i = 0, l = products.length; i < l; i++) 234 { 235 (function(product) 236 { 237 jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value) 238 { 239 product[key] = value; 240 }); 241 })(products[i]); 242 } 243 244 var data = 245 { 246 'event': 'addToCart', 247 'eventLabel': element.data('name'), 248 'ecommerce': 249 { 250 'currencyCode': AEC.currencyCode, 251 'add': 252 { 253 'products': products 254 } 255 }, 256 'eventCallback': function() 257 { 258 if (AEC.eventCallback) 259 { 260 if (element.data('click')) 261 { 262 eval(element.data('click')); 263 } 264 else if (element.is('a')) 265 { 266 document.location = element.attr('href'); 267 } 268 else if (element.is('img') && element.parent().is('a')) 269 { 270 document.location = element.parent().attr('href'); 271 } 272 else 273 { 274 return true; 275 } 276 } 277 }, 278 'eventTimeout': AEC.eventTimeout 279 }; 280 281 /** 282 * Cookie Consent 283 */ 284 (function(callback, element) 285 { 286 if (AEC.CookieConsent.support) 287 { 288 if (AEC.CookieConsent.granted) 289 { 290 AEC.CookieConsent.queue(callback).process(); 291 } 292 else 293 { 294 if (AEC.eventCallback) 295 { 296 if (element.data('click')) 297 { 298 eval(element.data('click')); 299 } 300 else if (element.is('a')) 301 { 302 document.location = element.attr('href'); 303 } 304 else if (element.is('img') && element.parent().is('a')) 305 { 306 document.location = element.parent().attr('href'); 307 } 308 else 309 { 310 return true; 311 } 312 } 313 } 314 } 315 else 316 { 317 return callback.apply(window,[]); 318 } 319 320 })((function(dataLayer,data, element) 321 { 322 return function() 323 { 324 dataLayer.push(data); 325 326 /** 327 * Track time 328 */ 329 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 330 } 331 })(dataLayer,data, element), element); 332 333 /** 334 * Facebook Pixel Tracking 335 */ 336 if (AEC.facebook) 337 { 338 if ("undefined" !== typeof fbq) 339 { 340 var fb = [], price = 0; 341 342 for (i = 0, l = products.length; i < l; i++) 343 { 344 fb.push(products[i].id); 345 346 /** 347 * Accumulative price 348 */ 349 price += parseFloat(products[i].price); 350 } 351 352 (function(callback) 353 { 354 if (AEC.CookieConsent.support) 355 { 356 AEC.CookieConsent.queue(callback).process(); 357 } 358 else 359 { 360 callback.apply(window,[]); 361 } 362 363 })((function(price, element) 364 { 365 return function() 366 { 367 fbq('track', 'AddToCart', 368 { 369 content_name: element.data('name'), 370 content_ids: fb, 371 content_type: 'product', 372 value: price, 373 currency: AEC.currencyCode 374 }); 375 } 376 })(price, element)); 377 } 378 } 379 380 if (AEC.eventCallback) 381 { 382 return false; 383 } 384 385 return true; 386 }, 387 click: function(context,dataLayer) 388 { 389 var element = jQuery(context); 390 391 if (AEC.forceSelectors) 392 { 393 jQuery.each(['id','name','category','brand','price','quantity','position','attributes'], function(index, attribute) 394 { 395 element.data(attribute, element.attr('data-' + attribute)); 396 }); 397 } 398 399 if (!AEC.gtm()) 400 { 401 /** 402 * Track time 403 */ 404 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.data('name'), element.data('category')); 405 406 return true; 407 } 408 409 var item = 410 { 411 'name': AEC.convert(element.data('name')), 412 'id': AEC.convert(element.data('id')), 413 'price': AEC.convert(element.data('price')), 414 'category': AEC.convert(element.data('category')), 415 'brand': AEC.convert(element.data('brand')), 416 'quantity': AEC.convert(element.data('quantity')), 417 'position': AEC.convert(element.data('position')) 418 }; 419 420 /** 421 * Affiliation attributes 422 */ 423 jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value) 424 { 425 item[key] = value; 426 }); 427 428 var data = 429 { 430 'event': 'productClick', 431 'eventLabel': AEC.convert(element.data('name')), 432 'ecommerce': 433 { 434 'click': 435 { 436 'actionField': 437 { 438 'list': AEC.convert(element.data('list')) 439 }, 440 'products': 441 [ 442 item 443 ] 444 } 445 }, 446 'eventCallback': function() 447 { 448 if (AEC.eventCallback) 449 { 450 if (element.data('click')) 451 { 452 eval(element.data('click')); 453 } 454 else if (element.is('a')) 455 { 456 document.location = element.attr('href'); 457 } 458 else if (element.is('img') && element.parent().is('a')) 459 { 460 document.location = element.parent().attr('href'); 461 } 462 else 463 { 464 return true; 465 } 466 } 467 }, 468 'eventTimeout': AEC.eventTimeout, 469 'eventTarget': (function(element) 470 { 471 /** 472 * Default target 473 */ 474 var target = 'Default'; 475 476 /** 477 * Check if element is anchor 478 */ 479 if (element.is('a')) 480 { 481 target = 'Link'; 482 483 if (element.children().first().is('img')) 484 { 485 target = 'Image'; 486 } 487 } 488 489 if (element.is('button')) 490 { 491 target = 'Button'; 492 } 493 494 return target; 495 496 })(element) 497 }; 498 499 /** 500 * Cookie Consent 501 */ 502 (function(callback, element) 503 {
504 if (AEC.CookieConsent.support) 505 { 506 if (AEC.CookieConsent.granted) 507 { 508 AEC.CookieConsent.queue(callback).process(); 509 } 510 else 511 { 512 if (AEC.eventCallback) 513 { 514 if (element.data('click')) 515 { 516 eval(element.data('click')); 517 } 518 else if (element.is('a')) 519 { 520 document.location = element.attr('href'); 521 } 522 else if (element.is('img') && element.parent().is('a')) 523 { 524 document.location = element.parent().attr('href'); 525 } 526 else 527 { 528 return true; 529 } 530 } 531 } 532 } 533 else 534 { 535 return callback.apply(window,[]); 536 } 537 538 })((function(dataLayer,data, element) 539 { 540 return function() 541 { 542 dataLayer.push(data); 543 544 /** 545 * Track time 546 */ 547 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.data('name'), element.data('category')); 548 } 549 })(dataLayer,data, element), element); 550 551 if (AEC.eventCallback) 552 { 553 return false; 554 } 555 556 return true; 557 }, 558 ajaxList:function(context,dataLayer) 559 { 560 var element = jQuery(context); 561 562 /** 563 * Collection of products added to cart 564 */ 565 var products = []; 566 567 if (AEC.forceSelectors) 568 { 569 jQuery.each(['id','name','category','brand','price','quantity'], function(index, attribute) 570 { 571 element.data(attribute, element.attr('data-' + attribute)); 572 }); 573 } 574 575 if (!AEC.gtm()) 576 { 577 if (AEC.eventCallback) 578 { 579 /** 580 * Invoke original click event(s) 581 */ 582 if (element.data('click')) 583 { 584 /** 585 * Track time 586 */ 587 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 588 589 eval(element.data('click')); 590 } 591 } 592 593 return true; 594 } 595 596 products.push( 597 { 598 'name': AEC.convert(element.data('name')), 599 'id': AEC.convert(element.data('id')), 600 'price': AEC.convert(element.data('price')), 601 'category': AEC.convert(element.data('category')), 602 'brand': AEC.convert(element.data('brand')), 603 'quantity': 1 604 }); 605 606 /** 607 * Affiliation attributes 608 */ 609 for (i = 0, l = products.length; i < l; i++) 610 { 611 (function(product) 612 { 613 jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value) 614 { 615 product[key] = value; 616 }); 617 })(products[i]); 618 } 619 620 var data = 621 { 622 'event': 'addToCart', 623 'eventLabel': element.data('name'), 624 'ecommerce': 625 { 626 'currencyCode': AEC.currencyCode, 627 'add': 628 { 629 'actionField': 630 { 631 'list':AEC.convert(element.data('list')) 632 }, 633 'products': products 634 } 635 } 636 }; 637 638 /** 639 * Cookie Consent 640 */ 641 (function(callback, element) 642 { 643 if (AEC.CookieConsent.support) 644 { 645 if (AEC.CookieConsent.granted) 646 { 647 AEC.CookieConsent.queue(callback).process(); 648 } 649 else 650 { 651 if (element.data('click')) 652 { 653 /** 654 * Track time 655 */ 656 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 657 658 /** 659 * Evaluate original click 660 */ 661 eval(element.data('click')); 662 } 663 } 664 } 665 else 666 { 667 return callback.apply(window,[]); 668 } 669 670 })((function(dataLayer,data, element) 671 { 672 return function() 673 { 674 dataLayer.push(data); 675 676 /** 677 * Track time 678 */ 679 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category')); 680 } 681 })(dataLayer,data, element), element); 682 683 /** 684 * Invoke original click event(s) 685 */ 686 if (AEC.eventCallback) 687 { 688 if (element.data('click')) 689 { 690 eval(element.data('click')); 691 } 692 } 693 694 if (AEC.facebook) 695 { 696 if ("undefined" !== typeof fbq) 697 { 698 var fb = [], price = 0; 699 700 for (i = 0, l = products.length; i < l; i++) 701 { 702 fb.push(products[i].id); 703 704 /** 705 * Accumulative price 706 */ 707 price += parseFloat(products[i].price); 708 } 709 710 (function(callback) 711 {
712 if (AEC.CookieConsent.support) 713 { 714 AEC.CookieConsent.queue(callback).process(); 715 } 716 else 717 { 718 callback.apply(window,[]); 719 } 720 721 })((function(price, element) 722 { 723 return function() 724 { 725 fbq('track', 'AddToCart', 726 { 727 content_name: element.data('name'), 728 content_ids: fb, 729 content_type: 'product', 730 value: price, 731 currency: AEC.currencyCode 732 }); 733 } 734 })(price, element)); 735 } 736 } 737 738 return true; 739 }, 740 remove: function(context, dataLayer) 741 { 742 var element = jQuery(context); 743 744 if (AEC.forceSelectors) 745 { 746 jQuery.each(['id','name','category','brand','price','quantity'], function(index, attribute) 747 { 748 element.data(attribute, element.attr('data-' + attribute)); 749 }); 750 } 751 752 if (!AEC.gtm()) 753 { 754 /** 755 * Track time 756 */ 757 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name'), element.data('category')); 758 759 return true; 760 } 761 762 var item = 763 { 764 'name': AEC.convert(element.data('name')), 765 'id': AEC.convert(element.data('id')), 766 'price': AEC.convert(element.data('price')), 767 'category': AEC.convert(element.data('category')), 768 'brand': AEC.convert(element.data('brand')), 769 'quantity': AEC.convert(element.data('quantity')), 770 'variant': AEC.convert(element.data('variant')) 771 }; 772 773 /** 774 * Affiliation attributes 775 */ 776 jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value) 777 { 778 item[key] = value; 779 }); 780 781 var data = 782 { 783 'event': 'removeFromCart', 784 'eventLabel': AEC.convert(element.data('name')), 785 'ecommerce': 786 { 787 'remove': 788 { 789 'products': 790 [ 791 item 792 ] 793 } 794 }, 795 'eventCallback': function() 796 { 797 if (AEC.eventCallback) 798 { 799 if (element.data('click')) 800 { 801 eval(element.data('click')); 802 } 803 else if (element.is('a')) 804 { 805 document.location = element.attr('href'); 806 } 807 else if (element.is('img') && element.parent().is('a')) 808 { 809 document.location = element.parent().attr('href'); 810 } 811 else 812 { 813 return true; 814 } 815 } 816 }, 817 'eventTimeout': AEC.eventTimeout 818 }; 819 820 if (element.data('mini-cart')) 821 { 822 if ('undefined' !== typeof Minicart) 823 { 824 (function(dataLayer, data, Minicart, element, stop) 825 { 826 Minicart.prototype.updateContentOnRemove = Minicart.prototype.updateContentOnRemove.wrap(function(parentMethod, result, el) 827 { 828 parentMethod(result, el); 829 830 if (!stop) 831 { 832 stop = true; 833 834 if ('undefined' != typeof result.success) 835 { 836 data['eventCallback'] = function(){}; 837 838 /** 839 * Fallback for private mode 840 */ 841 data['eventTimeout'] = AEC.eventTimeout; 842 843 /** 844 * Push data 845 */ 846 dataLayer.push(data); 847 848 /** 849 * Track time 850 */ 851 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name')); 852 } 853 } 854 }); 855 })(dataLayer, data, Minicart, element, false); 856 } 857 } 858 else 859 { 860 /** 861 * Track event 862 */ 863 dataLayer.push(data); 864 865 /** 866 * Track time 867 */ 868 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name')); 869 } 870 871 if (AEC.eventCallback) 872 { 873 return false; 874 } 875 876 return true; 877 }, 878 wishlist: function(context,dataLayer) 879 { 880 var element = jQuery(context); 881 882 if (AEC.forceSelectors) 883 { 884 jQuery.each(['id','name','category','brand','price','quantity'], function(index, attribute) 885 { 886 element.data(attribute, element.attr('data-' + attribute)); 887 }); 888 } 889 890 if (!AEC.gtm()) 891 { 892 /** 893 * Track time 894 */ 895 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_WISHLIST, element.data('name'), element.data('category')); 896 897 return true; 898 } 899 900 var data = 901 { 902 'event': 'addToWishlist',
903 'eventLabel': AEC.convert(element.data('name')), 904 'eventCallback': function() 905 { 906 if (AEC.eventCallback) 907 { 908 if (element.data('click')) 909 { 910 eval(element.data('click')); 911 } 912 else if (element.is('a')) 913 { 914 document.location = element.attr('href'); 915 } 916 else if (element.is('img') && element.parent().is('a')) 917 { 918 document.location = element.parent().attr('href'); 919 } 920 else 921 { 922 return true; 923 } 924 } 925 }, 926 'eventTimeout': AEC.eventTimeout 927 }; 928 929 /** 930 * Push data 931 */ 932 dataLayer.push(data); 933 934 /** 935 * Track time 936 */ 937 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_WISHLIST, element.data('name'), element.data('category')); 938 939 if (AEC.eventCallback) 940 { 941 return false; 942 } 943 944 return true; 945 }, 946 compare: function(context,dataLayer) 947 { 948 var element = jQuery(context); 949 950 if (AEC.forceSelectors) 951 { 952 jQuery.each(['id','name','category','brand','price','quantity'], function(index, attribute) 953 { 954 element.data(attribute, element.attr('data-' + attribute)); 955 }); 956 } 957 958 if (!AEC.gtm()) 959 { 960 /** 961 * Track time 962 */ 963 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_COMPARE, element.data('name'), element.data('category')); 964 965 return true; 966 } 967 968 var data = 969 { 970 'event': 'addToCompare', 971 'eventLabel': AEC.convert(element.data('name')), 972 'eventCallback': function() 973 { 974 if (AEC.eventCallback) 975 { 976 if (element.data('click')) 977 { 978 eval(element.data('click')); 979 } 980 else if (element.is('a')) 981 { 982 document.location = element.attr('href'); 983 } 984 else if (element.is('img') && element.parent().is('a')) 985 { 986 document.location = element.parent().attr('href'); 987 } 988 else 989 { 990 return true; 991 } 992 } 993 }, 994 'eventTimeout': AEC.eventTimeout 995 }; 996 997 /** 998 * Push data 999 */ 1000 dataLayer.push(data); 1001 1002 /** 1003 * Track time 1004 */ 1005 AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_COMPARE, element.data('name'), element.data('category')); 1006 1007 if (AEC.eventCallback) 1008 { 1009 return false; 1010 } 1011 1012 return true; 1013 }, 1014 Callbacks:(function() 1015 { 1016 return { 1017 callbacks:[], 1018 queue: function(callback) 1019 { 1020 this.callbacks.push(callback); 1021 1022 return this; 1023 }, 1024 apply: function() 1025 { 1026 while (this.callbacks.length) 1027 { 1028 this.callbacks.shift().apply(AEC,arguments); 1029 } 1030 1031 return this; 1032 } 1033 } 1034 })(), 1035 Time:(function() 1036 { 1037 var T = 1038 { 1039 event: 'trackTime', 1040 timingCategory: '', 1041 timingVar: '', 1042 timingValue: -1, 1043 timingLabel: '' 1044 }; 1045 1046 var time = new Date().getTime(); 1047 1048 return { 1049 track: function(dataLayer, category, variable, label) 1050 { 1051 T.timingValue = (new Date().getTime()) - time; 1052 1053 if (category) 1054 { 1055 T.timingCategory = category; 1056 } 1057 1058 if (variable) 1059 { 1060 T.timingVar = variable; 1061 } 1062 1063 if (label) 1064 { 1065 T.timingLabel = label; 1066 } 1067 1068 /** 1069 * Track time 1070 */ 1071 dataLayer.push(T); 1072 }, 1073 trackContinue: function(dataLayer, category, variable, label) 1074 { 1075 this.track(dataLayer, category, variable, label); 1076 1077 /** 1078 * Reset time 1079 */ 1080 time = new Date().getTime(); 1081 } 1082 } 1083 })(), 1084 Queue: (function() 1085 { 1086 return { 1087 queue: [], 1088 impressions: function(data) 1089 { 1090 if (AEC.Const.Viewport) 1091 { 1092 jQuery(window).on( 1093 { 1094 load: function() 1095 { 1096 AEC.Queue.bind(data); 1097 } 1098 }); 1099 } 1100 else 1101 { 1102 dataLayer.push(data); 1103 } 1104 1105 return this; 1106 }, 1107 bind: function(data) 1108 { 1109 (function(queue, impressions) 1110 { 1111 jQuery.each(impressions, function(index, impression) 1112 { 1113 queue.push(impression); 1114 }); 1115 1116 })(this.queue, data.ecommerce.impressions); 1117 1118 if (this.queue.length) 1119 { 1120 (function(Queue, $) 1121 { 1122 var scroll = function() 1123 { 1124 var items = 1125 { 1126 noticeable: $.grep(Queue.queue, function(element, index) 1127 {
1128 return Queue.isOnScreen($('[data-id="' + element.id + '"][data-event=productClick]')); 1129 }), 1130 concealed: $.grep(Queue.queue, function(element, index) 1131 { 1132 return !Queue.isOnScreen($('[data-id="' + element.id + '"][data-event=productClick]')); 1133 }) 1134 }; 1135 1136 if (items.noticeable.length) 1137 { 1138 /** 1139 * Set event 1140 */ 1141 data.event = 'impression'; 1142 1143 /** 1144 * Update impressions event 1145 */ 1146 data.ecommerce.impressions = items.noticeable; 1147 1148 /** 1149 * Push item to dataLayer 1150 */ 1151 dataLayer.push(data); 1152 } 1153 1154 if (items.concealed.length) 1155 { 1156 Queue.queue = items.concealed; 1157 } 1158 else 1159 { 1160 /** 1161 * Empty queue 1162 */ 1163 Queue.queue = []; 1164 1165 /** 1166 * Remove scroll listener 1167 */ 1168 $(window).off('scroll.ec'); 1169 } 1170 }; 1171 1172 $(window).on('scroll.ec',scroll).trigger('scroll'); 1173 1174 })(this, jQuery); 1175 } 1176 }, 1177 isOnScreen: function(element) 1178 { 1179 /** 1180 * Default viewport 1181 */ 1182 var viewport = 1183 { 1184 top: 0, bottom: 0 1185 }; 1186 1187 /** 1188 * Check if element exists 1189 */ 1190 if ('undefined' === typeof element) 1191 { 1192 return false; 1193 } 1194 1195 /** 1196 * Get top 1197 */ 1198 viewport.top = jQuery(window).scrollTop(); 1199 1200 /** 1201 * Get bottom 1202 */ 1203 viewport.bottom = viewport.top + jQuery(window).height(); 1204 1205 /** 1206 * Get bounds 1207 */ 1208 var bounds = {}, offset = element.offset(); 1209 1210 if ('undefined' === typeof offset) 1211 { 1212 return false; 1213 } 1214 1215 if (offset == null) 1216 { 1217 return false; 1218 } 1219 1220 if (!offset.hasOwnProperty('top')) 1221 { 1222 return false; 1223 } 1224 1225 /** 1226 * Get bounds top 1227 */ 1228 bounds.top = element.offset().top; 1229 1230 /** 1231 * Get bounds bottom 1232 */ 1233 bounds.bottom = bounds.top + element.outerHeight(); 1234 1235 return ((bounds.top <= viewport.bottom) && (bounds.bottom >= viewport.top)); 1236 } 1237 } 1238 })(), 1239 Cookie: (function() //This is an experimental feature to overcome FPC (Full Page Cache) related issues (beta) 1240 { 1241 return { 1242 data: null, 1243 privateData: null, 1244 push: function(dataLayer) 1245 { 1246 if (this.data) 1247 { 1248 /** 1249 * Push data 1250 */ 1251 dataLayer.push(this.data); 1252 1253 /** 1254 * Reset data to prevent further push 1255 */ 1256 this.data = null; 1257 } 1258 1259 return this; 1260 }, 1261 pushPrivate: function() 1262 { 1263 var data = this.getPrivateData(); 1264 1265 if (data) 1266 { 1267 dataLayer.push( 1268 { 1269 privateData: data 1270 }); 1271 } 1272 1273 return this; 1274 }, 1275 visitor: function(data) 1276 { 1277 /** 1278 * Set data 1279 */ 1280 this.data = data; 1281 1282 return this; 1283 }, 1284 detail: function(data) 1285 { 1286 this.data = data; 1287 1288 return this; 1289 }, 1290 purchase: function(data) 1291 { 1292 this.data = data; 1293 1294 return this; 1295 }, 1296 impressions: function(data) 1297 { 1298 this.data = data; 1299 1300 return this; 1301 }, 1302 checkout: function(data) 1303 { 1304 this.data = data; 1305 1306 return this; 1307 }, 1308 promotion: function(data) 1309 { 1310 this.data = data; 1311 1312 return this; 1313 }, 1314 promotionClick: function(data) 1315 { 1316 this.data = data; 1317 1318 return this; 1319 }, 1320 getPrivateData: function() 1321 { 1322 if (!this.privateData) 1323 { 1324 var cookie = this.get('privateData'); 1325 1326 if (cookie) 1327 { 1328 this.privateData = this.parse(cookie); 1329 } 1330 } 1331 1332 return this.privateData; 1333 }, 1334 get: function(name) 1335 { 1336 var start = document.cookie.indexOf(name + "="), len = start + name.length + 1; 1337 1338 if ((!start) && (name != document.cookie.substring(0, name.length))) 1339 { 1340 return null; 1341 } 1342 1343 if (start == -1) 1344 { 1345 return null; 1346 } 1347 1348 var end = document.cookie.indexOf(String.fromCharCode(59), len); 1349 1350 if (end == -1) 1351 { 1352 end = document.cookie.length; 1353 } 1354 1355 return decodeURIComponent(document.cookie.substring(len, end)); 1356 }, 1357 remove: function(name) 1358 { 1359 document.cookie = name + "=" + "; path=/; expires=" + (new Date(0)).toUTCString(); 1360 1361 return this; 1362 }, 1363 parse: function(json) 1364 { 1365 var json = decodeURIComponent(json.replace(/\+/g, ' ')); 1366 1367 return JSON.parse(json); 1368 }, 1369 Storage: (function(cookie) //@todo: Replace Cookie with localStorage 1370 { 1371 return { 1372 set: function(property, value) 1373 { 1374 if ('undefined' !== typeof(Storage)) 1375 { 1376 localStorage.setItem(property, JSON.stringify(value)); 1377 } 1378 1379 return this; 1380 1381 }, 1382 get: function(property) 1383 { 1384 if ('undefined' !== typeof(Storage)) 1385 { 1386 return JSON.parse(localStorage.getItem(property)); 1387 } 1388 1389 return null; 1390 } 1391 } 1392 })(this) 1393 } 1394 })(), 1395 CookieConsent: (function() 1396 { 1397 return { 1398 support: false, 1399 granted: false, 1400 chain: [], 1401 queue: function(callback) 1402 { 1403 this.chain.push(callback); 1404 1405 return this; 1406 }, 1407 dispatch: function(consent) 1408 { 1409 this.granted = true; 1410 1411 dataLayer.push(consent); 1412 1413 return this.process(); 1414 }, 1415 process: function() 1416 { 1417 if (this.granted) 1418 { 1419 for (i = 0, l = this.chain.length; i < l; i++) 1420 { 1421 this.chain[i].apply(this,[]); 1422 } 1423 1424 /** 1425 * Reset chain 1426 */ 1427 this.chain = []; 1428 } 1429 1430 return this; 1431 } 1432 } 1433 })(), 1434 convert: function(content) 1435 { 1436 if ('undefined' !== typeof content && '' !== content && -1 !== content.toString().indexOf('&')) 1437 { 1438 if (null == this.textarea) 1439 { 1440 this.textarea = jQuery('<textarea/>'); 1441 } 1442 1443 return this.textarea.html(content).text(); 1444 } 1445 1446 return content; 1447 }, 1448 getClientId: function() 1449 { 1450 if ('undefined' !== typeof ga) 1451 { 1452 return ga.getAll()[0].get('clientId'); 1453 } 1454 }, 1455 parseJSON: function(content) 1456 { 1457 if ('object' === typeof content) 1458 { 1459 return content; 1460 } 1461 1462 if ('string' === typeof content) 1463 { 1464 try 1465 { 1466 return JSON.parse(content); 1467 } 1468 catch (e){} 1469 } 1470 1471 return {}; 1472 } 1473}; 1474 1475var GOOGLE_PAYLOAD_SIZE = 8192; 1476 1477/** 1478 * Calculate payload size (approx.) 1479 * 1480 * @return int bytes 1481 */ 1482var getPayloadSize = function(object) 1483{ 1484 var objects = [object]; 1485 var size = 0; 1486 1487 for (var index = 0; index < objects.length; index++) 1488 { 1489 switch (typeof objects[index]) 1490 { 1491 case 'boolean': 1492 size += 4; 1493 break; 1494 case 'number': 1495 size += 8; 1496 break; 1497 case 'string': 1498 size += 2 * objects[index].length; 1499 break; 1500 case 'object': 1501 if (Object.prototype.toString.call(objects[index]) != '[object Array]') 1502 { 1503 for (var key in objects[index]) size += 2 * key.length; 1504 } 1505 for (var key in objects[index]) 1506 { 1507 var processed = false; 1508 1509 for (var search = 0; search < objects.length; search++) 1510 { 1511 if (objects[search] === objects[index][key]) { 1512 processed = true; 1513 break; 1514 } 1515 } 1516 if (!processed) objects.push(objects[index][key]); 1517 } 1518 } 1519 } 1520 return size; 1521}; 1522 1523/** 1524 * Chunk payload 1525 */
1526var getPayloadChunks = function(arr, len) 1527{ 1528 var chunks = [],i = 0, n = arr.length; 1529 1530 while (i < n) 1531 { 1532 chunks.push(arr.slice(i, i += len)); 1533 } 1534 1535 return chunks; 1536};
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.