1/*global jQuery, Cookies, pwlGtmDataLayer:true*/ 2 3/** 4 * Set the array for the Visitor Interactions JS 5 * 6 * PEI Media Data Layer Instructions v2.0 7 * 4. Visitor Interactions Tracking 8 * 9 * @type {object} 10 */ 11var visitorInteractions = {}; 12 13( function () { 14 'use strict'; 15 16 visitorInteractions = { 17 18 /** 19 * Detect when a user clicks to start a login or closes the dropdown. 20 */ 21 loginStartButton: function () { 22 23 var pageType = pwlGtmDataLayer.findDlValue( 'pageType' ), 24 pageName = pwlGtmDataLayer.findDlValue( 'pageName' ); 25 26 var loginEvent = { 27 'event': 'virtual page view', 28 'pageType': 'identity', 29 'pageName': '/ga-virtual/identity/login', 30 }; 31 32 var registerEvent = { 33 'event': 'virtual page view', 34 'pageType': 'identity', 35 'pageName': '/ga-virtual/identity/register', 36 }; 37 38 var dropdownClosedEvent = { 39 'event': 'virtual page view', 40 'pageType': pageType, 41 'pageName': pageName, 42 }; 43 44 // Top header dropdown. 45 jQuery( document ).on( 'click', '.top-header-user-account.td_ul_login > li > a', function () { 46 var topHeaderLogin = jQuery( '.top-header-user-account.td_ul_login' ), 47 loginForm = topHeaderLogin.find( '#blaize-login-top' ), 48 subMenu = topHeaderLogin.find( '.sub-menu' ); 49 50 // Trigger the homepage event when the dropdown is closed, 51 // else trigger the login event. 52 if ( subMenu.length && subMenu.css( 'display' ) === 'none' ) { 53 pwlGtmDataLayer.push( dropdownClosedEvent ); 54 } else if ( loginForm.length && loginForm.css( 'display' ) === 'block' ) { 55 pwlGtmDataLayer.push( loginEvent ); 56 } 57 } ); 58 59 // Trigger the homepage event when the dropdown is closed by clicking 60 // outside of it. Also check that the login/register form is not 61 // visible to avoid triggering the same event twice. 62 // See "pwl_modal_closed". 63 jQuery( document ).on( 'pwl_login_menu_closed', function () { 64 if ( jQuery( '.mfp-wrap.mfp-ready' ).length === 0 ) { 65 pwlGtmDataLayer.push( dropdownClosedEvent ); 66 } 67 }); 68 69 // "Click here to login" link in the modal. 70 jQuery( document ).on( 'click', '.blaize-to-login > a', function() { 71 pwlGtmDataLayer.push( loginEvent ); 72 } ); 73 74 // "Click here to register" link in the modal. 75 jQuery( document ).on( 'click', '.blaize-to-register > a', function() { 76 pwlGtmDataLayer.push( registerEvent ); 77 }); 78 79 jQuery(document).on('mouseup', '.btn-register', function () { 80 pwlGtmDataLayer.push( registerEvent ); 81 } ); 82 83 }, 84 85 /** 86 * Detect when a user clicks the my pei save article button 87 * 88 * Web Analytics - Event Register 89 * PMP-4910 Web Analytics - PEI Subscriptions - How many times users save content 90 */ 91 myPeiSaveButton: function () { 92 93 var pushArray = { 94 'event': 'visitor interaction', 95 'interaction_name': 'button click', 96 'buttonName': 'myPEISaveArticle', 97 }; 98 99 jQuery( document ).on( 'click', '.js-myPei-button--save[data-mypei_button_checked="not-saved"]', function () { 100 pwlGtmDataLayer.push( pushArray ); 101 } ); 102 103 }, 104 105 /** 106 * Detect when a user clicks the my pei share list button 107 * 108 * Web Analytics - Event Register 109 * PMP-4912 Web Analytics - PEI Subscriptions - How many times users share lists 110 */ 111 myPeiShareListButton: function () { 112 113 var pushArray = { 114 'event': 'visitor interaction', 115 'interaction_name': 'button click', 116 'buttonName': 'myPEIShareList', 117 }; 118 119 jQuery( document ).on( 'click', '.js-myPei-share-list', function () { 120 pwlGtmDataLayer.push( pushArray ); 121 } ); 122 123 }, 124 125 /** 126 * Detect when a user create a new my PEI list 127 * 128 * Web Analytics - Event Register 129 * PMP-4911 Web Analytics - PEI Subscriptions - How many times users create lists 130 */ 131 myPeiCreateNewListButton: function () { 132 133 var pushArray = { 134 'event': 'visitor interaction', 135 'interaction_name': 'button click', 136 'buttonName': 'myPEINewListCreation', 137 }; 138 139 var modalElement = jQuery( '#modal-create-list, #modal-add-article' ); 140 141 if ( modalElement.length > 0 ) { 142 143 var createButton = modalElement.find( 'form' ).find( 144 'input[data-modal_action="add-article-to-new-list"], input[data-modal_action="create-list"]' 145 ); 146 147 createButton.on( 'click', function () { 148 setTimeout( function () { 149 if ( modalElement.find( '.myPei-modal__notifications--error' ).length < 1 ) { 150 pwlGtmDataLayer.push( pushArray ); 151 } 152 }, 1000 ); 153 } ); 154 } 155 }, 156 157 /** 158 * Detects when a user has clicked link in more stories pop up 159 * 160 * Data layer triggers on click of links contained in the âmore storiesâ pop-out: 161 * 162 * PEI Media Data Layer Instructions v2.0 163 * 4.3 More Stories Pop-Out 164 **/ 165 moreStoriesPopOut: function () { 166 167 var pushArray = { 168 'event': 'visitor interaction', 169 'interaction_name': 'more stories pop-out click', 170 }; 171 172 jQuery( '.td-content-more-articles-box a' ).click( function ( event ) { 173 174 pushArray[ 'moreStoriesArticle' ] = event.currentTarget.text; 175 176 pwlGtmDataLayer.push( pushArray ); 177 178 } ); 179 }, 180 181 /** 182 * Detects when a user has clicked to visit the cart page 183 * 184 * Data layer triggers on click click of cart button 185 * 186 * PEI Media Data Layer Instructions v2.0 187 * 4.9 Click to Cart 188 **/ 189 clickToCart: function () { 190 191 var pushArray = { 192 'event': 'visitor interaction', 193 'interaction_name': 'click to cart', 194 }; 195 196 var pageType = pwlGtmDataLayer.findDlValue( 'pageType' ); 197 198 jQuery( '.wc_cart_wrapper' ).click( function () { 199 200 pushArray[ 'clickToCartLoc' ] = pageType; 201 202 // Check to see if the bottom has been reached so we don't fire more than once. 203 pwlGtmDataLayer.push( pushArray ); 204 205 } ); 206 207 } 208 , 209 210 /** 211 * Detects when a user has reached the end of an article 212 * 213 * When a user gets to the bottom of the article of the post type "post" then a Data Layer push will be 214 * triggered. 215 * 216 * PEI Media Data Layer Instructions v2.0 217 * 4.8 Article Scroll 218 **/ 219 articleScroll: function () { 220 221 var hasArticleScrolled = false;
222 var pushArray = { 223 'event': 'visitor interaction', 224 'interaction_name': 'end of content scroll', 225 }; 226 227 jQuery( window ).scroll( function () { 228 // Check to see if the bottom has been reached so we don't fire more than once. 229 if ( hasArticleScrolled === false ) { 230 231 // Define the element to trigger the push. 232 var articleContainer = jQuery( 'article.type-post' ); 233 234 if ( articleContainer.length ) { 235 236 var windowHeight = document.documentElement.clientHeight; 237 var currentDistanceFromTop = jQuery( document ).scrollTop(); 238 var articleBottom = articleContainer[ 0 ].offsetHeight; 239 var elementDistanceFromTop = articleContainer.offset().top; 240 241 var articleBottomDistanceFromTop = windowHeight - elementDistanceFromTop + currentDistanceFromTop; 242 243 if ( articleBottomDistanceFromTop >= articleBottom ) { 244 hasArticleScrolled = true; 245 pwlGtmDataLayer.push( pushArray ); 246 } 247 } 248 } 249 250 } ); 251 } 252 , 253 254 /** 255 * Detects when a user adds a product to a cart 256 * 257 * PEI Media Data Layer Instructions v2.0 258 * 5.2 Add Product to Cart 259 */ 260 addProduct: function () { 261 262 var self = this, 263 pageType = pwlGtmDataLayer.findDlValue( 'pageType' ), 264 ecommVariables = this.findEcommerceVariables(), 265 pushArray = { 266 'event': 'visitor interaction', 267 'interaction_name': 'add to cart', 268 }; 269 270 // category archive, subscription page 271 jQuery( '.add_to_cart_button' ).on( 'click', function () { 272 273 var $this = jQuery( this ), 274 quantity = self.getProductQty( $this ); 275 276 if ( 0 === quantity ) { 277 // single product page 278 if ( jQuery( 'form.cart:first input[name=quantity]' ).length > 0 ) { 279 quantity = parseInt( jQuery( 'form.cart:first input[name=quantity]' ).val() ); 280 } else { // category archive, subscription page 281 quantity = 1; 282 } 283 } 284 285 // get product data 286 var productData = self.getProductData( $this.data(), quantity ); 287 288 pushArray[ 'ecommerce' ] = { 289 'currencyCode': self.getCurrencyCode(), 290 'add': { 291 'products': [ productData ], 292 }, 293 }; 294 295 pushArray[ 'productAddLoc' ] = pageType; 296 297 pwlGtmDataLayer.push( pushArray ); 298 299 } ); 300 301 // undo button 302 jQuery( '.td-page-content' ).on( 'click', '.restore-item', function () { 303 var undoURL = jQuery( this ).attr( 'href' ); 304 305 // Remove scheme and domain 306 var finalURL = undoURL.substring( undoURL.indexOf( '?' ) + 1 ); 307 308 // Get querystring values 309 var queryString = finalURL.split( '&' ); 310 311 // Set up an empty array in which we store product data 312 var productDataArray = {}; 313 314 // Push all the values to the productDataArray 315 for ( var i = 0, l = queryString.length; i < l; i ++ ) { 316 var values = queryString[ i ].split( '=' ); 317 318 // If the value of the query string isn't set return it as empty 319 if ( values.length > 1 ) { 320 productDataArray[ values[ 0 ] ] = decodeURIComponent( values[ 1 ] ); 321 } else { 322 productDataArray[ values[ 0 ] ] = ''; 323 } 324 } 325 326 // Get product data 327 var productData = self.getProductData( productDataArray, productDataArray.quantity ); 328 329 pushArray[ 'ecommerce' ] = { 330 'currencyCode': self.getCurrencyCode(), 331 'add': { 332 'products': [ productData ], 333 }, 334 }; 335 336 pushArray[ 'productAddLoc' ] = pageType; 337 338 pwlGtmDataLayer.push( pushArray ); 339 } ); 340 } 341 , 342 343 /** 344 * Detects when a user removes from cart via "x" button 345 * 346 * PEI Media Data Layer Instructions v2.0 347 * 5.3 Remove a Product from a Cart 348 */ 349 removeProduct: function () { 350 351 var self = this, 352 pageType = pwlGtmDataLayer.findDlValue( 'pageType' ), 353 pushArray = { 354 'event': 'visitor interaction', 355 'interaction_name': 'remove from cart', 356 }; 357 358 jQuery( '.widget_shopping_cart, .product-remove' ).on( 'click', 'a.remove', function ( e ) { 359 360 var $this = jQuery( this ), 361 productData = $this; 362 363 // get product quantity 364 var quantity = self.getProductQty( $this ); 365 366 // If there's no quantity return 367 if ( 0 == quantity ) { 368 return true; 369 } 370 371 // get product data 372 productData = self.getProductData( $this.data(), quantity ); 373 374 pushArray[ 'ecommerce' ] = { 375 'currencyCode': self.getCurrencyCode(), 376 'remove': { 377 'products': [ productData ], 378 }, 379 }; 380
381 pushArray[ 'productRemoveLoc' ] = pageType; 382 383 pwlGtmDataLayer.push( pushArray ); 384 385 } ); 386 387 } 388 , 389 390 /** 391 * Detects when user adds or removes item from cart 392 * 393 * PEI Media Data Layer Instructions v2.0 394 * Covers 5.2 & 5.3 Add a Product to a Cart Remove a Product from a Cart 395 */ 396 updateProductCart: function () { 397 398 var self = this, 399 pageType = pwlGtmDataLayer.findDlValue( 'pageType' ); 400 401 // When a user clicks the update cart button on cart page 402 jQuery( '[name=update_cart]' ).on( 'click', function () { 403 404 // Go through each product line 405 jQuery( '.product-quantity input.qty' ).each( function () { 406 var $this = jQuery( this ), 407 default_value = $this.prop( 'defaultValue' ), 408 new_value = parseInt( $this.val() ); 409 410 // If new_value is not a number set it to default one 411 if ( isNaN( new_value ) ) { 412 new_value = default_value; 413 } 414 415 // If value has changed push event to Data Layer 416 if ( default_value != new_value ) { 417 418 var new_quantity_value, 419 interactionType, 420 interactionName, 421 interactionLocation, 422 pushArray = { 423 'event': 'visitor interaction', 424 'ecommerce': {}, 425 }; 426 427 // If default value is lessa than new value 428 // it means a product has been added 429 if ( default_value < new_value ) { 430 431 interactionType = 'add'; 432 interactionName = 'add to cart'; 433 interactionLocation = 'productAddLoc'; 434 new_quantity_value = new_value - default_value; 435 436 } 437 // Otherwise a product has been removed 438 else { 439 440 interactionType = 'remove'; 441 interactionName = 'remove from cart'; 442 interactionLocation = 'productRemoveLoc'; 443 new_quantity_value = default_value - new_value; 444 445 } 446 447 pushArray[ 'interaction_name' ] = interactionName; 448 449 pushArray[ 'ecommerce' ][ 'currencyCode' ] = self.getCurrencyCode(); 450 pushArray[ 'ecommerce' ][ interactionType ] = { 451 'products': [ 452 self.getProductData( 453 $this.closest( '.cart_item' ).find( '.remove' ).data(), 454 new_quantity_value, 455 ), 456 ], 457 }; 458 459 pushArray[ interactionLocation ] = pageType; 460 461 pwlGtmDataLayer.push( pushArray ); 462 } 463 } ); 464 } ); 465 } 466 , 467 468 /** 469 * When a user proceeds through checkout 470 * 471 * PEI Media Data Layer Instructions v2.0 472 * Covers 5.4 Commence Checkout Process 473 */ 474 commenceCheckout: function () { 475 476 var pushArray = { 477 'event': 'visitor interaction', 478 'interaction_name': 'commence checkout', 479 }; 480 481 var self = this; 482 483 var pageType = pwlGtmDataLayer.findDlValue( 'pageType' ); 484 485 var products = this.findCheckOutProducts(); 486 487 if ( products ) { 488 489 jQuery( '.checkout-button' ).click( function () { 490 491 pushArray[ 'ecommerce' ] = { 492 'currencyCode': self.getCurrencyCode(), 493 'checkout': { 494 'actionField': { 'step': 1 }, 495 'products': products, 496 }, 497 }; 498 499 pushArray[ 'checkoutLoc' ] = pageType; 500 501 pwlGtmDataLayer.push( pushArray ); 502 503 } ); 504 } 505 } 506 , 507 508 /** 509 * When a user clicks a social follow, share button 510 * 511 * PEI Media Data Layer Instructions v2.4 512 * Covers 4.4 Social Follow Buttons, 4.5 Social Sharing Buttons 513 */ 514 socialInteractions: function ( trigger, action ) { 515 var interactionType, interactionLabel, interactionValue, 516 pushArray = { 517 'event': 'visitor interaction', 518 }; 519 520 jQuery( trigger ).on( 'click', function ( event ) { 521 var currentLink = jQuery( event.currentTarget ); 522 523 // Set DL variables 524 if ( 'follow' === action ) { 525 526 interactionType = 'social follow click'; 527 interactionLabel = 'socialFollowNetwork'; 528 interactionValue = currentLink.attr( 'title' ).toLowerCase(); 529 530 } else if ( 'share' === action ) { 531 532 interactionType = 'social share click'; 533 interactionLabel = 'socialShareNetwork'; 534 interactionValue = currentLink.find( 'span' ).text().toLowerCase(); 535 536 } 537 538 // Return if the user clicked on email button 539 // (we use another function to register email interactions) 540 if ( 'email' === interactionValue ) 541 return; 542 543 // Push array to Data Layer
544 if ( '' !== interactionValue ) { 545 pushArray[ 'interaction_name' ] = interactionType; 546 pushArray[ interactionLabel ] = interactionValue; 547 548 pwlGtmDataLayer.push( pushArray ); 549 } 550 } ); 551 } 552 , 553 554 /** 555 * When a user clicks share by email button 556 * 557 * PEI Media Data Layer Instructions v2.4 558 * Covers 4.6 Email Share Buttons 559 */ 560 emailInteractions: function () { 561 var pushArray = { 562 'event': 'visitor interaction', 563 'interaction_name': 'email share click', 564 }; 565 566 checkSuccess(); 567 568 function checkSuccess () { 569 if ( jQuery( '#sharing_email' ).find( 'form' ).css( 'display' ) === 'none' ) { 570 pwlGtmDataLayer.push( pushArray ); 571 } else { 572 setTimeout( checkSuccess, 1000 ); //every 1 second. Not ideal but means no plugin needed. 573 } 574 } 575 } 576 , 577 578 /** 579 * When a user clicks on a PDF attached to a Print Edition 580 * or a link inside the post content. 581 * 582 * PEI Media Data Layer Instructions v2.4 583 * Covers 4.7 Download file 584 */ 585 downloadAttachments: function () { 586 jQuery( 'a[href$=".pdf"]' ).on( 'click', function ( event ) { 587 588 // Get the url for the PDF 589 var url = event.currentTarget.href; 590 591 // Retrieve the file name from href add +1 since we don't want the / at the beginning 592 var filename = url.substring( url.lastIndexOf( '/' ) + 1 ); 593 594 var pushArray = { 595 'event': 'visitor interaction', 596 'interaction_name': 'download file', 597 'downloadFileName': filename.replace( '.pdf', '' ), // Remove the file extension from the filename 598 }; 599 600 pwlGtmDataLayer.push( pushArray ); 601 } ); 602 } 603 , 604 605 /** 606 * Add current pageName to the search form so 607 * that we can use this value for the search page Data Layer 608 * 609 * PEI Media Data Layer Instructions v2.4 610 * Covers 2.4.3 Search Results Pages 611 */ 612 searchPage: function () { 613 if ( !window.dataLayer ) 614 return; 615 616 var self = this; 617 618 jQuery( '.td-search-form, .td-search-form-widget' ).on( 'submit', function () { 619 self.setPageSearchCookie(); 620 } ); 621 622 jQuery( '#td-aj-search-mob, #td-aj-search' ).on( 'click', '.result-msg a', function () { 623 self.setPageSearchCookie(); 624 } ); 625 } 626 , 627 628 /** 629 * Stores a cookie which value is current value for Article Access Method 630 * 631 * PEI Media Data Layer Instructions v2.4 632 * Covers 2.4.2 Article Pages 633 */ 634 handleAccessMethod: function ( trigger, value, selector ) { 635 selector = selector || 'a'; 636 637 if(value.indexOf('search results') !== -1) { 638 jQuery( '.algolia-hits-wrapper' ).on('click', trigger, function ( event ) { 639 640 value = 'search results: ' + jQuery('.ais-SearchBox-input').val(); 641 642 Cookies.set( 'peiArticleAccessedFrom', value, { 643 // Set an expiry date of one minute. 644 // Using the end of session could lead 645 // to wrong value pushed to the Data Layer. 646 expires: new Date( new Date().getTime() + 60 * 1000 ), 647 } ); 648 }); 649 } else { 650 jQuery( trigger ).on( 'click', selector, function ( event ) { 651 652 // If href is not set return 653 if ( '#' === jQuery( event.currentTarget ).attr( 'href' ) ) 654 return; 655 // We need to retrieve the value from the section title 656 // at the end of every article page 657 if ( 'article bottom' === value ) 658 value = jQuery( '.td_block_related_posts' ).find( '.td-related-title a.td-cur-simple-item' ).text(); 659 // We need to retrieve the value from the widget title 660 // on the right sidebar of every page that has one 661 if ( 'widgets' === value ) 662 value = jQuery( this ).parents( trigger ).find( '.block-title' ).text(); 663 Cookies.set( 'peiArticleAccessedFrom', value, { 664 // Set an expiry date of one minute. 665 // Using the end of session could lead 666 // to wrong value pushed to the Data Layer. 667 expires: new Date( new Date().getTime() + 60 * 1000 ), 668 } ); 669 } ); 670 } 671 } 672 , 673 674 /** 675 * Set a cookie to store current pageName value 676 * so we can use it later in Search Page 677 */ 678 setPageSearchCookie: function () { 679 Cookies.set( 'peiPageSearchMadeOn', pwlGtmDataLayer.findDlValue( 'pageName' ).replace( '/ga-virtual', '' ) ); 680 } 681 , 682 683 /** 684 * If we're on an article page set articleAccessedFrom property to the correct value 685 */ 686 setArticleAccessMethodValue: function () { 687 if ( 'article' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 688 var peiAccessCookie = Cookies.get( 'peiArticleAccessedFrom' ), 689 objectKey = this.findDlObject(), 690 articleAccessMethodValue = 'entry page';
691 692 if ( peiAccessCookie ) { 693 articleAccessMethodValue = peiAccessCookie; 694 } 695 696 if ( null !== objectKey ) { 697 window.dataLayer[ objectKey ][ 'articleAccessMethod' ] = articleAccessMethodValue; 698 } 699 } 700 } 701 , 702 703 /** 704 * If we're on a search page set searchPage property to the correct value 705 */ 706 setSearchPageValue: function () { 707 if ( 'search results' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 708 var peiSearchCookie = Cookies.get( 'peiPageSearchMadeOn' ), 709 objectKey = this.findDlObject(), 710 peiPageSearchMadeOnValue = 'no value'; 711 712 if ( peiSearchCookie ) { 713 peiPageSearchMadeOnValue = peiSearchCookie; 714 } 715 716 if ( null !== objectKey ) { 717 window.dataLayer[ objectKey ][ 'searchPage' ] = peiPageSearchMadeOnValue; 718 } 719 } 720 } 721 , 722 723 /** 724 * Returns current page name formatted 725 */ 726 extractPageName: function () { 727 var pageName = pwlGtmDataLayer.findDlValue( 'pageName' ); 728 729 var taxonomyName = pageName.substring( pageName.lastIndexOf( '/' ) + 1 ); 730 731 return taxonomyName.replace( /-/g, ' ' ); 732 } 733 , 734 735 /** 736 * Return dataLayer object with values pushed via PHP on pageLoad 737 */ 738 findDlObject: function () { 739 for ( var i = 0, l = window.dataLayer.length; i < l; i ++ ) { 740 if ( window.dataLayer[ i ].hasOwnProperty( 'pageType' ) ) { 741 return i; 742 } 743 } 744 745 return null; 746 } 747 , 748 749 /** 750 * Returns current pageType when multiple dataLayer elements on a page 751 **/ 752 findEcommerceVariables: function () { 753 754 var ecommVariables = ''; 755 756 var i = ''; 757 758 for ( i = 0; i < window.dataLayer.length; i ++ ) { 759 if ( window.dataLayer[ i ].hasOwnProperty( 'ecommerce' ) ) { 760 ecommVariables = window.dataLayer[ i ].ecommerce; 761 break; 762 } 763 } 764 765 return ecommVariables.detail; 766 } 767 , 768 769 findCheckOutProducts: function () { 770 771 if ( jQuery( 'a.remove' ).length > 0 ) { 772 773 var products = []; 774 775 jQuery( 'a.remove' ).each( function () { 776 777 var productData = jQuery( this ); 778 779 var quantity = jQuery( this ).closest( '.cart_item' ).find( '.product-quantity input.qty' ).val(); 780 781 if ( isNaN( quantity ) ) { 782 quantity = 1; 783 } 784 785 var product = { 786 'category': productData.data( 'product_category' ), 787 'name': productData.data( 'product_name' ).toLowerCase(), 788 'price': String( productData.data( 'product_price' ) ), 789 'sku': productData.data( 'product_sku' ), 790 'quantity': parseInt( quantity ), 791 }; 792 793 products.push( product ); 794 795 } ); 796 return products; 797 } 798 799 //no items in checkout 800 return false; 801 802 } 803 , 804 805 /** 806 * Retrieve product quantity for a product 807 */ 808 getProductQty: function ( el ) { 809 var quantity = 0, 810 quantity_element = el.closest( '.cart_item' ).find( '.product-quantity input.qty' ); 811 812 if ( 0 == quantity_element.length ) { 813 814 var subscriptionQuantity = parseInt( el.closest( '.cart_item' ).find( '.product-quantity input' ).val() ); 815 816 if ( subscriptionQuantity === 1 ) { 817 818 quantity = 1; 819 820 } 821 822 quantity_element = el.closest( '.mini_cart_item' ).find( '.quantity' ); 823 824 if ( quantity_element.length > 0 ) { 825 quantity = parseInt( quantity_element.text() ); 826 827 if ( isNaN( quantity ) ) { 828 quantity = 0; 829 } 830 } 831 } else { 832 quantity = quantity_element.val(); 833 } 834 835 return quantity; 836 } 837 , 838 839 /** 840 * Retrieve product data 841 */ 842 getProductData: function ( productData, quantity ) { 843 return { 844 'category': productData[ 'product_category' ], 845 'name': productData[ 'product_name' ].toLowerCase(), 846 'price': String( productData[ 'product_price' ] ), 847 'sku': productData[ 'product_sku' ], 848 'quantity': quantity, 849 }; 850 } 851 , 852 853 /** 854 * Retrieve current currency code from Aelia Currency Switcher configuration object 855 */ 856 getCurrencyCode: function () { 857 const params = window.wc_aelia_currency_switcher_params; 858 859 if ( ( 'object' === typeof params ) && params.selected_currency ) { 860 return params.selected_currency; 861 } 862 863 return 'GBP'; 864 } 865 , 866 867 /** 868 * Check if a modal has closed which means that any contained functionality has been successful 869 * @param modalElement 870 * @param pushArray 871 */ 872 checkModalSuccess: function ( modalElement, pushArray ) { 873 874 if ( modalElement.css( 'display' ) === 'none' ) { 875 setTimeout( checkSuccess, 1000 ); //every 1 second. Not ideal but means no plugin needed. 876 } else { 877 pwlGtmDataLayer.push( pushArray ); 878 } 879 880 } 881 , 882 883 }; 884 885} )(); 886 887jQuery( document ).ready( function () { 888 visitorInteractions.moreStoriesPopOut(); 889 visitorInteractions.clickToCart(); 890 visitorInteractions.addProduct(); 891 visitorInteractions.removeProduct(); 892 visitorInteractions.updateProductCart(); 893 visitorInteractions.commenceCheckout(); 894 visitorInteractions.articleScroll(); 895 visitorInteractions.socialInteractions( '.footer-social-wrap a', 'follow' ); 896 visitorInteractions.socialInteractions( '.js-sharing-wrapper a', 'share' ); 897 visitorInteractions.emailInteractions(); 898 visitorInteractions.downloadAttachments(); 899 visitorInteractions.searchPage(); 900 visitorInteractions.setArticleAccessMethodValue(); 901 visitorInteractions.setSearchPageValue(); 902 visitorInteractions.myPeiShareListButton(); 903 visitorInteractions.myPeiCreateNewListButton(); 904 visitorInteractions.loginStartButton(); 905 906 // Handle all the cases for accessMethod property for articles 907 // More Stories Pop Out 908 visitorInteractions.handleAccessMethod( 909 '.td-more-articles-box .td-module-thumb, ' + 910 '.td-more-articles-box .td-module-title', 911 'more stories pop out', 912 ); 913 914 // Widgets 915 visitorInteractions.handleAccessMethod( 916 '.widget_dpe_fp_widget', 917 'widgets', 918 ); 919 920 // Main nav items 921 visitorInteractions.handleAccessMethod( 922 '.sub-menu', 923 'main navigation', 924 '.td_block_inner .td-module-thumb a, .td_block_inner .entry-title a', 925 ); 926 927 // Categories 928 if ( 'topic article list' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 929 visitorInteractions.handleAccessMethod( 930 // triggers 931 'body.category .td_module_16 .td-module-thumb, ' + 932 'body.category .td_module_16 .entry-title, ' + 933 'body.category .td_module_mx5 .td-module-thumb, ' + 934 'body.category .td_module_mx5 .td-meta-info-container .entry-title, ' + 935 'body.category .td_module_mx6 .td-module-thumb, ' + 936 'body.category .td_module_mx6 .td-meta-info-container .entry-title', 937 // value 938 'Category: ' + visitorInteractions.extractPageName(), 939 ); 940 } 941 942 // Tags 943 if ( 'topic article list' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 944 visitorInteractions.handleAccessMethod( 945 // triggers 946 'body.tag .td_module_16 .td-module-thumb, ' + 947 'body.tag .td_module_16 .entry-title, ' + 948 'body.tag .td_module_mx5 .td-module-thumb, ' + 949 'body.tag .td_module_mx5 .td-meta-info-container .entry-title, ' + 950 'body.tag .td_module_mx6 .td-module-thumb, ' + 951 'body.tag .td_module_mx6 .td-meta-info-container .entry-title', 952 // value 953 'Tag: ' + visitorInteractions.extractPageName(), 954 ); 955 } 956 957 // Authors 958 if ( 'author article list' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 959 visitorInteractions.handleAccessMethod( 960 // triggers 961 '.td_module_16 .td-module-thumb, ' + 962 '.td_module_16 .entry-title', 963 // values 964 'author article list', 965 ); 966 } 967 968 // Related articles 969 if ( 'article' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 970 visitorInteractions.handleAccessMethod( 971 '.td_block_related_posts', 972 'article bottom', 973 '.td_module_related_posts .entry-title a, .td_module_related_posts .td-module-thumb a', 974 ); 975 } 976 977 // Our Latest Posts 978 if ( 'error' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 979 visitorInteractions.handleAccessMethod( 980 // triggers 981 '.td_module_16 .td-module-thumb, ' + 982 '.td_module_16 .entry-title', 983 // values 984 'our latest posts', 985 ); 986 } 987 988 // Homepage 989 if ( 'homepage' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 990 visitorInteractions.handleAccessMethod( 991 '.td-main-content-wrap', 992 'homepage', 993 ); 994 } 995 996 // Magazine 997 if ( 'magazine archive' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 998 visitorInteractions.handleAccessMethod( 999 '.td-main-content .td_module_1', 1000 'magazine: ' + visitorInteractions.extractPageName(), 1001 ); 1002 } 1003 1004 // Search results 1005 if ( 'search results' === pwlGtmDataLayer.findDlValue( 'pageType' ) ) { 1006 visitorInteractions.handleAccessMethod( 1007 // triggers 1008 '.ais-hits--thumbnail a, ' + 1009 '.entry-title a', 1010 // values 1011 'search results: ' + jQuery('.ais-SearchBox-input').val(), 1012 ); 1013 } 1014 1015 // Site search 1016 1017 visitorInteractions.handleAccessMethod( 1018 //triggers 1019 '.td-head-form-search-wrap', 1020 //values 1021 'site search: ' 1022 ); 1023 1024} ); 1025
1026//some of these interactions are coming from ajax so we need to wait until the page has completely loaded before loaded the function 1027jQuery( document ).ajaxStop( function () { 1028 1029 visitorInteractions.updateProductCart(); 1030 visitorInteractions.commenceCheckout(); 1031 visitorInteractions.myPeiSaveButton(); 1032 1033 if ( jQuery( 'body' ).is( '.woocommerce-cart' ) ) { 1034 visitorInteractions.removeProduct(); 1035 } 1036} );
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.