1jQuery(function($) { 2 3 'use strict'; 4 5 6 /** 7 * jQuery Tiny Pub/Sub 8 * https://github.com/cowboy/jquery-tiny-pubsub 9 * 10 * Copyright (c) 2013 "Cowboy" Ben Alman 11 * Licensed under the MIT license. 12 **********************************************************************/ 13 var o = $({}); 14 $.subscribe = function() {o.on.apply(o, arguments);}; 15 $.unsubscribe = function() {o.off.apply(o, arguments);}; 16 $.publish = function() {o.trigger.apply(o, arguments);}; 17 18 /** 19 * Save the main building block of DOM elements; for the 20 * sake of succinctness 21 **********************************************************************/ 22 var DOM = (function ( dom ) { 23 24 var dom = dom || {} 25 , wptwaFlag = $( '.wptwa-flag' ) 26 ; 27 28 dom.body = $('body:eq(0)'); 29 dom.isSmallScreen = ( window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == '"small"' || window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == 'small' ) ? true : false; 30 dom.isMobileScreen = ( window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == '"mobile"' || window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == 'mobile' ) ? true : false; 31 dom.isLargeScreen = ( window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == '"desktop"' || window.getComputedStyle( wptwaFlag.get(0), ':after' ).content == 'desktop' ) ? true : false; 32 33 return dom; 34 35 }( DOM ) ); 36 37 /**
38 * Simple cookie utilities 39 **********************************************************************/ 40 var COOKIES = (function ( cookies ) { 41 42 var cookies = cookies || {}; 43 44 cookies.setItem = function ( name, value, durationInMinutes ) { 45 var d = new Date(); 46 d.setTime( d.getTime() + ( durationInMinutes * 60 * 1000 ) ); 47 var expires = 'expires=' + d.toString(); 48 document.cookie = name + '=' + value + ';' + expires + ';path=/'; 49 }; 50 51 cookies.getItem = function ( name ) { 52 var name = name + '=', 53 decodedCookie = decodeURIComponent( document.cookie ), 54 ca = decodedCookie.split(';'); 55 56 for ( var i = 0; i < ca.length; i++ ) { 57 58 var c = ca[ i ]; 59 60 while ( c.charAt( 0 ) == ' ' ) { 61 c = c.substring(1); 62 } 63 64 if ( c.indexOf( name ) == 0 ) { 65 return c.substring( name.length, c.length ); 66 } 67 } 68 return null; 69 } 70 71 cookies.deleteItem = function ( name ) { 72 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; 73 }; 74 75 return cookies; 76 77 }( COOKIES ) ); 78 79 /** 80 * Set widget height on mobile 81 **********************************************************************/ 82 (function () { 83 84 $.subscribe('wptwa-widget-ready', function () { 85 var container = $( '.wptwa-container' ) 86 , box = container.find( '.wptwa-box' ) 87 , description = container.find( '.wptwa-description' ) 88 , toggle = container.find( '.wptwa-toggle' ) 89 , peopleList = container.find( '.wptwa-people' ) 90 ; 91 92 peopleList.css({ 93 maxHeight: $( window ).height() - ( description.outerHeight() + parseInt( box.css( 'bottom' ) ) + 20 ) 94 }); 95 96 }); 97 98 }()); 99 100 /** 101 * Centralize the process of hide/show of the box. 102 **********************************************************************/ 103 (function () { 104 var neverBeenResized = true; 105 $.subscribe('wptwa-widget-ready', function () { 106 var wptwa = DOM.body.find( '.wptwa-container' ), 107 toggleBox = function ( e ) { 108 wptwa.toggleClass( 'wptwa-show' ); 109 110 if ( ! COOKIES.getItem( 'wptwa' ) ) { 111 COOKIES.setItem( 'wptwa', 'toggled', 1440 ); 112 } 113 }; 114 $.subscribe('wptwa-toggle-box', toggleBox); 115 }); 116 117 }()); 118 119 /** 120 * Show and hide the box. 121 **********************************************************************/ 122 (function () { 123 124 $.subscribe('wptwa-widget-ready', function () { 125 126 var wptwaFlag = DOM.body.find( '.wptwa-flag' ), 127 wptwa = DOM.body.find( '.wptwa-container' ), 128 delayTime = parseInt( wptwa.data( 'delay-time' ) ), 129 inactiveTime = parseInt( wptwa.data( 'inactive-time' ) ), 130 scrollLength = parseInt( wptwa.data( 'scroll-length' ) ), 131 autoDisplayOnMobile = wptwa.data( 'auto-display-on-mobile' ), 132 box = wptwa.find( '.wptwa-box' ), 133 toggle = wptwa.find( '.wptwa-toggle' ), 134 close = wptwa.find( '.wptwa-close' ), 135 bottomClose = wptwa.find( '.wptwa-mobile-close' ), 136 autoShow 137 ; 138 139 if ( ! wptwa.length || ! wptwaFlag.length ) { 140 return; 141 } 142 143 /* Set the box's display to block. Its visibility still hidden though. */ 144 box.addClass( 'wptwa-js-ready' ); 145 146 /* Toggle box on toggle's (or close's) click */ 147 toggle.add( close ).add( bottomClose ).on( 'click', function () { 148 $.publish('wptwa-toggle-box'); 149 } ); 150 151 /* We're done here if the screen is small. */ 152 if ( DOM.isSmallScreen && wptwa.is( '.wptwa-disable-auto-display-on-small-screen' ) ) { 153 return; 154 } 155 156 /* Show box after a delay time on page load and only if it has 157 not been shown before. 158 */ 159 if ( delayTime > 0 ) { 160 autoShow = setTimeout( function () { 161 if ( ! box.is( '.wptwa-show' ) && ! COOKIES.getItem( 'wptwa' ) ) { 162 $.publish('wptwa-toggle-box'); 163 } 164 }, delayTime * 1000 ); 165 } 166 167 /* Trigger after inactivity and only if it has not been shown 168 before. 169 */ 170 var cb, 171 executed = false, 172 events = 'mousemove mousedown mouseup onkeydown onkeyup focus scroll', 173 showAfterInactivity = function () { 174 clearTimeout( cb ); 175 if ( ! executed ) { 176 cb = setTimeout(function () { 177 if ( ! COOKIES.getItem( 'wptwa' ) && ! box.is( '.wptwa-show' ) ) { 178 $.publish('wptwa-toggle-box'); 179 } 180 $( document ).off( events, showAfterInactivity ); 181 }, inactiveTime * 1000 ); 182 } 183 }; 184 185 if ( inactiveTime > 0 ) { 186 $( document ).on( events, showAfterInactivity ); 187 } 188 189 /* Trigger after scrolling. 190 Accessing DOM on-scroll is a bad idea. Let's execute the function 191 every half a second during/post scroll instead. 192 */ 193 var percentage = Math.abs( scrollLength ) / 100, 194 scrolling, 195 timing = true, 196 scrollHandler = function() { 197 198 scrolling = true; 199 200 if ( timing ) { 201 202 setTimeout(function () { 203 if ( $( window ).scrollTop() >= ( $( document ).height() - $( window ).height() ) * percentage ){ 204 if ( ! COOKIES.getItem( 'wptwa' ) && ! box.is( '.wptwa-show' ) ) { 205 $.publish('wptwa-toggle-box'); 206 } 207 $( window ).off( 'scroll', scrollHandler ); 208 } 209 timing = true; 210 scrolling = false; 211 }, 500 ); 212 213 if ( scrolling ) { 214 timing = false; 215 } 216 } 217 } 218 ; 219 220 if ( scrollLength > 0 ) { 221 $( window ).on( 'scroll', scrollHandler ); 222 } 223 }); 224 225 }()); 226 227 /** 228 * If avatar is not provided or provided but error, add a hint to 229 * .wptwa-face so we can show a default image. 230 **********************************************************************/ 231 (function () { 232 233 $.subscribe('wptwa-widget-ready', function () { 234 DOM.body.find( '.wptwa-container .wptwa-face' ).each(function () { 235 var el = $( this ),
236 img = el.find( 'img' ), 237 noImage = true 238 ; 239 240 if ( img.length ) { 241 var url = img.attr( 'src' ), 242 tester = new Image(); 243 tester.src = url; 244 245 tester.onerror = function () { 246 el.addClass( 'no-image' ); 247 }; 248 249 } 250 else { 251 el.addClass( 'no-image' ); 252 } 253 254 }); 255 }); 256 257 }()); 258 259 /** 260 * If we're on desktop, use web.whatsapp.com instead. But if not, 261 * remove the target attribute because it will simply open the app. 262 **********************************************************************/ 263 (function () { 264 265 var setupLinks = function () { 266 var wptwaAccounts = DOM.body.find( 'a.wptwa-account' ), 267 wptwaFlag = DOM.body.find( '.wptwa-flag' ) 268 ; 269 270 if ( ! wptwaFlag.length ) { 271 return; 272 } 273 274 /* Change URL to web.whatsapp.com if the user is using a desktop. */ 275 if ( DOM.isLargeScreen ) { 276 277 wptwaAccounts.each(function () { 278 var el = $( this ), 279 number = el.data( 'number' ), 280 text = el.data( 'auto-text' ) 281 ; 282 283 if ( '' === number ) { 284 return true; 285 } 286 el.attr( 'href', 'https://web.whatsapp.com/send?phone=' + number + '&text=' + text ); 287 }); 288 289 } 290 else { 291 if ( window.location === window.parent.location ) { 292 wptwaAccounts.removeAttr( 'target' ); 293 } 294 } 295 296 /* Change [wptwa_page_title] and [wptwa_page_url] */ 297 var currentURL = location.href 298 , currentTitle = document.title 299 ; 300 301 wptwaAccounts.each(function () { 302 var el = $( this ), 303 number = el.data( 'number' ), 304 href = el.attr('href'), 305 href = href.replace(/\[wptwa_page_title\]/g, currentTitle), 306 href = href.replace(/\[wptwa_page_url\]/g, currentURL) 307 ; 308 309 if ( '' === number ) { 310 return true; 311 } 312 313 el.attr( 'href', href ); 314 315 }); 316 }; 317 318 setupLinks(); 319 320 $.subscribe('wptwa-widget-ready', function () { 321 setupLinks(); 322 }); 323 324 $.subscribe('wptwa-woo-ready', function () { 325 setupLinks(); 326 }); 327 328 $.subscribe('wptwa-button-ready', function () { 329 setupLinks(); 330 }); 331 332 }()); 333 334 /** 335 * Get widget via AJAX 336 **********************************************************************/ 337 (function () { 338 339 var wptwasw = DOM.body.find( '#wptwa-config' ); 340 341 if ( wptwasw.length < 1 ) { 342 return; 343 } 344 345 /* wptwasw.length will always renurn true for now, which is why 346 we need to check the `data-ids` value */ 347 if ( wptwasw.data( 'ids' ) == '' ) { 348 return; 349 } 350 351 /** 352 * In order to prevent heavy load on the server, we use the cache 353 * stored from the last ajax request. 354 */ 355 356 var cookieName = 'wptwa-widget-cache-' + wptwasw.data( 'ids' ); 357 358 if ( wptwasw.data( 'cache-time' ) > 0 359 && COOKIES.getItem( cookieName ) 360 && sessionStorage.getItem( cookieName ) ) { 361 362 $( sessionStorage.getItem( cookieName ) ).appendTo( DOM.body ); 363 setTimeout( function () { 364 $.publish( 'wptwa-widget-ready' ); 365 }, 100 ); 366 return; 367 } 368 369 var data = { 370 'action': 'wptwa_display_widget', 371 'when': Date.now(), 372 'current-language': wptwasw.data( 'current-language' ), 373 'ids': wptwasw.data( 'ids' ), 374 'page-title': wptwasw.data( 'page-title' ), 375 'page-url': wptwasw.data( 'page-url' ) 376 }; 377 378 $.post( wptwa_ajax_object.ajax_url, data, function( response ) { 379 380 if ( 'no-show' === response ) { 381 return; 382 } 383 384 var hideOnLargeScreen = true 385 , hideOnSmallScreen = true 386 ; 387 388 $( response ).find( '.wptwa-account' ).each(function () { 389 var el = $( this ); 390 391 if ( DOM.isLargeScreen && ! el.is( '.wptwa-hide-on-large-screen' ) ) { 392 hideOnLargeScreen = false; 393 } 394 395 if ( ( DOM.isSmallScreen || DOM.isMobileScreen ) && ! el.is( '.wptwa-hide-on-small-screen' ) ) { 396 hideOnSmallScreen = false; 397 } 398 }); 399 400 if ( ( DOM.isLargeScreen && ! hideOnLargeScreen ) || ( ( DOM.isMobileScreen || DOM.isSmallScreen ) && ! hideOnSmallScreen ) ) { 401 $( response ).appendTo( DOM.body ); 402 403 /* Cache the widget for future use to prevent frequent ajax calls. */ 404 405 COOKIES.setItem( cookieName, 'loaded', wptwasw.data('cache-time') ); 406 sessionStorage.setItem( cookieName, response ); 407 } 408 409 setTimeout( function () { 410 $.publish( 'wptwa-widget-ready' ); 411 }, 100 ); 412 }); 413 414 }()); 415 416 /** 417 * Button uses ajax to fetch data so we can have an accurate display 418 * even when the page is cached. 419 **********************************************************************/ 420 (function () { 421 422 var wptwasw = DOM.body.find( '#wptwa-config' ) 423 , ids = [] 424 , pageURL = '' 425 , pageTitle = '' 426 , buttonJSONString = '' 427 , fetchNew = false 428 ; 429 430 if ( wptwasw.length < 1 ) { 431 return; 432 } 433 434 DOM.body.find( '.wptwa-button-container' ).each(function () { 435 var el = $( this ) 436 , id = el.data( 'target-id' ) 437 ; 438 439 pageURL = el.data( 'page-url' ); 440 pageTitle = el.data( 'page-title' ); 441 442 ids.push( id ); 443 }); 444 445 if ( ids.length < 1 ) { 446 return; 447 } 448 449 /* Remove duplicates. Without this, we'll be facing a bug ahead. */ 450 ids = ids.filter( function (value, index, self) { 451 return self.indexOf(value) === index; 452 } ); 453 454 var displayButtons = function ( data ) { 455 var data = JSON.parse( data ) 456 for ( var key in data ) { 457 if ( data.hasOwnProperty( key ) ) { 458 var val = data[ key ]; 459 DOM.body.find( '.wptwa-button-container#wptwa-button-' + val.id ).append( val.content ); 460 461 /* Remove this item from the ids. Those which are not removed means 462 that it doesn't have the button to show. */ 463 var index = ids.indexOf( val.id ); 464 if ( index > -1 ) { 465 ids.splice( index, 1 ); 466 } 467 } 468 } 469 470 /* If there's an offline account which doesn't have an offline description, 471 then remove the container. */ 472 for ( var i = 0, limit = ids.length; i < limit; i++ ) { 473 DOM.body.find( '.wptwa-button-container#wptwa-button-' + ids[i] ).remove(); 474 } 475 476 setTimeout( function () { 477 $.publish('wptwa-button-ready'); 478 }, 100 ); 479 }; 480 481 /** 482 * In order to prevent heavy load on the server, we use the cache 483 * stored from the last ajax request. 484 */ 485 486 /* It's cached and there's no cookie */ 487 if ( wptwasw.data( 'cache-time' ) > 0 && ! COOKIES.getItem( 'wptwa-buttons-cache' ) ) { 488 fetchNew = true; 489 } 490 491 /* It's cached and there's no storage */ 492 if ( wptwasw.data( 'cache-time' ) > 0 && ! sessionStorage.getItem('wptwa-buttons-cache') ) { 493 fetchNew = true; 494 } 495 496 /* It's cached and there's a storage but some ids are missing */ 497 if ( wptwasw.data( 'cache-time' ) > 0 && sessionStorage.getItem('wptwa-buttons-cache') ) { 498 var jsoned = JSON.parse( sessionStorage.getItem('wptwa-buttons-cache') ) 499 , currentIds = [] 500 ; 501 502 for ( var key in jsoned ) { 503 if ( jsoned.hasOwnProperty( key ) ) { 504 var val = jsoned[ key ]; 505 currentIds.push( val.id ) 506 } 507 } 508 509 var arrIds = ids.toString().split( ',' ); 510 for ( var i = 0, lim = arrIds.length; i < lim; i++ ) { 511 if ( ! currentIds.includes( parseInt( arrIds[ i ] ) ) ) { 512 fetchNew = true; 513 } 514 } 515 } 516 517 /* It's cached, there's a storage and nothing's wrong */ 518 if ( wptwasw.data( 'cache-time' ) > 0 519 && ! fetchNew 520 && sessionStorage.getItem('wptwa-buttons-cache')) { 521 522 displayButtons( sessionStorage.getItem('wptwa-buttons-cache') ); 523 } 524 525 /* It's not cached of there's something wrong with the cache */ 526 if ( wptwasw.data( 'cache-time' ) < 1 || fetchNew ) { 527 var data = { 528 'action': 'wptwa_display_buttons', 529 'when': Date.now(), 530 'ids': ids.join( ',' ), 531 'page-title': pageTitle, 532 'page-url': pageURL 533 }; 534 535 $.post( wptwa_ajax_object.ajax_url, data, function( response ) { 536 537 if ( response === 'none' ) { 538 return false; 539 } 540 541 /* Cache the widget for future use to prevent frequent ajax calls. */ 542 COOKIES.setItem( 'wptwa-buttons-cache', 'loaded', wptwasw.data('cache-time') ); 543 sessionStorage.setItem('wptwa-buttons-cache', response ); 544 displayButtons( response ); 545 546 }); 547 } 548 549 }()); 550 551 /** 552 * WooCommerce buttons are loaded using AJAX and treated differently 553 * from the other buttons because it has randomize and limit features. 554 **********************************************************************/ 555 (function () { 556 557 var wptwasw = DOM.body.find( '#wptwa-config' ) 558 , ids = '' 559 , pageURL = '' 560 , pageTitle = '' 561 , buttonJSONString = '' 562 , fetchNew = false 563 ; 564 565 if ( wptwasw.length < 1 ) { 566 return; 567 } 568 569 DOM.body.find( '.wptwa-wc-buttons-container' ).each(function () { 570 var el = $( this ); 571 572 pageURL = el.data( 'page-url' ); 573 pageTitle = el.data( 'page-title' ); 574 ids = el.data( 'ids' ); 575 }); 576 577 if ( ids.length < 1 ) { 578 return; 579 } 580 581 var displayWCButtons = function ( data ) { 582 583 var data = JSON.parse( data ); 584 585 for ( var key in data ) { 586 if ( data.hasOwnProperty( key ) ) { 587 var val = data[ key ]; 588 DOM.body.find( '.wptwa-wc-buttons-container' ).append( $( '<p>' + val.content + '</p>' ) ); 589 } 590 } 591 592 setTimeout( function () { 593 $.publish('wptwa-woo-ready'); 594 }, 100 ); 595 596 }; 597 598 /** 599 * In order to prevent heavy load on the server, we use the cache 600 * stored from the last ajax request. 601 */ 602 603 var cookieName = 'wptwa-wc-buttons-cache-' + ids.toString().replace( /,/g, '-' ); 604 605 if ( wptwasw.data( 'cache-time' ) > 0 606 && COOKIES.getItem( cookieName ) 607 && sessionStorage.getItem( cookieName ) ) { 608 609 displayWCButtons( sessionStorage.getItem( cookieName ) ); 610 return; 611 } 612 613 var data = { 614 'action': 'wptwa_display_buttons', 615 'when': Date.now(), 616 'ids': ids, 617 'type' : 'woocommerce_button', 618 'page-title': pageTitle, 619 'page-url': pageURL 620 }; 621 622 $.post( wptwa_ajax_object.ajax_url, data, function( response ) { 623 624 if ( response === 'none' ) { 625 return false; 626 } 627 628 /* Cache the widget for future use to prevent frequent ajax calls. */ 629 COOKIES.setItem( cookieName, 'loaded', wptwasw.data('cache-time') ); 630 sessionStorage.setItem( cookieName, response ); 631 displayWCButtons( response ); 632 633 }); 634 635 }()); 636 637 /** 638 * Send event to Google Analytics
639 **********************************************************************/ 640 (function () { 641 642 /* Remove gdpr container if user already gave her consent. */ 643 $.subscribe('wptwa-widget-ready', function () { 644 if ( COOKIES.getItem( 'consent' ) ) { 645 DOM.body.find( '.wptwa-gdpr' ).remove(); 646 } 647 }); 648 649 DOM.body.on( 'click', 'a.wptwa-account', function ( e ) { 650 651 var el = $( this ) 652 , number = parseInt( el.data( 'number' ) ) 653 , gaLabel = el.data( 'ga-label' ) 654 , parent = el.parents( '.wptwa-people' ) 655 , gdpr = parent.find( '.wptwa-gdpr' ) 656 , confirmation = gdpr.find( '.wptwa-confirmation' ) 657 , consent = gdpr.find( '#wptwa-consent' ) 658 , to 659 ; 660 661 /* If consent needed and is not given yet. */ 662 if ( consent.length && ! consent.is( ':checked' ) ) { 663 confirmation.addClass( 'wptwa-blink' ); 664 665 confirmation.one( 'animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function () { 666 confirmation.removeClass( 'wptwa-blink' ); 667 } ); 668 669 e.preventDefault(); 670 return false; 671 } 672 673 /* If the script reaches here, the user gave her consent. */ 674 if ( el.closest( '.wptwa-container' ).length ) { 675 COOKIES.setItem( 'consent', 'acquired', 1440 ); 676 gdpr.remove(); 677 } 678 679 /* Click analytics. Try to send data to Google or Facebook. */ 680 try { 681 gtag( 'event', 'Button Clicked', { 682 'event_category': 'WhatsApp Click to Chat', 683 'event_label': 'WhatsApp Account: ' + gaLabel 684 } ); 685 } 686 catch ( error ) { 687 /* It seems like the site doesn't have Google Analytics installed. */ 688 window.console && console.log( 'Catched from WhatsApp Click to Chat: ' + error.message ); 689 } 690 691 try { 692 ga( 'send', 'event', 'WhatsApp Click to Chat', 'Button Clicked', 'WhatsApp Account: ' + gaLabel ); 693 } 694 catch ( error ) { 695 /* It seems like the site doesn't have Google Analytics installed. */ 696 window.console && console.log( 'Catched from WhatsApp Click to Chat: ' + error.message ); 697 } 698 699 try { 700 _gaq.push([ '_trackEvent', 'WhatsApp Click to Chat', 'Button Clicked', 'WhatsApp Account: ' + gaLabel ]); 701 } 702 catch ( error ) { 703 /* It seems like the site doesn't have Google Analytics installed. */ 704 window.console && console.log( 'Catched from WhatsApp Click to Chat: ' + error.message ); 705 } 706 707 try { 708 dataLayer.push({ 709 'event': 'customEvent', 710 'eventCategory': 'WhatsApp Click to Chat', 711 'eventAction': 'Button Clicked', 712 'eventLabel': 'WhatsApp Account: ' + gaLabel 713 }); 714 } 715 catch ( error ) { 716 /* It seems like the site doesn't have Google Analytics installed. */ 717 window.console && console.log( 'Catched from WhatsApp Click to Chat: ' + error.message ); 718 } 719 720 var pixeled = false; 721 try { 722 /* Facebook pixel yields warning when we initiate fbq multiple times. */ 723 if ( ! pixeled ) { 724 fbq( 'trackCustom', 'ClickToChat', { 725 event: 'Chat started', 726 account: gaLabel 727 }); 728 pixeled = true; 729 } 730 } 731 catch ( error ) { 732 /* It seems like the site doesn't have Google Analytics installed. */ 733 window.console && console.log( 'Catched from WhatsApp Click to Chat: ' + error.message ); 734 } 735 736 } ); 737 738 }()); 739 740 /** 741 * 742 **********************************************************************/ 743 (function () { 744 745 746 747 }()); 748 749});
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.