1var Sys = 2{ 3 Application: { 4 add_load: function (arg) { 5 $(document).ready(arg); 6 console.log("add_load: Just load once and hope it's fine", { fx: arg }); 7 }, 8 add_init: function (arg) { 9 $(document).ready(arg); 10 console.log("add_init: Just load once and hope it's fine", { fx: arg }); 11 } 12 } 13}; 14 15 16var friendArray = new Array(); 17function createNewEmailRow(dvId, textboxClassName) { 18 if (!textboxClassName) { 19 textboxClassName = 'add-friend-textbox'; 20 } 21 if(friendArray[dvId] == null) 22 { 23 friendArray[dvId] = 0; 24 } 25 // only allow 4 additional friends for emailing coupon 26 if (friendArray[dvId] < 4) { 27 friendArray[dvId]++; 28 var d = document.getElementById(dvId); 29 var _nwTxt = document.createElement('input'); 30 var _nwBr = document.createElement('br'); 31 var _nwMsg = document.createElement('span'); 32 _nwTxt.type = 'text'; 33 _nwTxt.className = textboxClassName; 34 _nwTxt.id = _nwTxt.name = 'friendEmail' + friendArray[dvId]; 35 _nwMsg.id = _nwMsg.name = 'friendMsg' + friendArray[dvId]; 36 _nwMsg.innerHTML = ' *' 37 _nwMsg.className = 'coupon-email-frnd'; 38 d.appendChild(_nwBr); 39 d.appendChild(_nwTxt); 40 d.appendChild(_nwMsg); 41 _nwTxt.addEventListener("keyup", function () { 42 _nwTxt.style.border = "1px solid #e5e5e8"; 43 _nwMsg.className = 'coupon-email-frnd'; 44 }); 45 if (friendArray[dvId] == 4) { 46 var lnkId = dvId.replace('dvFriendEmail', 'lnkNewFriend'); 47 document.getElementById(lnkId).innerHTML = ''; // disable 48 } 49 } else { 50 var lnkId = dvId.replace('dvFriendEmail', 'lnkNewFriend'); 51 document.getElementById(lnkId).innerHTML = ''; // disable 52 } 53 54} 55 56function createNewEmailRowValidate(dvId, textboxClassName, friendemail) { 57 if (friendArray[dvId] == null) { 58 friendArray[dvId] = 0; 59 } 60 if (friendArray[dvId] == 0) { 61 if ($(friendemail).val() != null && validEmail($(friendemail).val())) { 62 $(friendemail).attr("style", "border:1px solid #e5e5e8;margin-bottom: 5px;"); 63 createNewEmailRow(dvId, textboxClassName); 64 } else { 65 $(friendemail).attr("style", "border:1px solid #F50000;"); 66 } 67 } 68 else { 69 var d = document.getElementById('friendEmail' + friendArray[dvId]); 70 if (d.value && validEmail(d.value)) { 71 $('#friendEmail' + friendArray[dvId]).attr("style", "border:1px solid #e5e5e8;margin-bottom: 5px;"); 72 createNewEmailRow(dvId, textboxClassName); 73 } else { 74 $('#friendEmail' + friendArray[dvId]).attr("style", "border:1px solid #F50000;"); 75 } 76 } 77} 78 79function validEmail(email){ 80 var emailReg = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; 81 return emailReg.test(email); 82} 83 84function InvalidAddFriend(lstControl){ 85 var cntrArr = lstControl.split(';'); 86 var elm; 87 for(i=1;i<=4;i++) 88 { 89 elm = document.getElementById('friendMsg'+i); 90 if(elm !=null) 91 { 92 if (cntrArr.indexOf('friendEmail' + i) == -1) 93 { 94 elm.className = 'coupon-email-frnd'; 95 }else{ 96 elm.className = 'coupon-email-frnd-invalid'; 97 } 98 } 99 } 100} 101 102function InvalidAddFriendBorder(lstControl) { 103 var cntrArr = lstControl.split(';'); 104 var elm; 105 for (i = 1; i <= 4; i++) { 106 elm = document.getElementById('friendEmail' + i); 107 if (elm != null) { 108 if (cntrArr.indexOf('friendEmail' + i) == -1) {
109 elm.style["border"] = "1px solid #e5e5e8"; 110 } else { 111 elm.style["border"] = "1px solid #F50000"; 112 } 113 } 114 } 115 InvalidAddFriend(lstControl); 116} 117function hideCouponDetail() { } 118function EmailSuccessfullySent(Event, Action, Label) { 119 if (Event != null && Action != null && Label != null) { 120 ga('send', Event, Action, Label); 121 } 122 try { 123 recaptchaV2_reset(); 124 hideCouponDetail(); 125 } catch (e) { } 126} 127function EmailFailSent(msg) { 128 alert(msg); 129 try { 130 recaptchaV2_reset(); 131 hideCouponDetail(); 132 } catch (e) { } 133} 134 135var couponTextId = null; 136var bf_coupon_title_link = null; 137var lastPopupShown = null; 138 139function coupon_click() { 140 // flash assume yes 141 var bf_lnk = $get(bf_coupon_title_link); 142 googleTrackOut(couponTextId, 'yes'); 143 eval(bf_lnk.getAttribute('onclick').replace('return ', '').replace('this', 'bf_lnk')); 144} 145 146function pageloadingtime(){ 147 // loads all flash objects 148 149 //calculate the current time in afterload 150 afterload = (new Date()).getTime(); 151 // now use the beforeload and afterload to calculate the seconds 152 secondes = (afterload-beforeload)/1000; 153 // If necessary update in window.status 154 window.status='Page loaded in ' + secondes + ' seconds.'; 155 // Place the seconds in the innerHTML to show the results 156 document.getElementById("loadingtime").innerHTML = "<font color='white'>Page loaded in " + secondes + " seconds.</font>"; 157 158 //popDD(); 159 flashload = (new Date()).getTime(); 160 flSeconds = (flashload-afterload)/1000; 161 document.getElementById("loadingtime").innerHTML += "<br/><font color='white'>Flash and cb " + flSeconds + " seconds.</font>"; 162} 163 164function offerClick(lnk,id, isP, dest){ 165 googleTrackOut(id, isP); 166 document.location = lnk.href; 167 168 var scrollToText = '&scrollTo=' + $(document).scrollTop(); 169 var hashIndex = dest.indexOf("#"); 170 var finalDest = dest.substring(0, hashIndex) + scrollToText + dest.substring(hashIndex); 171 172 var nWinow = window.open(finalDest, '_blank'); 173 try { nWinow.focus(); } catch (er) { } 174 return false; 175} 176 177function cbOfferClick(lnk, id, isP, dest) { 178 var rnd = randomString(); 179 googleTrackOut(id, isP); 180 document.location = addQueryStringValue(lnk.href, 'rndLookup=' + rnd); 181 var nWinow = window.open(addQueryStringValue(dest, 'rndLookup=' + rnd), '_blank'); 182 try { nWinow.focus(); } catch (er) { } 183 return false; 184} 185var recaptchaV2_invisible = function (token, host) { 186 const tokenname = 'g-recaptcha-response-invis'; 187 var parentDiv = $(host).closest('div'); 188 var response = parentDiv.find(`input[name="${tokenname}"]`); 189 if (response.length == 0) { 190 response = $(`<input type="hidden" name="${tokenname}" />`).appendTo(parentDiv); 191 } 192 response.val(token); 193 $(host).closest('form').find('.recaptcha-click').click(); 194} 195 196var recaptchaV2_validation = function (response) { 197 if ('function' === typeof recaptchaV2_validation_sendtofriend_callback) { 198 recaptchaV2_validation_sendtofriend_callback(response); 199 } 200 if ('function' === typeof recaptchaV2_validation_forgotpassword_callback) { 201 recaptchaV2_validation_forgotpassword_callback(response); 202 } 203} 204//Do not call this function directly. Call recaptchaV2_render(container) 205var recaptchaV2_loader = function () { 206 recaptchaV2_loader.loadState = 2; 207 while (recaptchaV2_loader.backlog.length > 0) { 208 let nextEntry = recaptchaV2_loader.backlog.pop(); 209 $(nextEntry).attr('captchaNumber', recaptchaV2_loader.widgetCount); 210 var isInvisible = $(nextEntry).hasClass('c-invisible'); 211 212 var widgetid; 213 if (isInvisible) { 214 var hideAnimatedBadge = !$(nextEntry).hasClass('grecaptcha-nobadge') && 215 $(nextEntry).hasClass('popup-captcha-span') && 216 $(nextEntry).closest('.modal-content,.modal-content-clickout').length > 0; 217 218 if (hideAnimatedBadge) { 219 $(nextEntry).addClass('grecaptcha-nobadge'); 220 /* Hack. Don't show recaptcha badge until css "blowUpModal" animation completes. 221 * While blowUpModal animation is running, badge will be mispositioned 222 * In theory, we could wait 501ms, since the animation runs for 0.5s. In practice, that isn't usually a long enough wait. 223 * Only needed for modals (popup-captcha-span) and only if badge isn't hidden. 224 */ 225 $(document).one('animationend', '.modal-content,.modal-content-clickout', function () { 226 $(nextEntry).removeClass('grecaptcha-nobadge'); 227 }); 228 setTimeout(function () { 229 $(nextEntry).removeClass('grecaptcha-nobadge'); 230 }, 750); 231 } 232 widgetid = grecaptcha.render(nextEntry, { 233 'sitekey': '6Lf2MscpAAAAANHlrwxJMY7manlrIITazmr9BnLF', 'size': 'invisible', 'badge':'bottomright', 'callback': function (token) { recaptchaV2_invisible(token, nextEntry); } 234 }); 235 236 237 } else { 238 widgetid = grecaptcha.render(nextEntry, { 239 'sitekey': '6LcpK6spAAAAADSFvKOGpPE0zDqqMEET_diXHehQ', 'callback': recaptchaV2_validation 240 }); 241 } 242 recaptchaV2_loader.recaptchawidgets[recaptchaV2_loader.widgetCount] = widgetid; 243 recaptchaV2_loader.widgetCount++; 244 } 245}; 246recaptchaV2_loader.widgetCount = 0; 247recaptchaV2_loader.loadState = 0; 248recaptchaV2_loader.backlog = []; 249recaptchaV2_loader.recaptchawidgets = {}; 250 251//Usage: 252//This clears the recaptchawidgets backlog/widget count/load state/etc. so a shell load will have a fresh start. 253var reset_recaptchav2_Loader = function () { 254 recaptchaV2_loader.widgetCount = 0; 255 recaptchaV2_loader.loadState = 0; 256 recaptchaV2_loader.backlog = []; 257 recaptchaV2_loader.recaptchawidgets = {}; 258} 259 260//Usage:
261//recaptchaV2_render(container): Load recaptcha in container. If already loaded, resets it. 262//recaptchaV2_render(): Preload Recaptcha script. Resets all captchas. 263var recaptchaV2_render = function (container) { 264 if (container && document.querySelectorAll(container).length<=0) { 265 // Tried to call render on a captcha that's been hidden or does not exist; update all existing captchas 266 console.log("Error adding Recaptcha to hidden container: " + container); 267 recaptchaV2_render(); 268 return; 269 } 270 document.querySelectorAll(container).forEach(node => { 271 var currentWidget 272 if (!!$(node).attr('captchaNumber')) 273 currentWidget = recaptchaV2_loader.recaptchawidgets[$(node).attr('captchaNumber')]; 274 //containerIsEmpty is used to see if the div is empty. It will be empty if there is curently a widget when the captcha is in a updatepanel. 275 var containerIsEmpty = $(node).attr('captchaNumber')==undefined 276 //There's already a recaptcha here. Reset it. 277 if (typeof (node) !== "undefined" && !containerIsEmpty) { 278 grecaptcha.reset(node); 279 return; 280 } 281 if ($(node)) { 282 recaptchaV2_loader.backlog.push(node); 283 } 284 }); 285 286 switch (recaptchaV2_loader.loadState) { 287 case 0: //Recaptcha is not loaded 288 recaptchaV2_loader.loadState = 1; 289 $.getScript('//www.google.com/recaptcha/api.js?onload=recaptchaV2_loader&render=explicit'); 290 break; 291 case 1: //Recaptcha is busy loading. 292 break; 293 case 2: //Recaptcha is already loaded. 294 if (!container) { 295 //Reset all captchas 296 for (var key in recaptchaV2_loader.recaptchawidgets) { 297 if (!recaptchaV2_loader.hasOwnProperty(key) && document.getElementById(key)) { 298 recaptchaV2_render(key); 299 } 300 } 301 } 302 recaptchaV2_loader(); 303 break; 304 } 305}; 306var recaptchaV2_last_widgetid = function () { 307 return recaptchaV2_loader.recaptchawidgets[recaptchaV2_loader.widgetCount - 1]; 308} 309var recaptchaV2_response = function (widget_id) { 310 return grecaptcha.getResponse(widget_id); 311} 312var recaptchaV2_reset = function (widget_id) { 313 if ('undefined' !== typeof (widget_id)) { 314 grecaptcha.reset(widget_id); 315 } 316 else { 317 for (var id = recaptchaV2_loader.widgetCount; id > 0; --id) { 318 grecaptcha.reset(recaptchaV2_loader.recaptchawidgets[id - 1]); 319 } 320 } 321}; 322 323function bf_lgnGetUrl(elm) { 324 $get(elm).value = document.location.pathname + document.location.search; 325 return true; 326} 327function cb_CloseReload() { 328 document.location = document.location.href.replace('https://', 'http://'); 329} 330function bf_blReload() { 331 window.location.reload(true); 332} 333function GoToBeFrugal(lnk) { 334 try { 335 if (window.opener != null && !window.opener.closed) { 336 try { 337 window.opener.open(lnk.href, '_blank'); 338 window.close(); 339 } catch (e2) { 340 window.open(lnk.href, '_blank'); 341 window.close(); 342 } 343 } else { 344 window.open(lnk.href, '_blank'); 345 window.close(); 346 } 347 } catch (e) { } 348 return false; 349} 350 //toadd ":", "<", ">","/", "\" 351function SearchUrlCleanup(link) { 352 return link.replace(/&/g, "[and]").replace(/%26/g, "[and]").replace(/\*/g, "[ast]").replace(/\+/g, "[plus]").replace(/\?/g, "[ques]").replace(/@/g, "[em]") 353 .replace(/%/g, "[percent]").replace(/:/g, "[colon]").replace(/</g, "[openang]").replace(/>/g, "[closeang]").replace(/\\/g, "[backslash]") 354 .replace(/[\u2018\u2019]/g, "'")/*this is called out seperately, since this is a keyboard dependant apostraphe*/.replace(/[\u{0080}-\u{FFFFF}]/gu, "") 355 .substring(0,150); /*this is to prevent the url from breaking if it's too large. Nobody should want an actual response from this anyway*/ 356} 357 358function SerchURLToDest(link) { 359 return link.replace(/\[and]/g, "&").replace(/\[ast]/g, "*").replace(/\[plus]/g, "+").replace(/\[ques]/g, "?").replace(/\[em]/g, "@").replace(/\[percent]/g, "%") 360 .replace(/\[colon\]/g, ":").replace(/\[openang\]/g, "<").replace(/\[closeang\]/g, ">").replace(/\[backslash\]/g, "\\"); 361} 362 363function bf_man_click(elm) { 364 // DOM 2 Events 365 var dispatchMouseEvent = function (target, var_args) { 366 var e = document.createEvent("MouseEvents"); 367 // If you need clientX, clientY, etc., you can call 368 // initMouseEvent instead of initEvent 369 e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1)); 370 target.dispatchEvent(e); 371 }; 372 dispatchMouseEvent(elem, 'mouseover', true, true); 373 dispatchMouseEvent(elem, 'mousedown', true, true); 374 dispatchMouseEvent(elem, 'click', true, true); 375 dispatchMouseEvent(elem, 'mouseup', true, true); 376} 377 378function bf_mediaplayer_show() { 379 try { 380 if (player) { $get('player').className = 'bf-movie-on-screen'; } 381 } catch (e) { } 382} 383function bf_mediaplayer_hide() { 384 try { 385 if (player) { 386 //If video refuses to pause, try to hide the video anyways. 387 try {player.pauseVideo();} catch (e) { } 388 $get('player').className = 'bf-movie-off-screen'; 389 } 390 } catch (e) { } 391} 392 393//Warning: Do not apply this function to new pages without testing that stopText and startText are assigned successfully. 394//Some pages (e.g., the contact us page) do not assign the startText successfully. The latter can be tested by placing a breakpoint 395//in the button's codebehind and waiting 60 seconds for it to timeout. 396//Usage: OnClientClick="if(!bf_DisableButton(this, 'submitting', 'submit')) return false;" 397function bf_DisableButton(sender, stopText, startText) { 398 try { 399 if (sender.stop) return false; 400 sender.stop = true; 401 if (sender.nodeName === 'BUTTON') { 402 startText = startText || sender.innerHTML; 403 sender.innerHTML = stopText; 404 } 405 else { 406 startText = startText || sender.value; 407 sender.value = stopText; 408 } 409 setTimeout(function () { 410 bf_enable_button(sender, startText); 411 }, 60000); 412 return true; 413 } catch (e) { 414 return true; 415 } 416} 417 418function bf_enable_button(element, startText) { 419 var tmp = $(element); 420 var sender; 421 if (tmp.length > 0) 422 sender = tmp[0]; 423 sender.stop = false; 424 if (sender.nodeName === 'BUTTON') { 425 sender.innerHTML = startText; 426 } 427 else { 428 sender.value = startText; 429 } 430} 431 432async function ShowTermsForRetailer(resultdiv, retailerid) { 433 const resp = await fetch('/Service/CashBackTermsControl/' + retailerid + '/'); 434 if(resp.ok) { 435 document.getElementById(resultdiv).innerHTML = await resp.text(); 436 437 //If The terms window is inside a modal with scrollhack turned on, make the popup scrollable if it hangs of the bottom. 438 setTimeout(function () { 439 var scrollhack = $('#' + resultdiv).closest('.modal-scrollhack'); 440 if (scrollhack.length) { 441 var bottom = $('#' + resultdiv).position().top + $('#' + resultdiv).outerHeight(true); 442 var height = $(window).height(); 443 if (height < bottom) { 444 scrollhack.css('overflow-y', 'scroll'); 445 } 446 } 447 }, 1); 448 }; 449 450 hideCategories(); 451 return false; 452} 453 454async function ShowTermsForClickout(resultdiv, id, cDate) { 455 const resp = await fetch(`/Service/CashBackTermsControl/0/?ClickID=${id}&ClickDate=${cDate}`); 456 if (resp.ok) { 457 document.getElementById(resultdiv).innerHTML = await resp.text(); 458 459 //If The terms window is inside a modal with scrollhack turned on, make the popup scrollable if it hangs of the bottom. 460 setTimeout(function () { 461 var scrollhack = $('#' + resultdiv).closest('.modal-scrollhack'); 462 if (scrollhack.length) { 463 var bottom = $('#' + resultdiv).position().top + $('#' + resultdiv).outerHeight(true); 464 var height = $(window).height(); 465 if (height < bottom) { 466 scrollhack.css('overflow-y', 'scroll'); 467 } 468 } 469 }, 1); 470 }; 471 472 hideCategories(); 473 return false; 474} 475 476async function CallTermsAndPolicy(SourceID, type, isPopupID, TPPopupID, ContainerID, PopupButton) { 477 setTimeout(function () { 478 $('#' + PopupButton)[0].click(); 479 }, 1); 480 HidePopupTemporarily(ContainerID); 481 if (isPopupID.trim()) { 482 PopupContainerOverflow(isPopupID, TPPopupID); 483 } 484 const resp = await fetch(`/ServicePages/BefrugalSiteWs/?handler=ShowTermsAndPolicy&type=${type}`); 485 if(resp.ok) { 486 document.getElementById(TPPopupID).innerHTML = await rslt.text(); 487 CallTermsAndPolicyFollowUp(SourceID, isPopupID, TPPopupID, ContainerID); 488 }; 489 return false; 490} 491 492function CallTermsAndPolicyFollowUp(SourceID, isPopupID, TPPopupID, ContainerID) { 493 centerScrollPopupSmallWindow(TPPopupID, ContainerID, SourceID, isPopupID); 494 toggleCenterScrollPopupListenerSmallWindow(TPPopupID, ContainerID, SourceID, isPopupID); 495 setTimeout(function () { 496 $('#' + TPPopupID + ' .privacy-policy a').bind('mouseup', function () {
497 var fixedpositiony = $("#" + TPPopupID).offset().top - $(window).scrollTop(); 498 $('#' + TPPopupID).css("top", fixedpositiony); 499 var fixedpositionx = $("#" + TPPopupID).offset().left; 500 $('#' + TPPopupID).css("left", fixedpositionx); 501 $('#' + TPPopupID).css("position", "fixed"); 502 }); 503 }, 1000); 504 505} 506 507function PopupContainerOverflow(isPopupID, TPPopupID) { 508 if ($('#' + TPPopupID).css("display") != "none") { 509 $('#' + isPopupID).css("overflow", "visible"); 510 window.addEventListener('click', function eventfunction(event) { 511 if (event.target.id != "isPopupID" && !($(event.target).parents('#' + isPopupID).length)) { 512 $('#' + isPopupID).css("overflow", "auto"); 513 window.removeEventListener('click', eventfunction); 514 } 515 }); 516 } 517 return false; 518} 519 520//Requires jquery.js, includeoffer.js 521//txtSearch: Textbox containing search terms 522//btnSearch: "Search" button. Can be null. 523//ulAutoComplete: Autocomplete Node. 524//contextKey: ContextKey passed to search webservice. 525function InitSearch() { 526 let searchConfigs = document.querySelectorAll("[name=\"autoCompleteConfig\"]"); 527 for (let i = 0; i < searchConfigs.length; ++i) { 528 try { 529 let args = JSON.parse(searchConfigs[i].value); 530 args.TemplateControl = searchConfigs[i]; 531 MakeSearchListener(args); 532 } catch (e) { } 533 } 534} 535InitSearch(); 536$(document).on('bf:shellload', InitSearch); 537 538function MakeSearchListener(args) { 539 var txtSearch = document.getElementById(args.Parameters.TxtSearchId); 540 var btnSearch = document.getElementById(args.Parameters.BtnSearchId); 541 var ulAutoComplete = document.getElementById(args.Parameters.UlAutoCompleteId); 542 var contextKey = args.Parameters.ContextKey; 543 var bypassSearch = args.Parameters.BypassSearch; 544 var favoriteSelected = args.Parameters.FavoriteToggle; 545 var templateControl = args.TemplateControl; 546 547 var HASSEARCH = 'data-hassearch'; 548 if ($(txtSearch).attr(HASSEARCH)) return; 549 $(txtSearch).attr(HASSEARCH, true); 550 551 var VK_ENTER = 13; 552 var VK_UP = 38; 553 var VK_DOWN = 40; 554 555 var hideAutocomplete = function (targetClicked) { 556 delete ulAutoComplete.selectedNode; 557 ulAutoComplete.style.display = 'none'; 558 hideCategories(); 559 if (!targetClicked || !targetClicked.is('.search-box-mobile-and-desktop-view')) 560 FullMobileSearch(false); 561 ClearAutoCompleteMobile($(ulAutoComplete)); 562 } 563 564 //Hide autocomplete dropdown when user clicks elsewhere. 565 $(document).click(function (e) { 566 var ignored = $([txtSearch, btnSearch, ulAutoComplete]); 567 if (!ignored.is(e.target) && 568 ignored.has(e.target).length == 0 && 569 !$(e.target).is('.icon-cross')) { 570 hideAutocomplete($(e.target)); 571 } 572 }); 573 574 var getAutoCompleteUrl = function (st) { 575 var fixquery = function (str) { return encodeURIComponent(str); }; 576 return String.format("/SearchOffers/search.asmx/GetCompletionListMultiJSON?contextKey={0}&restrict=0&count={2}&prefixText={1}", 577 contextKey, 578 fixquery(st), 579 checkIfMobileBasedOnWidth() ? "10" : "10"); 580 }; 581 582 var doSearch = function () { 583 if (!ulAutoComplete.selectedNode) { 584 if (!bypassSearch) { 585 LgSrc(txtSearch.value); 586 return false; 587 } 588 else { 589 return true; 590 } 591 } 592 var ganText = $(ulAutoComplete.selectedNode).attr('data-gan'); 593 var dest = $(ulAutoComplete.selectedNode).attr('data-href'); 594 595 if (bypassSearch) { 596 txtSearch.value = $(ulAutoComplete.selectedNode).attr('data-friend'); 597 delete ulAutoComplete.selectedNode; 598 ulAutoComplete.style.display = 'none'; 599 if (favoriteSelected) { 600 doFavoriteAdd(ganText); 601 } 602 } else { 603 var searchType = $(ulAutoComplete.selectedNode).find('span:first'); 604 if (searchType != null && searchType.length == 1 && searchType.attr('TACSearchType') == 'tool') { 605 dest = SerchURLToDest(dest) 606 } 607 var useShell = true; 608 var firstShell = $(ulAutoComplete).closest('[data-bfshell]'); 609 if (firstShell.length == 0) { 610 useShell = false; 611 } else { 612 var shellchoice = firstShell.closest('[data-bfshell]').attr('data-bfshell'); 613 if (0 === 'False'.localeCompare(shellchoice, 'en', { sensitivity: 'accent' })) { 614 useShell = false; 615 } 616 } 617 if (new URL(document.baseURI).origin !== new URL(dest, document.baseURI).origin) { 618 window.open(dest, '_blank'); 619 } 620 else if (useShell) { 621 hideAutocomplete(); 622 txtSearch.value = ''; 623 $(document).trigger("bf:ShellRequest", dest); 624 } else { 625 window.location = dest; 626 } 627 } 628 return false; 629 }; 630 631 var currentSearchStatus = { 632 currentSearch: txtSearch.value, 633 currentHit: 0, 634 lastHit: 0, 635 SetSearch: function(search) { 636 currentSearchStatus.currentSearch = search; 637 currentSearchStatus.currentHit++; 638 } 639 } 640 641 var currentTimer = null; 642 643 var processAutocomplete = function () { 644 var myhit = currentSearchStatus.currentHit; 645 var autocompleteHandler = function (data) { 646 if (currentSearchStatus.lastHit > myhit) { 647 //Due to timing issues, the responses from the autocomplete task arrived out of order. This result is stale and should be ignored. 648 return; 649 } 650 651 currentSearchStatus.lastHit = myhit; 652 var searches = $.parseJSON(data); 653 delete ulAutoComplete.selectedNode; 654 while (ulAutoComplete.firstChild) ulAutoComplete.removeChild(ulAutoComplete.firstChild); 655 ulAutoComplete.style.display = searches.length !== undefined && searches.length !== null ? '' : 'none'; 656 var totalcount = 0; 657 var isplacement = false; 658 var useBasicSeeAll = true; 659 var showDealSeperator = null; 660 $.each(searches, function (i, currentResult) { 661 var currentTemplateParameters = currentResult.TemplateParameters; 662 var html = templateControl.getAttribute('template_' + currentResult.TemplateName); 663 for (var c = 0; c < currentTemplateParameters.length; c++) { 664 if (c == 0) { 665 currentTemplateParameters[c] = currentTemplateParameters[c].replace(/\"/g, """); 666 } 667 if (!!html) { 668 html = html.replace(new RegExp('##' + c + '##', 'g'), currentTemplateParameters[c].replace(/\$/g, "$$$$")); 669 } 670 else { 671 html = new String(); 672 } 673 } 674 totalcount++; 675 if (!isplacement && currentResult.IsRecommended) { 676 isplacement = true; 677 totalcount++; 678 $("<div class='search-placement-divider'><span>Recommended Stores</span></div>").appendTo(ulAutoComplete); 679 }
680 if (showDealSeperator == false && SearchUrlCleanup(currentResult.URL).startsWith("/deals/")) { 681 showDealSeperator = true; 682 totalcount++; 683 $("<div class='search-placement-divider'><span>Deals</span></div>").appendTo(ulAutoComplete); 684 } 685 686 if (useBasicSeeAll && currentResult.TemplateName == 'SearchAllSearchTerm') { 687 useBasicSeeAll = false; 688 } 689 690 $('<div/>') 691 .mouseenter(updateHighlightedNode.bind(this, i + AmountToAddToIndex(isplacement, showDealSeperator), false)) 692 .click(doSearch) 693 .attr('data-href', SearchUrlCleanup(currentResult.URL)) 694 .attr('data-gan', currentResult.SearchInternalName) 695 .attr('data-friend', currentResult.SearchFriendlyName) 696 .attr('class', isplacement ? 'search-placement' : '') 697 .html(html) 698 .appendTo(ulAutoComplete); 699 700 701 if (showDealSeperator == null && SearchUrlCleanup(currentResult.URL).startsWith("/store/")) { 702 showDealSeperator = false; 703 } 704 705 }); 706 707 function AmountToAddToIndex(hasPlacement, dealSeperator) 708 { 709 var x = 0; 710 if (hasPlacement == true) 711 x++; 712 if (dealSeperator == true) 713 x++; 714 return x; 715 } 716 717 var searchBoxTerm = $('.search-box').val(); 718 if (searchBoxTerm.length > 1 && contextKey != "favorites-search" && useBasicSeeAll) { 719 $('<div/>') 720 .mouseenter(updateHighlightedNode.bind(this, totalcount, false)) 721 .click(doSearch) 722 .html('<span><div class="searchbarhlb"><p class="search-text"><span class="searchBarTitle"></span><span class="searchbarAllResults">See all results for <strong>' + searchBoxTerm + '</strong> <span class="ico-moon icon-chevron-right" style="font-size:13px;vertical-align:middle;"></span></span><span class="searchBarTitle"></span><span class="searchbarhcbrate"></span><span class="searchbarhright"></span></p></div></span>') 723 .attr('data-href', "/coupons/search/" + SearchUrlCleanup(searchBoxTerm) + "/") 724 .appendTo(ulAutoComplete); 725 } 726 $(ulAutoComplete).mouseleave(function () { 727 if (ulAutoComplete.selectedNode) { 728 ulAutoComplete.selectedNode.className = ulAutoComplete.selectedNode.className.replace(' selected', ''); 729 delete ulAutoComplete.selectedNode; 730 } 731 }); 732 }; 733 734 $.ajax({
735 type: 'Get', 736 url: getAutoCompleteUrl(currentSearchStatus.currentSearch), 737 success: autocompleteHandler, 738 error: function (jqXHR, textStatus, errorThrown) { 739 //console.log("Failed search", textStatus, errorThrown); 740 } 741 }); 742 }; 743 744 var updateHighlightedNode = function (newIndex, isdelta) { 745 var nodes = ulAutoComplete.childNodes; 746 if (nodes.length == 0) return; 747 $.each(nodes, function (i, currentResult) { 748 if (currentResult.className.includes("search-placement-divider")) { 749 //nodes = ulAutoComplete.removeChild(ulAutoComplete.childNodes[i]); 750 //return false; 751 } 752 }); 753 if (isdelta) { 754 if (ulAutoComplete.selectedNode) { 755 newIndex = (newIndex + (ulAutoComplete.selectedIndex || 0) + nodes.length) % nodes.length; 756 } else { 757 newIndex = newIndex == 1 ? 0 : nodes.length - 1; 758 } 759 } 760 if (ulAutoComplete.selectedNode) { 761 ulAutoComplete.selectedNode.className = ulAutoComplete.selectedNode.className.replace(' selected', ''); 762 } 763 ulAutoComplete.selectedIndex = newIndex; 764 ulAutoComplete.selectedNode = nodes[newIndex]; 765 ulAutoComplete.selectedNode.className = ulAutoComplete.selectedNode.className + ' selected'; 766 }; 767 768 $(txtSearch).bind({ 769 keydown: function (e) { 770 //Prevent caret from moving while user navigates auto-complete dropdown. 771 return e.keyCode != VK_UP && e.keyCode != VK_DOWN; 772 }, 773 keypress: function (e) { 774 if (e.keyCode === VK_ENTER) { 775 e.preventDefault(); 776 e.stopPropagation(); 777 doSearch(); 778 } 779 }, 780 keyup: function (e) { 781 if (e.keyCode == VK_ENTER) return; 782 if (e.keyCode == VK_UP || e.keyCode == VK_DOWN) { 783 updateHighlightedNode(e.keyCode == VK_DOWN ? 1 : -1, true); 784 e.preventDefault(); 785 return; 786 } 787 788 if (currentSearchStatus.currentSearch == txtSearch.value) return; 789 currentSearchStatus.SetSearch(txtSearch.value); 790 791 if (currentTimer) { 792 //Debounce 793 clearTimeout(currentTimer); 794 } 795 currentTimer = setTimeout(processAutocomplete, 50); 796 }, 797 paste: function (e) { 798 currentTimer = setTimeout(function () { 799 currentSearchStatus.SetSearch(txtSearch.value); 800 processAutocomplete(); 801 }, 50); 802 }, 803 click: function (e) { 804 console.log('Click X'); 805 currentTimer = setTimeout(function () { 806 currentSearchStatus.SetSearch(txtSearch.value); 807 processAutocomplete(); 808 }, 50); 809 } 810 }); 811 $(btnSearch).click(doSearch); 812}; 813 814function ClearAutoCompleteMobile(autoCompleteMobile) { 815 $('.store-search-box').val(''); 816 $('.icon-cross').hide(); 817 autoCompleteMobile.empty(); 818} 819 820// Add toAdd to the link as a query string value. If there is a tag, keep the tag at the end of the url 821function addQueryStringValue(link, toAdd) { 822 var start = link; 823 var end = ''; 824 825 if (link.indexOf("#") > -1) { 826 start = link.split('#')[0]; 827 end = '#' + link.split('#')[1]; 828 } 829 830 var seperator = '?'; 831 if (link.indexOf('?') > -1) 832 seperator = '&'; 833 834 return start + seperator + toAdd + end; 835} 836 837function showCategories() { 838 var dropdownUL = document.querySelector("#dropdown-nav"); 839 if (dropdownUL) dropdownUL.className = "dropdown-nav open"; 840} 841 842function hideCategories() { 843 var dropdownUL = document.querySelector("#dropdown-nav"); 844 if(dropdownUL) dropdownUL.className = "dropdown-nav bf-is-hidden"; 845} 846 847function toggleCategories() { 848 var dropdownUL = document.querySelector("#dropdown-nav"); 849 if (dropdownUL.className == "dropdown-nav open") 850 dropdownUL.className = "dropdown-nav bf-is-hidden"; 851 else 852 dropdownUL.className = "dropdown-nav open"; 853} 854 855function doFavoriteAdd(retailerid) { 856 const token = $('input[name="__RequestVerificationToken"]').val(); 857 $.ajax({
858 type: "POST", 859 url: '/ServicePages/BefrugalSiteWs/?handler=AddStoreFavorite', 860 data: { retailerInternalName: retailerid }, 861 headers: { RequestVerificationToken: token }, 862 success: async function (msg) { 863 var inputDiag = $(".favoriteSearchBoxInputClass"); 864 if (inputDiag.length > 0) 865 inputDiag[0]._haschanged = false; 866 867 if (msg.alreadyFull) { 868 //alreadyFull 869 console.log("favorites full"); 870 $(".searchboxSuccess").hide(); 871 $(".searchboxFull").css('display', 'inline-block'); 872 } 873 else { 874 if (msg.storeIsFavorite) { 875 let originaltext = $(".favorite-search-box").val(); 876 await RefreshPage(); 877 //success 878 $(".favorite-search-box").val(originaltext); 879 $(".searchboxSuccess").show(); 880 } 881 else { 882 //alreadyadded 883 $(".searchboxSuccess").hide(); 884 $(".searchboxFull").hide(); 885 } 886 } 887 }, 888 error: function (msg) { 889 console.log("failure to add favorite"); 890 } 891 }); 892} 893 894function toggleJoinLogin (memberLogin, joinNow) { 895 var joinDiv = $("#join_dialog_wrapper"); 896 var signDiv = $("#sign_dialog_wrapper"); 897 var style = joinDiv.css("display"); 898 joinDiv.css("display", signDiv.css("display")); 899 signDiv.css("display", style); 900 if (style == "none") 901 { 902 $("#loginLnk").text(memberLogin); 903 $("#joinScroll").text(joinNow); 904 } 905 else 906 { 907 $("#loginLnk").text(joinNow); 908 909 910 $("#joinScroll").text(memberLogin); 911 912 } 913} 914 915function checkIfMobileBasedOnWidth() { 916 return $(window).width() < 750; 917} 918 919function ScrollToTop() { 920 jQuery('html,body').animate({ scrollTop: jQuery('#TopOfPageControl').offset().top }, 250); 921} 922 923var shouldShowOffer = false; 924function ShowOffersFull() { 925 if ($find('pceFavoriteOffersFullBehaviorID') != null) { 926 shouldShowOffer = true; 927 ShowOffersFullPopup(); 928 } 929 else { 930 shouldShowOffer = true; 931 Sys.Application.add_load(function(event) { 932 ShowOffersFullPopup(); 933 }); 934 } 935} 936 937function ShowOffersFullPopup() { 938 if (shouldShowOffer) { 939 $find('pceFavoriteOffersFullBehaviorID').show(); 940 shouldShowOffer = false; 941 } 942} 943 944var shouldShowDeal = false; 945function ShowDealsFull() { 946 if ($find('pceFavoriteDealsFullBehaviorID')!=null) { 947 shouldShowDeal = true; 948 ShowDealsFullPopup(); 949 } 950 else { 951 shouldShowDeal = true; 952 Sys.Application.add_load(function (event) { 953 ShowDealsFullPopup(); 954 }); 955 } 956} 957 958function ShowDealsFullPopup() { 959 if (shouldShowDeal) { 960 $find('pceFavoriteDealsFullBehaviorID').show(); 961 shouldShowDeal = false; 962 } 963} 964 965//#region Sidebar 966function disableIfNeeded(button) { 967 if (button.classList.contains("alreadyClicked")) { 968 return false; 969 } 970 971 button.classList.add("alreadyClicked"); 972 973 return true; 974} 975//#Region RetailerDescriptionSideBar Show button 976$(document).on('click', '.seeMoreSpn', function (e) { 977 var parent = $(e.target).parent(); 978 979 //this is so that if the "more" button is clicked directly, it goes up two levels, while if the "..." is clicked, it goes up one level. 980 if (parent.hasClass("seeMoreSpn")) { 981 parent = parent.parent(); 982 } 983 showRetailerDescription(parent); 984}); 985function showRetailerDescription(container) { 986 $(container).find(".continuation").show(); 987 $(container).find(".seeMoreSpn").hide(); 988} 989//#region CashBackCategories hide/expand 990$(document).on('click', '.cashback-sidebar-up-arrow', function (e) { 991 var parent = $(e.target).parent(); 992 if (parent.hasClass('cashback-sidebar-up-arrow')) { 993 parent = parent.parent(); 994 } 995 cashback_sidebar_Hide(parent); 996}); 997 998$(document).on('click', '.cashback-sidebar-down-arrow', function (e) { 999 var parent = $(e.target).parent(); 1000 if (parent.hasClass('cashback-sidebar-down-arrow')) { 1001 parent = parent.parent(); 1002 } 1003 cashback_sidebar_Show(parent); 1004}); 1005 1006function cashback_sidebar_Hide(container) { 1007 container.find('.Cashback-Department-Contents').hide(); 1008 container.find('.cashback-sidebar-down-arrow').show(); 1009 container.find('.cashback-sidebar-up-arrow').hide(); 1010} 1011function cashback_sidebar_Show(container) { 1012 container.find('.Cashback-Department-Contents').show(); 1013 container.find('.cashback-sidebar-down-arrow').hide(); 1014 container.find('.cashback-sidebar-up-arrow').show(); 1015} 1016 1017//#endregion 1018//#endregion
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.