1// is user active global vars 2window.abst = {}; 3// activity timer 4 5window.abst.timer = localStorage.absttimer === undefined ? {} : JSON.parse(localStorage.absttimer || 0); 6 7window.abst.currscroll = window.scrollY; 8window.abst.currentMousePos = -1; 9window.abst.oldMousePos = -2; 10window.abst.abactive = true; 11window.abst.timeoutTime = 3000; // how much inactivity before we stop loggin in milliseconds 12window.abst.intervals = {}; 13 14//what size, mobile, tablet or desktop 15if(window.innerWidth < 768) 16 window.abst.size = 'mobile'; 17else if(window.innerWidth < 1024) 18 window.abst.size = 'tablet'; 19else 20 window.abst.size = 'desktop'; 21 22 jQuery(document).ready(function(){ 23 24 //todo make visits / conversion wait until we have uuid 25 26 next_page_visit_report(); 27 28 if( !btab_vars.is_preview && jQuery('.ab-test-page-redirect').length > 0 ) { 29 jQuery('.ab-test-page-redirect').remove(); 30 } 31 32 if( jQuery('[bt_hidden="true"]').length > 0 ) { 33 jQuery('[bt_hidden="true"]').remove(); 34 } 35 36 37 // update scroll status 38 jQuery(document).mousemove(function(event) { 39 window.abst.currentMousePos = event.pageX; 40 }); 41 // catch mouse / keyboard action 42 jQuery('body').on('mousedown keydown touchstart', function(event) { 43 userActiveNow(); 44 }); 45 46 if(!('abConversionValue' in window.abst)) 47 window.abst.abConversionValue = 1; 48 49 window.abst.timerInterval = setInterval(function(){ 50 //check if scroll's changed 51 52 if((window.abst.currscroll != window.scrollY) || (window.abst.currentMousePos != window.abst.oldMousePos) ) 53 { 54 window.abst.currscroll = window.scrollY; 55 window.abst.oldMousePos = window.abst.currentMousePos; 56 userActiveNow(); 57 } 58 59 // check for active class and decrement all active timers 60 if(window.abst.abactive) //for each active timer, increment 61 abstOneSecond(); 62 63 },1000); // every second 64 65 66 //conversion things 67 if (typeof conversion_details !== 'undefined' && conversion_details) 68 { 69 var eid = null; 70 var variation = null; 71 72 // current p info 73 page_url = window.location.href.replace(window.location.origin,''); 74 if (page_url.charAt(0) == "/") page_url = page_url.substr(1); 75 if (page_url.charAt(page_url.length - 1) == "/") page_url = page_url.substr(0, page_url.length - 1); 76 //loop through each conversion d 77 jQuery.each( conversion_details, function( key, detail ) { 78 79 //regex url matching for url's with * *about* 80 if (detail.conversion_page_url && page_url) { 81 // Escape special characters in the user input 82 var escapedUrl = detail.conversion_page_url.replace(/([.+?^${}()|[\]\\])/g, '\\$1'); 83 // Replace * with a regex pattern (.*) 84 var regexPattern = escapedUrl.replace(/\*/g, '.*'); 85 // Create a regular expression object 86 var regex = new RegExp(`^${regexPattern}$`); 87 } 88 89 if(typeof regex !== 'undefined'){ 90 if (regex.test(page_url)) { 91 eid = key; 92 } 93 } 94 else if((detail.conversion_page_url === page_url) && (detail.conversion_page_url !== undefined) && (detail.conversion_page_url != '')) 95 { 96 eid = key; 97 } 98 else if(current_page.includes(detail.conversion_page_id) || current_page.includes(parseInt(detail.conversion_page_id))) 99 { 100 eid = key; 101 } 102 else 103 { 104 return true; // skip to the next one 105 } 106 107 variation = abstGetCookie('btab_'+eid); 108 109 if(!variation) 110 return true; // skip to the next one 111 112 variation = JSON.parse(variation); 113 114 //skip if its already converted 115 if( variation.conversion == 1 ) 116 return true; // skip to the next one 117 conversionValue = 1; 118 if(window.abst.abConversionValue && detail.use_order_value == true)// woo etc 119 conversionValue = window.abst.abConversionValue; 120 121 bt_experiment_w(eid,variation.variation,'conversion',false,conversionValue); 122 });
123 124 } 125 126 //foreach experiment 127 if (typeof bt_experiments !== 'undefined') 128 { 129 // check for css classes, then add attributes 130 jQuery("[class^='ab-'],[class*=' ab-']").each(function(e){ 131 if(jQuery(this).attr('class').includes('ab-var-') || jQuery(this).attr('class').includes('ab-convert')) 132 { 133 allClasses = jQuery(this).attr('class'); 134 allClasses = allClasses.split(" "); // into an array 135 thisTestVar = false; 136 thisTestGoal = false; 137 thisTestId = false; 138 thisTestConversion = false; 139 allClasses.forEach(function(element) { 140 141 if(element.startsWith('ab-var-')) 142 thisTestVar = element; 143 else if (element.startsWith('ab-goal-')) 144 thisTestGoal = element; 145 else if(element.startsWith('ab-') && !element.includes('ab-convert') ) 146 thisTestId = element; 147 if(element == 'ab-convert') 148 thisTestConversion = true; 149 150 }); 151 152 if(thisTestVar !== false && thisTestId !== false) 153 { 154 //we've got variations, do ya thing! 155 jQuery(this).attr('bt-eid',thisTestId.replace("ab-","")); 156 jQuery(this).attr('bt-variation',thisTestVar.replace("ab-var-","")); 157 } 158 159 if(thisTestConversion == true && thisTestId !== false) 160 { 161 // it's a conversion, convert! 162 abstConvert(thisTestId.replace("ab-","")); 163 } 164 165 if(thisTestGoal == true && thisTestId !== false) 166 { 167 //its a goal, record it! 168 abstGoal(thisTestId.replace("ab-",""),thisTestGoal.replace("ab-goal-","")); 169 } 170 } 171 172 if(jQuery(this).attr('class').includes('ab-click-convert-')) 173 { 174 175 jQuery(this).attr('class').split(" ").forEach(function(element) { // loop through all classes 176 if(element.trim().startsWith('ab-click-convert-')) 177 abClickListener(element.replace("ab-click-convert-",""),"."+element); 178 }); 179 180 } 181 182 }); 183 184 // legacy probably can be removed, check bricks 185 jQuery("[data-bt-variation]").each(function(){ 186 jQuery(this).attr('bt-variation',jQuery(this).attr('data-bt-variation')); 187 jQuery(this).attr('bt-eid',jQuery(this).attr('data-bt-eid')); 188 }); 189 190 191 //fix bricks child attributes 192 //fix bricks, move attr's up one level 193 document.querySelectorAll(".bricks-element [bt-eid]").forEach(el => { 194 let parent = el.closest('.bricks-element'); 195 parent.setAttribute('bt-eid', el.getAttribute('bt-eid')); 196 parent.setAttribute('bt-variation', el.getAttribute('bt-variation')); 197 el.removeAttribute('bt-eid'); 198 el.removeAttribute('bt-variation'); 199 }); 200 201 jQuery.each(bt_experiments, function(experimentId, experiment) { 202 203 // if there is a winner, AND the current page is the default page and AUTOCOMPLETE then just go straight there do not pass go 204 if(experiment.test_winner) 205 { 206 if(experiment.test_type == 'full_page' && (experiment.full_page_default_page == btab_vars.post_id)) // if full p and the p is this page 207 { 208 if(experiment.test_winner !== btab_vars.post_id) // if its not the current page 209 { 210 if(experiment.page_variations[experiment.test_winner] == undefined) // if its not defined 211 { 212 console.log('split test winner is not found, not redirecting'); 213 return false; // skip 214 } 215 216 console.log('Split Test winner is page redirect. Redirecting to '+ experiment.page_variations[experiment.test_winner]); 217 //only do it if its defined 218 window.location.replace( abRedirectUrl(experiment.page_variations[experiment.test_winner])); 219 220 return false; 221 } 222 else // it is the current page so show it 223 { 224 console.log('Test winner is current page. Showing '+ experiment.test_winner); 225 document.body.classList.add('abst-show-page'); 226 return false; // skip 2 next experiment 227 } 228 229 } 230 else if(experiment.test_type == 'css_test') 231 { 232 console.log('Split Test CSS winner. Showing '+ experiment.test_winner); 233 jQuery('body').addClass(experiment.test_winner); 234 } // text test winner todo 235 else // on page test 236 { 237 console.log('Split Test winner is on this page. Showing '+ experiment.test_winner); 238 jQuery('*[bt-eid=\"'+experimentId+'\"][bt-variation=\"'+experiment.test_winner+'\"]').addClass('bt-show-variation'); //maybe not necessary anymore now we have CSS? 239 //show variation 240 } 241 return true; 242 //skip this experiment 243 } 244 245 if(experiment.test_type == "css_test") 246 { 247 for (var i = 0; i < experiment.css_test_variations; i++) { 248 // Code to be executed for each element 249 jQuery('body').append('<script class="bt-css-scripts" bt-variation="test-css-'+experimentId+'-'+ (i+1)+ '" bt-eid="'+experimentId+'"/>'); 250 } 251 } 252 253 //full page test handler 254 if(experiment.test_type == 'full_page' && experiment.full_page_default_page == btab_vars.post_id) 255 { 256 //add original do nothing variation 257 jQuery('body').append('<div class="bt-redirect-handle" style="display: none !important" bt-variation="'+experiment.full_page_default_page+'" bt-eid="'+experimentId+'"></div>'); 258 //foreach variation 259 jQuery.each(experiment.page_variations,function(varId,variation){ 260 jQuery('body').append('<div class="bt-redirect-handle" style="display: none !important" bt-variation="'+varId+'" bt-eid="'+experimentId+'" bt-url="'+variation+'"></div>'); 261 }); 262 } 263 264 265 //add conversion click handlers 266 if(experiment.conversion_page == 'selector') 267 { 268 if(experiment.conversion_selector != '') 269 { 270 var conversionSelector = experiment.conversion_selector; 271 abClickListener(experimentId,conversionSelector, 0); 272 } 273 } 274 275 276 // if experiment goals exists 277 //loop through 278 for (var i = 1; i < Object.keys(experiment['goals']).length; i++) { 279 // if experiment.goals[i] key is click 280 //get key name for goal 281 const firstKey = Object.keys(experiment['goals'][i])[0]; 282 283 284 // click selector 285 if(firstKey === 'selector') 286 { 287 abClickListener(experimentId,experiment['goals'][i]['selector'], i); 288 } 289 290 // text subgoall 291 startInverval = false; 292 if(firstKey === 'text') 293 { 294 startInverval = true; 295
296 convstatus = abstGetCookie('btab_'+experimentId); 297 if(startInverval && convstatus) // if test exists and not false 298 { 299 convstatus = JSON.parse(convstatus); 300 if (convstatus && convstatus['goals'] && convstatus['goals'][i] == 1) 301 startInverval = false; 302 } 303 304 if(experiment['goals'][i]['text'] == '') 305 startInverval = false; 306 307 //if text exists and not complete 308 if(startInverval) 309 { 310 startTextWatcher(experimentId,experiment['goals'][i]['text'],i); 311 } 312 } 313 314 if(firstKey === 'page') 315 { 316 var goalPage = experiment['goals'][i]['page']; 317 318 if(goalPage == btab_vars.post_id){ 319 abstGoal(experimentId,i); 320 } 321 } 322 323 if(firstKey === 'url') 324 { 325 page_url = window.location.href.replace(window.location.origin,''); 326 if (page_url.charAt(0) == "/") page_url = page_url.substr(1); 327 if (page_url.charAt(page_url.length - 1) == "/") page_url = page_url.substr(0, page_url.length - 1); 328 329 goal_url = experiment['goals'][i]['url'].replace(window.location.origin,''); 330 if (goal_url.charAt(0) == "/") goal_url = goal_url.substr(1); 331 if (goal_url.charAt(goal_url.length - 1) == "/") goal_url = goal_url.substr(0, goal_url.length - 1); 332 333 if(page_url == goal_url){ 334 abstGoal(experimentId,i); 335 } 336 337 } 338 339 } 340 341 342 343 //text conversion 344 if(experiment.conversion_page == 'text') 345 { 346 startInverval = true; 347 if(!bt_experiments[experimentId]) 348 startInverval = false; // not if not defined 349 350 convstatus = abstGetCookie('btab_'+experimentId); 351 if(startInverval && convstatus) // if test exists and not false 352 { 353 convstatus = JSON.parse(convstatus); 354 if(convstatus.conversion == 1) // if its converted 355 startInverval = false; 356 } 357 358 if(experiment.conversion_text == '') 359 startInverval = false; 360 361 //if text exists and not complete 362 if(startInverval) 363 { 364 startTextWatcher(experimentId,experiment.conversion_text); 365 } 366 } 367 368 //text subgoals 369 370 371 372 373 if(experiment.conversion_page == 'surecart-order-paid' && window.scData ) // if surecart is slected and surecart js is detected 374 { 375 document.addEventListener('scOrderPaid', function(e) { // add listener 376 console.log('surecart OrderPaid'); 377 const checkout = e.detail; 378 if( checkout && checkout.amount_due ) { 379 if( experiment.use_order_value == true) 380 window.abst.abConversionValue = checkout.amount_due; // set value 381 abstConvert(experimentId, window.abst.abConversionValue); 382 } 383 }); 384 } 385 386 387 if( experiment.conversion_page == 'fingerprint' && !localStorage.getItem("ab-uuid") ) { 388 console.log("ab-uuid: set fingerprint"); 389 setAbFingerprint(); 390 } 391 392 }); 393 394 395 var experiments_el = jQuery('[bt-eid]:not([bt-eid=""])[bt-variation]:not([bt-variation=""])'); 396 var current_exp = {}; 397 var exp_redirect = {}; 398 399 experiments_el.each(function(e) { 400 var me = jQuery(this), 401 experimentId = me.attr('bt-eid'), 402 variation = me.attr('bt-variation'), 403 redirect_url = me.attr('bt-url'); 404 405 if( current_exp[experimentId] === undefined ) { 406 current_exp[experimentId] = []; 407 exp_redirect[experimentId] = []; 408 } 409 if (!current_exp[experimentId].includes(variation)) { 410 current_exp[experimentId].push(variation); 411 exp_redirect[experimentId][variation] = redirect_url; 412 } 413 414 }); 415 416 // add css tests to current exp 417 jQuery.each(bt_experiments, function(experimentId, value) { 418 // Code to be executed for each element 419 if(bt_experiments[experimentId]['test_type'] == 'css_test') 420 { 421 current_exp[experimentId] = []; // create 422 exp_redirect[experimentId] = []; 423 424 for (var i = 1; i <= parseInt(bt_experiments[experimentId]['css_test_variations']); i++) { 425 current_exp[experimentId].push('test-css-'+experimentId+'-'+i); 426 exp_redirect[experimentId]['test-css-'+experimentId+'-'+i] = ''; 427 } 428 } 429 }); 430 431 jQuery.each(current_exp, function(experimentId, variations) { 432 //check it exists 433 if( bt_experiments[experimentId] === undefined ) { 434 console.log("ABST: " +'Test ID '+ experimentId +' does not exist.'); 435 showSkippedVisitorDefault(experimentId); 436 return true; // continue to next exp 437 } 438 439 // if there is a winner for the test, then do no more - its already done above 440 if( bt_experiments[experimentId].test_winner) 441 return true; // continue to next exp 442 443 //if cookie consent isnt done, then show default 444 if ('BorlabsCookie' in window) 445 { 446 // borlabs v2 447 if (typeof window.BorlabsCookie.checkCookieConsent === 'function' && 448 !window.BorlabsCookie.checkCookieConsent('split-test') && 449 !window.BorlabsCookie.checkCookieConsent('ab-split-test')) 450 { 451 console.log('Borlabs cookie consent prevented a split test from running'); 452 showSkippedVisitorDefault(experimentId); 453 return true; // continue to next exp 454 } 455 //borlabs v3 456 if(typeof window.BorlabsCookie.Consents.hasConsent === 'function') 457 { 458 if(!window.BorlabsCookie.Consents.hasConsent('split-test') && !window.BorlabsCookie.Consents.hasConsent('ab-split-test') ) 459 { 460 console.log('Borlabs v3 cookie consent prevented a split test from running'); 461 showSkippedVisitorDefault(experimentId); 462 return true; // continue to next exp 463 } 464 } 465 } 466 467 468 469 if( bt_experiments[experimentId]['is_current_user_track'] == false ) { 470 showSkippedVisitorDefault(experimentId); 471 return true; // continue to next exp 472 } 473 474 // if the test is not published 475 if( bt_experiments[experimentId]['test_status'] !== 'publish' ) { 476 showSkippedVisitorDefault(experimentId); 477 return true; // continue to next exp 478 } 479 480 var targetVisitor = true; 481 482 var btab = abstGetCookie('btab_'+ experimentId); 483 484 var experimentVariation = ''; 485 486 if( !btab ) // no existing data, create 487 { 488 if(bt_experiments[experimentId]['test_type'] == 'css_test'){ 489 var randVar = getRandomInt(1, parseInt(bt_experiments[experimentId]['css_test_variations'])) - 1; 490 } 491 else 492 var randVar = getRandomInt(1, variations.length) - 1; 493 494 if(btab_vars.is_free && variations.length > 2){ 495 var randVar = getRandomInt(0, 1); //limit to 2 496 console.log('Free version of AB Split Test is limited to 1 variation. Your others will not be shown. Upgrade: https://absplittest.com/pricing?ref=ug'); 497 } 498 499 experimentVariation = variations[randVar]; 500 } 501 else //parse existing data 502 { 503 504 try { 505 var btab_cookie = JSON.parse(btab); 506 experimentVariation = btab_cookie.variation; 507 } catch (err) { 508 console.log('Error parsing cookie data:', err); 509 } 510 511 } 512 513 var variation_element = false; 514 if(bt_experiments[experimentId]['test_type'] == 'css_test') 515 { 516 jQuery('body').addClass(experimentVariation); 517 } 518 else // on page tests 519 { 520 variation_element = jQuery('*[bt-eid=\"'+experimentId+'\"][bt-variation=\"'+experimentVariation+'\"]'); 521 } 522 523 if( btab ){ 524 btab = JSON.parse( btab ); 525 var redirect_url = exp_redirect[experimentId][experimentVariation]; 526 if( redirect_url && !btab_vars.is_preview ) { 527 window.location.replace( abRedirectUrl( redirect_url) ); 528 } 529 else 530 { 531 abstShowPage(); // full page 532 if(variation_element) 533 variation_element.addClass('bt-show-variation'); // on page 534 } 535 return true; // continue to next exp 536 } 537 538 if( !btab ) { // new user, check tartgeting 539 540 var targetPercentage = bt_experiments[experimentId].target_percentage; 541 542 if(targetPercentage == '') 543 targetPercentage = 100; 544 545 var url_query = bt_experiments[experimentId].url_query; 546 urlQueryResult = null; 547 548 //we've got a url query 549 if(url_query !== '') 550 { 551 552 var exploded_query = url_query.trim().split("="); 553 if(exploded_query.length == 1) // just the query key 554 { 555 targetVisitor = bt_getQueryVariable(exploded_query[0]); 556 } 557 else if(exploded_query.length == 2) //query key and value 558 { 559 urlQueryResult = bt_getQueryVariable(exploded_query[0]); 560 targetVisitor = exploded_query[1] == urlQueryResult; 561 } 562 } 563 564 var target_option_device_size = bt_experiments[experimentId].target_option_device_size; 565 566 if(targetVisitor && target_option_device_size != 'all') 567 { 568 var device_size = jQuery(window).width(); 569 if(device_size > 767) 570 device_size = 'desktop'; 571 else if(device_size > 479) 572 device_size = 'tablet'; 573 else 574 device_size = 'mobile'; 575 576 targetVisitor = target_option_device_size.includes(device_size); 577 578 } 579 580 581 if(!targetVisitor) 582 { 583 showSkippedVisitorDefault(experimentId); 584 return true; // continue to next exp 585 } 586 // randomly target users according to percentage 587 var percentage = getRandomInt(1,100); 588 if(targetPercentage < percentage) 589 { 590 showSkippedVisitorDefault(experimentId,true); 591 console.log('ABST ' + experimentId+' skipped not in percentage target'); 592 return true; // continue to next exp 593 } 594 595 // no experiment cookie set, calculate and create 596 bt_experiments[experimentId].variations = bt_get_variations(experimentId); 597 } 598 599 if(variation_element && !variation_element.length) 600 { 601 showSkippedVisitorDefault(experimentId); 602 console.log('ABST variation doesnt exist, or doesnt match'); 603 return true; // continue to next exp 604 } 605 606 if (Object.keys(exp_redirect).length > 0) 607 { 608 redirect_url = exp_redirect[experimentId]; 609 redirect_url = redirect_url[experimentVariation]; 610 } 611 else 612 redirect_url = ''; 613 614 // if its css, add it to body 615 if(variation_element) 616 variation_element.addClass('bt-show-variation'); 617 bt_experiment_w(experimentId,experimentVariation,'visit', redirect_url); 618 }); 619 } 620 621 // warn users on localhost 622 if(btIsLocalhost()) 623 console.info("AB Split Test: It looks like you're on a localhost, using local storage instead of cookies. External Conversion Pixels will not work on Local web servers."); 624 625 window.dispatchEvent(new Event('resize')); // trigger a window resize event. Useful for sliders etc. that dynamically resize 626 jQuery('body').trigger('ab-test-setup-complete'); // the end of the ab testing. do other things if you like with jQuery('body').bind('ab-test-setup-complete', function() { //do what you want! }); 627 628}); 629 630function startTextWatcher(experimentId,word,goalId = null){ 631 632 if(!goalId) 633 goalId = 0; 634 635 if (typeof abst.intervals[experimentId] === 'undefined') { 636 abst.intervals[experimentId] = {}; 637 } 638 639 window.abst.intervals[experimentId][goalId] = setInterval(function () { 640 let found = false; 641 642 // Search within the main page more efficiently 643 jQuery("body").find(":contains('" + word + "')").each(function () { 644 if (jQuery(this).text().indexOf(word) >= 0 && jQuery(this).is(":visible")) { 645 found = true; 646 return false; // Break the loop 647 } 648 });
649 650 if (!found) { 651 jQuery("iframe").each(function () { 652 try { 653 var iframeBody = jQuery(this).contents().find("body"); 654 found = iframeBody.find(":contains('" + word + "')").filter(function () { 655 return jQuery(this).text().indexOf(word) >= 0 && jQuery(this).is(":visible"); 656 }).length > 0; 657 658 if (found){ 659 console.log('ABST: ' + experimentId + ' ' + word); 660 return false; // Break the loop 661 } 662 } catch (error) { 663 //console.error("Error accessing iframe contents:", error); 664 } 665 }); 666 } 667 668 if(found){ 669 if(goalId == 0) 670 { 671 abstConvert(experimentId); 672 } 673 else 674 { 675 abstGoal(experimentId,goalId); 676 } 677 clearInterval(window.abst.intervals[experimentId][goalId]); // Stop the interval after finding the word 678 } 679 }, 1000); 680 } 681 682 683 function abstConvert(testId = '',orderValue = 1){ 684 console.log('abstConvert',testId,orderValue); 685 if(testId !== '') 686 { 687 var btab = abstGetCookie('btab_'+ testId); 688 if(btab) 689 { 690 btab = JSON.parse(btab); 691 if(btab.conversion == 0) 692 { 693 bt_experiment_w(testId,btab.variation,'conversion',false,orderValue); 694 btab.conversion = 1; 695 experiment_vars = JSON.stringify(btab); 696 abstSetCookie('btab_'+ testId, experiment_vars, 1000); 697 if(abst.intervals[testId]){ 698 clearInterval(abst.intervals[testId]); 699 } 700 } 701 else 702 { 703 console.log("ABST: " +bt_experiments[testId].name + ': Visitor has already converted'); 704 } 705 } 706 else 707 { 708 if(!bt_experiments[testId]) 709 console.log("ABST: " +'Test ID not found or test not active'); 710 } 711 } 712 } 713 714 function abstGoal(testId = '',goal = ''){ 715 // console.log('start abstGoal',testId,goal); 716 if(testId !== '' && goal !== '') 717 { 718 var btab = abstGetCookie('btab_'+ testId); 719 if(btab) 720 { 721 btab = JSON.parse(btab); 722 //console.log('btab',btab); 723 if(btab.conversion !== 1) // no goals after conversion 724 { 725 if(Array.isArray(btab.goals)) 726 { 727 //if its not in the goal 728 if(btab.goals[goal] !== 0) 729 { 730 btab.goals[goal] = 1; 731 bt_experiment_w(testId,btab.variation,goal,false,1); 732 } 733 734 experiment_vars = JSON.stringify(btab); 735 abstSetCookie('btab_'+ testId, experiment_vars, 1000); 736 if(abst.intervals[testId+""+goal]) 737 { 738 clearInterval(abst.intervals[testId+""+goal]); 739 } 740 } 741 else 742 { 743 console.log("ABST: " +bt_experiments[testId].name + ': Visitor has already goaled'); 744 } 745 } 746 //else 747 //console.log('no goals after conversion'); 748 } 749 else 750 { 751 if(!bt_experiments[testId]) 752 console.log("ABST: " +'Test ID not found or test not active'); 753 } 754 } 755 } 756 757function showSkippedVisitorDefault(eid,createCookie = false){ 758 759 if(!window.bt_experiments[eid]){ // if no experiment, show first variations 760 761 btv = jQuery('*[bt-eid=\"'+eid+'\"]').first().attr('bt-variation'); 762 jQuery('*[bt-eid=\"'+eid+'\"][bt-variation=\"'+btv+'\"]').addClass('bt-show-variation'); 763 return true; 764 } 765 766 if(bt_experiments[eid].test_winner !== ''){ // if we have a winner 767 768 if(bt_experiments[eid].test_type =="full_page") // full page winner 769 { 770 url = bt_experiments[eid].page_variations[bt_experiments[eid].test_winner]; 771 if(url !== undefined) 772 { 773 window.location.replace( abRedirectUrl(url) ); // follow the link w search params 774 return true; 775 } 776 else 777 { 778 console.log("ABST: " +'Full page test complete without matching page winner. Showing current page.'); 779 } 780 abstShowPage(); 781 } 782 783 if(bt_experiments[eid].test_type == "css_test") // css winner 784 { 785 console.log('css test winner, showing ver ' + bt_experiments[eid]['test_winner']); 786 jQuery("body").addClass('test-css-'+eid+'-'+bt_experiments[eid]['test_winner']); // add winning class 787 return true; // next 788 } 789 } 790 791 if(bt_experiments[eid].test_type == "full_page") 792 { 793 abstShowPage(); 794 if(createCookie) 795 skippedCookie(eid,bt_experiments[eid].full_page_default_page); 796 797 return true; // next 798 } 799 800 if(bt_experiments[eid].test_type == "css_test") // css version 1 801 { 802 jQuery("body").addClass('test-css-'+eid+'-1'); // add 1 class 803 if(createCookie) 804 skippedCookie(eid,'test-css-'+eid+'-1'); 805 return true; // next 806 } 807 808 //on page tests only from here 809 810 if(!eid) 811 return; 812 var foundSpecial = false; 813 jQuery('*[bt-eid=\"'+eid+'\"]').each(function(index, element){ 814 var variationName = jQuery(element).attr('bt-variation').toLowerCase(); 815 var defaultNames = ["original","one","1","default","standard","a","control"]; 816 if(defaultNames.includes(variationName)) 817 { 818 btv = variationName; 819 jQuery(element).addClass('bt-show-variation'); // show the matched element 820 foundSpecial = true; 821 } 822 }); 823 if(!foundSpecial){ 824 btv = jQuery('*[bt-eid=\"'+eid+'\"]').first().attr('bt-variation'); 825 jQuery('*[bt-eid=\"'+eid+'\"][bt-variation=\"'+btv+'\"]').addClass('bt-show-variation'); 826 } 827 828 if(createCookie) 829 skippedCookie(eid,btv); 830 831} 832function skippedCookie(eid,btv){ 833 var experiment_vars = { 834 eid: eid, 835 variation: btv, 836 conversion: 1, 837 skipped:1 838 }; 839 experiment_vars = JSON.stringify(experiment_vars); 840 abstSetCookie('btab_'+ eid, experiment_vars, 1000); 841 return true; 842} 843 844//takes input slug or url and ends url suitable for window/replace 845function abRedirectUrl(url){ 846 847 url = url + window.location.search + window.location.hash; 848 // if it starts with http/s dop nothing 849 if(url.startsWith('http') || url.startsWith('/')) 850 return url; 851 else 852 return '/' + url; 853 854} 855 856function abstOneSecond(){ 857 if(Object.keys(window.abst.timer).length > 0) 858 { 859 Object.entries(window.abst.timer).forEach(([ index,item]) => { 860 if(window.abst.timer[index] > -1) // dont decrease below -1 861 window.abst.timer[index] = window.abst.timer[index] - 1; 862 863 if(window.abst.timer[index] == 0){ // convert if its counted down, only fired once 864 865 //console.log('time active converting ' + index); 866 //index could be goal-eid-goalid 867 if(index.includes('goal-')) 868 { 869 var parts = index.split('-'); 870 abstGoal(parts[1],parts[2]); 871 } 872 else 873 abstConvert(index); 874 875 } 876 });
877 878 // update localstorage 879 localStorage.absttimer = JSON.stringify(window.abst.timer); // localstorage need strings 880 } 881} 882 883 884 885function userActiveNow(){ 886 window.abst.currscroll = window.scrollY; // update last known scroll n mouse 887 window.abst.abactive = true; // we active 888 clearTimeout(window.abst.timeoutTimer); // delete the old timout 889 window.abst.timeoutTimer = setTimeout(abstActiveTimeout, window.abst.timeoutTime); // create new timeout 890} 891 892function abstActiveTimeout(){ 893 window.abst.abactive = false; 894} 895 896 897function getRandomInt(min, max) { 898 min = Math.ceil(min); 899 max = Math.floor(max); 900 return Math.floor(Math.random() * (max - min + 1)) + min; 901} 902 903function abstSetCookie(c_name, value, exdays) { 904 if(btIsLocalhost()) 905 return btSetLocal(c_name,value); 906 907 var exdate = new Date(); 908 exdate.setDate(exdate.getDate() + exdays); 909 var c_value = escape(value) + ((exdays == null) ? '' : ';path=/; expires=' + exdate.toUTCString()) + "; SameSite=None; Secure"; 910 911 document.cookie = c_name + '=' + c_value; 912} 913function deleteCookie(c_name) { 914 if(btIsLocalhost()) 915 return btDeleteLocal(c_name); 916 917 document.cookie = c_name+"= ; expires = Thu, 01 Jan 1970 00:00:00 GMT"; 918} 919 920function abstGetCookie(c_name) { 921 if(btIsLocalhost()) 922 return btGetLocal(c_name); 923 924 var i, x, y, ARRcookies = document.cookie.split(';'); 925 for (i = 0; i < ARRcookies.length; i++) { 926 x = ARRcookies[i].substr(0, ARRcookies[i].indexOf('=')); 927 y = ARRcookies[i].substr(ARRcookies[i].indexOf('=') + 1); 928 x = x.replace(/^\s+|\s+$/g, ''); 929 if (x == c_name) { 930 return unescape(y); 931 } 932 } 933} 934 935function abstShowPage(){ 936 jQuery("body").addClass('abst-show-page'); 937 jQuery("body",parent.window.document).addClass('abst-show-page'); // bb iframe UI 938} 939 940function btSetLocal(c_name,value){ 941 localStorage.setItem(c_name, value); 942} 943 944function btGetLocal(c_name){ 945 return localStorage.getItem(c_name); 946} 947 948function btDeleteLocal(c_name){ 949 localStorage.removeItem(c_name); 950} 951 952function btIsLocalhost(){ 953 return (location.hostname === "localhost" || location.hostname === "127.0.0.1"|| location.hostname.endsWith(".local")|| location.hostname.endsWith(".test")); 954} 955 956function bt_get_variations(eid){ 957 958 variation = []; 959 jQuery('[bt-eid=' + eid + ']').each(function (index, val) { 960 var newVariation = jQuery(this).attr('bt-variation'); 961 962 // Check if the variation already exists in the array 963 if (variation.indexOf(newVariation) === -1) { 964 variation.push(newVariation); 965 } 966 }); 967 968 if(btab_vars.is_free) 969 { 970 //only return first 2 variations 971 variation = variation.slice(0,2); 972 } 973 974 return variation; 975} 976 977function bt_experiment_w(eid,variation,type, url,orderValue=1){ 978 979 // dont log it if its a skipper or malformed 980 if(variation == '_bt_skip_' || btab_vars.is_preview || !eid || !variation) 981 { 982 return true; 983 } 984 985 // if its a fingerprinter and we dont have a uuid, then wait for it 986 if(bt_experiments[eid].conversion_page == 'fingerprint' && !localStorage.getItem('ab-uuid')) 987 { 988 console.log("bt_exp_w: waiting for fingerprint"); 989 setTimeout(bt_experiment_w, 500, eid, variation, type, url,orderValue); 990 return true; //back in 500ms 991 } 992 993 var data = { 994 'action': 'bt_experiment_w', 995 'eid' : eid, 996 'variation' : variation, 997 'type' : type, 998 'size' : abst.size, 999 'location' : btab_vars.post_id, 1000 'orderValue': orderValue 1001 }; 1002 1003 btab_track_event(data); // analytics tagger 1004 1005 var experiment_vars = { 1006 eid: eid, 1007 variation: variation, 1008 conversion: 0, 1009 goals:[], 1010 }; 1011 1012 // set up time watchers 1013 if( type == 'visit' && bt_experiments[eid]['conversion_page'] == 'time') 1014 { 1015 window.abst.timer[eid] = bt_experiments[eid]['conversion_time']; 1016 } 1017 //goal time watcher 1018 if( type == 'visit') 1019 { 1020 // console.log(bt_experiments[eid]['goals']); 1021 //foreach goals 1022 jQuery.each(bt_experiments[eid]['goals'], function(key, value) { 1023 // if valuee.time is set 1024 if(value['time'] > 0) 1025 { 1026 window.abst.timer["goal-"+eid + "-"+key] = value['time']; 1027 } 1028 });
1029 1030 } 1031 1032 // set up conversion 1033 if( type == 'conversion' ) 1034 experiment_vars.conversion = 1; 1035 else if ( type == 'visit' ) 1036 { 1037 // not conversion or goal 1038 } 1039 else // goal 1040 { 1041 experiment_vars.goals[type] = 1; // add to goals list 1042 } 1043 1044 1045 //add uuid if necessary 1046 if( bt_experiments[eid]['conversion_page'] == 'fingerprint' ) 1047 data.uuid = localStorage.getItem('ab-uuid'); 1048 1049 experiment_vars = JSON.stringify(experiment_vars); 1050 abstSetCookie('btab_'+ eid, experiment_vars, 1000); 1051 //show the page if its not a redirect or external 1052 if(url !== "ex" && !url) 1053 { 1054 abstShowPage(); // show the page 1055 } 1056 1057 //send it to WP to log 1058 // use beacon the data 1059 console.log('sent beacon',data); 1060 navigator.sendBeacon(bt_ajaxurl+"?action=bt_experiment_w&method=beacon",JSON.stringify(data)); // send the data 1061 1062 // if its a full page redirect, set cookie then redirect then log visit 1063 if(type == 'visit' && url ){ 1064 console.log('redirecting after beacon'); 1065 window.location.replace( abRedirectUrl(url)); 1066 } 1067 1068 return true; 1069} 1070 1071async function btab_track_event(data){ 1072 1073 //create javascript event with data 1074 jQuery('body').trigger('abst_event', [data]); 1075 1076 if(btab_vars.tagging == '0'){ 1077 //console.log('event tagging turned off'); 1078 return false; 1079 } 1080 1081 window.abeventstarted = new Date().getTime(); // give up sending events after 5 seconds 1082 //set up vals 1083 var trackName = bt_experiments[data.eid].name; 1084 if(trackName == '') 1085 trackName = data.eid; 1086 1087 var trackCat = data.type; 1088 var trackValue = data.variation; 1089 1090 //google analytics 4 for all 1091 window.abst.abga4 = setInterval(function(){ 1092 if(typeof gtag === "function"){ // if using gtag 1093 gtag('event', 'ab_split_test', { //custom event 1094 'test_name': trackName, 1095 'test_variation': trackValue, 1096 'test_event': trackCat 1097 }); 1098 clearInterval(window.abst.abga4); 1099 return; 1100 } 1101 1102 if(window.dataLayer && typeof window.dataLayer.push === "function"){ // if using GTM 1103 1104 window.dataLayer.push({ 1105 'event': 'ab_split_test', 1106 'test_name': trackName, 1107 'test_variation': trackValue, 1108 'test_event': trackCat 1109 }); 1110 clearInterval(window.abst.abga4); 1111 } 1112 1113 if(new Date().getTime() - window.abeventstarted > 5000)//quit after 5s 1114 clearInterval(window.abst.abga4); 1115 },499); 1116 1117 1118 1119 if(btab_vars.is_agency == '1') //agency only after here 1120 { 1121 trackName = "AB Test: " + trackName; 1122 window.abst = window.abst || {}; 1123 window.abst.abconvertpartner = window.abst.abconvertpartner || {}; 1124 window.abst.abconvertpartner.abawp = false; 1125 window.abst.abconvertpartner.clarity = false; 1126 window.abst.abconvertpartner.gai = false; 1127 window.abst.abconvertpartner.abmix = false; 1128 window.abst.abconvertpartner.abumav = false; 1129 window.abst.abconvertpartner.umami = false; 1130 window.abst.abconvertpartner.cabin = false; 1131 window.abst.abconvertpartner.plausible = false; 1132 window.abst.abconvertpartner.fathom = false; 1133 1134 //tag matomo 1135 var _paq = window._paq = window._paq || []; 1136 _paq.push(['trackEvent', trackName, trackCat, trackValue]); 1137 1138 window.abst.abconvertpartner.timer = setInterval(function(){ 1139 if(!window.abst.abconvertpartner.clarity) 1140 if(typeof clarity === "function"){ 1141 window.abst.abconvertpartner.clarity = true; 1142 clarity("set", trackName + "-" + trackCat, trackValue); 1143 } 1144 1145 if(!window.abst.abconvertpartner.gai) 1146 if(typeof ga === "function"){ 1147 tracker = ga.getAll()[0]; 1148 if (tracker) 1149 { 1150 tracker.send("event", trackName, trackCat, trackValue,{nonInteraction: true}); // send non interactive event to GA 1151 window.abst.abconvertpartner.gai = true; 1152 } 1153 } 1154 1155 if(!window.abst.abconvertpartner.fathom) 1156 if(window.fathom){ 1157 console.log('fathom trackEvent', trackName + ", " + trackValue + ": " + trackCat); 1158 window.abst.abconvertpartner.fathom = true; 1159 window.fathom.trackEvent(trackName + ", " + trackValue + ": " + trackCat); 1160 } 1161 1162 if(!window.abst.abconvertpartner.abmix) 1163 if(typeof mixpanel == "object"){ 1164 mixpanel.track(trackName, {'type': trackCat,'variation':trackValue}, {send_immediately: true}); 1165 window.abst.abconvertpartner.abmix = true; 1166 } 1167 1168 if(!window.abst.abconvertpartner.abumav) 1169 if(typeof usermaven === "function"){ 1170 window.abst.abconvertpartner.abumav = true; 1171 usermaven("track", trackName, { 1172 type: trackCat, 1173 variation: trackValue 1174 }); 1175 } 1176 1177 if(!window.abst.abconvertpartner.umami) 1178 if(window.umami){ 1179 window.abst.abconvertpartner.umami = true; 1180 umami.track(bt_experiments[data.eid].name, { 1181 type: trackCat, 1182 variation: trackValue 1183 }); 1184 } 1185 1186 if(!window.abst.abconvertpartner.cabin) 1187 if(window.cabin){ 1188 window.abst.abconvertpartner.cabin = true; 1189 cabin.event(bt_experiments[data.eid].name + ' | ' + trackCat + ' | ' + trackValue); 1190 } 1191 1192 if(!window.abst.abconvertpartner.plausible) 1193 if(window.plausible){ 1194 window.abst.abconvertpartner.plausible = true; 1195 plausible(bt_experiments[data.eid].name, {props: {testEvent: trackCat, variation: trackValue}}); 1196 } 1197 1198 1199 if(!window.abst.abconvertpartner.abawp) 1200 if(typeof AnalyticsWP === "object"){ 1201 window.abst.abconvertpartner.abawp = true; 1202 AnalyticsWP.event('Test: ' + bt_experiments[data.eid].name, { 1203 test_id: data.eid, 1204 test_name: bt_experiments[data.eid].name, 1205 test_variation: trackValue, 1206 test_visit_type: trackCat 1207 }); 1208 } 1209 1210 if(new Date().getTime() - window.abeventstarted > 5000) //quit after 5s 1211 clearInterval(window.abst.abconvertpartner.timer); 1212 },500); 1213 1214 1215 } // end agency tracking 1216 1217} 1218 1219// check for a full page tes tvisit cookie 1220function next_page_visit_report(){ 1221 var setvisit = abstGetCookie('ab-set-visit'); 1222 if(setvisit) 1223 { 1224 try { 1225 setvisit = JSON.parse(setvisit); 1226 1227 bt_experiment_w(setvisit.eid, setvisit.variation, setvisit.type, false, setvisit.orderValue); 1228 } catch (err) { 1229 console.log('Error parsing next page visitor report data:', err); 1230 } finally { 1231 abstSetCookie('ab-set-visit', false, 1000); 1232 } 1233 } 1234} 1235 1236function bt_getQueryVariable(variable) { 1237 var query = window.location.search.substring(1); 1238 var vars = query.split("&"); 1239 for (var i=0;i<vars.length;i++) { 1240 var pair = vars[i].split("="); 1241 if(pair[0] == variable){ 1242 if(pair[1] == null) 1243 return true; 1244 return pair[1]; 1245 } 1246 } 1247 return(false); 1248} 1249 1250if (!String.prototype.endsWith) { 1251 String.prototype.endsWith = function(search, this_len) { 1252 if (this_len === undefined || this_len > this.length) { 1253 this_len = this.length; 1254 } 1255 return this.substring(this_len - search.length, this_len) === search; 1256 }; 1257} 1258 1259 1260 1261//function to find and replace strings uin document, including str
1261ings with formatting like strong em, etc 1262function bt_replace_all(find, replace, location = 'body') { 1263 // Get the element by the provided location 1264 const element = document.querySelector(location); 1265 1266 // Function to recursively replace text 1267 function replaceText(node) { 1268 if (node.nodeType === Node.TEXT_NODE) { // Check if it's a text node 1269 // Replace text, preserving HTML entities by decoding and encoding 1270 let text = node.textContent; 1271 let div = document.createElement('div'); 1272 div.innerHTML = text.replace(new RegExp(find, 'gi'), replace); 1273 node.textContent = div.textContent || div.innerText || ""; 1274 } else { 1275 // Otherwise, handle all its children nodes 1276 node.childNodes.forEach(replaceText); 1277 } 1278 } 1279 1280 // Start the text replacement process from the chosen element 1281 replaceText(element); 1282} 1283 1284// Usage example: 1285//bt_replace_all('find text', 'replace text'); 1286 1287function bt_replace_all_html(find, replace, location = 'body') { 1288 // Get the element by the provided location 1289 const element = document.querySelector(location); 1290 1291 // Function to recursively replace HTML 1292 function replaceHTML(node) { 1293 if (node.nodeType === Node.ELEMENT_NODE) { // Check if it's an element node 1294 // Replace HTML, preserving the node structure 1295 node.innerHTML = node.innerHTML.split(find).join(replace); 1296 } else { 1297 // Otherwise, handle all its children nodes 1298 node.childNodes.forEach(replaceHTML); 1299 } 1300 } 1301 1302 // Start the HTML replacement process from the chosen element 1303 replaceHTML(element); 1304} 1305 1306function abClickListener(experimentId,conversionSelector, goalId = 0) { 1307 var testCookie = abstGetCookie('btab_'+experimentId); 1308 if(testCookie) 1309 { 1310 testCookie = JSON.parse(testCookie); 1311 if(goalId == 0) 1312 { 1313 if(testCookie.conversion == 1) 1314 { 1315 //console.log('abClickListener: already converted'); 1316 return; 1317 } 1318 } 1319 else // issa goal 1320 { 1321 if(testCookie.goals[goalId] == 1) 1322 { 1323 //console.log('abClickListener: goal already converted'); 1324 return; 1325 } 1326 } 1327 } 1328 var eventType = 'click'; // Default event type 1329 // If a pipe symbol exists, split it into the conversion selector and the event type 1330 if(conversionSelector.indexOf('|') !== -1) { 1331 var conversionParts = conversionSelector.split('|'); 1332 // Check if there are at least two conversionParts 1333 if(conversionParts.length >= 2) { 1334 conversionSelector = conversionParts[0]; // First part is the conversion selector 1335 eventType = conversionParts[1]; // Second part is the event type 1336 } 1337 } 1338 1339 try { 1340 document.addEventListener(eventType, function(event) { 1341 var target = event.target; 1342 while (target && target !== document) { 1343 if (target.matches(conversionSelector)) { 1344 //console.log(eventType + ' conversion on ' + conversionSelector + ' type ' + goalId); 1345 if(goalId > 0) 1346 abstGoal(experimentId,goalId); 1347 else 1348 abstConvert(experimentId); 1349 break; 1350 } 1351 target = target.parentNode; 1352 } 1353 }, true); 1354 } catch(error) { 1355 console.info('ABST: Invalid conversion selector:' + conversionSelector + ' ' + error + ' ' + goalId); 1356 } 1357 var iframes = document.querySelectorAll('iframe'); 1358 iframes.forEach(function(iframe) { 1359 try { 1360 var iframeDoc = iframe.contentWindow.document; 1361 iframeDoc.addEventListener(eventType, function(event) { 1362 if (event.target.matches(conversionSelector)) { 1363 console.log(eventType + ' IFRAME conversion on ' + conversionSelector); 1364 abstConvert(experimentId); 1365 } 1366 }, true); 1367 } catch (error) { 1368 //console.info('Error accessing cross-origin iframe:', error); // CORS issue, the iframe is not in the same origin and does not allow cross origin access. 1369 } 1370 }); 1371} 1372 1373 1374async function setAbFingerprint() { 1375 if(!localStorage.getItem("ab-uuid")) 1376 try { 1377 const module = await import(window.bt_pluginurl + "/js/ab-fingerprint.js"); 1378 const fp = await ThumbmarkJS.getFingerprint(); 1379 localStorage.setItem("ab-uuid", fp); 1380 console.log("set Fingerprint: " + fp); 1381 } catch (error) { 1382 1383 console.error("Error setting fingerprint:", error); 1384 } 1385 else 1386 console.log("ab-uuid: already set: " + localStorage.getItem("ab-uuid")); 1387}
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.