1$(function () { 2 /** 3 * DETERMINES DISPLAY 4 **/ 5 var display = "desktop"; 6 var displayOptions = { 7 mobile: "(max-width: 670px)", 8 tablet: "(max-width: 960px)", 9 }; 10 if (typeof Modernizr !== "undefined" && !$("html").hasClass("oldIE")) { 11 // we care about display 12 $.each(displayOptions, function (type, size) { 13 if (Modernizr.mq(size)) { 14 display = type; 15 return false; // break the loop 16 } 17 }); 18 } 19 20 /** 21 * WINDOW EVENTS 22 **/ 23 $(window).on({ 24 resize: function () { 25 /** 26 * CHECKS FOR CHANGE IN DISPLAY TYPE 27 **/ 28 if (typeof Modernizr !== "undefined" && !$("html").hasClass("oldIE")) { 29 // we care about display 30 var newDisplay = "desktop"; 31 $.each(displayOptions, function (type, size) { 32 if (Modernizr.mq(size)) { 33 newDisplay = type; 34 return false; // break the loop 35 } 36 }); 37 38 if (newDisplay !== display) { 39 // display has changed 40 display = newDisplay; 41 42 // INDEX PAGE: hides/displays secondary form fields 43 if (!$("body").hasClass("showFields") && newDisplay == "mobile") { 44 $(".secondary input, .secondary select").removeClass("required"); 45 $(".secondary").removeClass("req"); 46 } else { 47 $(".secondary input, .secondary select").addClass("required"); 48 $(".secondary").addClass("req"); 49 } 50 51 // ACCOUNT PAGE: 52 // makes sure sliding infos are reset 53 if (newDisplay == "desktop") { 54 $(".moreInfo.visible").trigger("click"); 55 } 56 57 // adds/removes expandable creditor functionality 58 if (newDisplay == "mobile") { 59 expandableCreditors("bind"); 60 61 if ($(".creditor.editing").length) { 62 $(".creditor.editing").addClass("open"); 63 } 64 } else { 65 expandableCreditors("remove"); 66 } 67 } 68 } 69 }, // ends on resize 70 }); 71 72 /** 73 * IF MOBILE, REMOVES REQUIRED CLASS FOR SECONDARY FIELDS 74 **/ 75 if (!$("body").hasClass("showFields") && display == "mobile") { 76 $(".secondary input, .secondary select").removeClass("required"); 77 $(".secondary").removeClass("req"); 78 } else { 79 $(".secondary input, .secondary select").addClass("required"); 80 $(".secondary").addClass("req"); 81 } 82 83 /** 84 * THANKYOU PAGE 85 **/ 86 if ($("#thankyou").length) { 87 // using session var 88 if ($("#thankyou h1 .name").html() != "") { 89 $("#thankyou h1 .name").show(); 90 } 91 if ($("#thankyou .reference .number").html() != "") { 92 $("#thankyou .reference.infos").show(); 93 } 94 if ($("#thankyou .phone .number").html() != "") { 95 $("#thankyou .phone.infos").show(); 96 } 97 } 98 99 /** 100 * DYNAMIC TRACKING PARAMETERS 101 * Fully dynamic approach: captures ALL query parameters from URL and adds them to the form 102 **/ 103 104 // Get all URL parameters 105 var urlParams = getQueryParams(window.location.search); 106 107 // Cookie settings 108 var today = new Date(); 109 var expires = new Date(today.getTime() + 90 * 86400000); 110 111 // Read existing cookies 112 var cookies = document.cookie.split(";"); 113 var existingValues = {}; 114 115 $(cookies).each(function () { 116 var thisCookie = this.split("="); 117 var cookieName = $.trim(thisCookie[0]); 118 if (thisCookie.length > 1) { 119 existingValues[cookieName] = decodeURIComponent($.trim(thisCookie[1])); 120 } 121 }); 122 123 // Special handling for GCLID (first and all) - preserve existing behavior 124 var currentGclid = urlParams.gclid || "null"; 125 126 if ($("input#gclid_all").length) { 127 if (existingValues.gclid_all && currentGclid !== "null") { 128 // Only append if we have a real gclid value (not "null") 129 $("input#gclid_all").val(existingValues.gclid_all + "__%%__" + currentGclid); 130 document.cookie = "gclid_all=" + encodeURIComponent(existingValues.gclid_all + "__%%__" + currentGclid) + ";expires=" + expires.toUTCString() + ";path=/"; 131 } else if (existingValues.gclid_all) { 132 // Keep existing value if current is "null"
133 $("input#gclid_all").val(existingValues.gclid_all); 134 } else { 135 // First time - set to current value 136 $("input#gclid_all").val(currentGclid); 137 if (currentGclid !== "null") { 138 document.cookie = "gclid_all=" + encodeURIComponent(currentGclid) + ";expires=" + expires.toUTCString() + ";path=/"; 139 } 140 } 141 } 142 143 if ($("input#gclid_first").length) { 144 if (existingValues.gclid_first) { 145 $("input#gclid_first").val(existingValues.gclid_first); 146 } else { 147 $("input#gclid_first").val(currentGclid); 148 if (currentGclid !== "null") { 149 document.cookie = "gclid_first=" + encodeURIComponent(currentGclid) + ";expires=" + expires.toUTCString() + ";path=/"; 150 } 151 } 152 } 153 154 console.log("URL Parameters found:", urlParams); 155 156 // UTM parameters to persist across navigation 157 var utmParams = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term", "utm_channel", "utm_userid", "odsource", "wbraid", "gbraid"]; 158 var utmStorageKey = "cc_utm_params"; 159 160 // If UTMs are present in the URL, save them to localStorage (first touch wins) 161 var hasUtmInUrl = false; 162 $.each(utmParams, function (i, key) { 163 if (urlParams[key]) { 164 hasUtmInUrl = true; 165 return false; 166 } 167 }); 168 169 if (hasUtmInUrl) { 170 var toStore = {}; 171 $.each(utmParams, function (i, key) { 172 if (urlParams[key]) { 173 toStore[key] = urlParams[key]; 174 } 175 }); 176 try { 177 localStorage.setItem(utmStorageKey, JSON.stringify(toStore)); 178 } catch (e) {} 179 } 180 181 // Load persisted UTMs from localStorage (fills in what the URL is missing) 182 var storedUtms = {}; 183 try { 184 var stored = localStorage.getItem(utmStorageKey); 185 if (stored) { 186 storedUtms = JSON.parse(stored); 187 } 188 } catch (e) {} 189 190 // Merge: URL params take priority over stored values 191 var mergedParams = $.extend({}, storedUtms, urlParams); 192 193 // Dynamically process ALL URL parameters (including restored UTMs) 194 $.each(mergedParams, function (paramName, paramValue) { 195 // Skip gclid as it's handled specially above 196 if (paramName === "gclid") { 197 return true; // continue 198 } 199 200 // Check if a hidden field already exists for this parameter 201 var inputField = $("input[name='" + paramName + "']"); 202 203 if (inputField.length) { 204 inputField.val(paramValue); 205 console.log("Updated existing field: " + paramName + " = " + paramValue); 206 } else { 207 $("<input>").attr("type", "hidden").attr("name", paramName).val(paramValue).appendTo("form#fillInfo"); 208 console.log("Created dynamic field: " + paramName + " = " + paramValue); 209 } 210 }); 211 212 /** 213 * ZIP CODE AUTO-FORMAT 214 * Digits only, max 5 215 **/ 216 $(document).on("input change blur", "#txtZip", function () { 217 $(this).val($(this).val().replace(/\D/g, "").substring(0, 5)); 218 if ($(this).val().length > 0 && $(this).val().length < 5) { 219 showInlineError(this, "Please enter a valid 5-digit zip code."); 220 } else { 221 clearInlineError(this); 222 } 223 }); 224 225 /** 226 * PHONE AUTO-FORMAT 227 * Formats input as (XXX) XXX-XXXX, digits only, max 10 228 **/ 229 function formatPhone(value) { 230 var digits = value.replace(/\D/g, "").substring(0, 10); 231 if (digits.length >= 7) { 232 return "(" + digits.substring(0, 3) + ") " + digits.substring(3, 6) + "-" + digits.substring(6); 233 } else if (digits.length >= 4) { 234 return "(" + digits.substring(0, 3) + ") " + digits.substring(3); 235 } else if (digits.length >= 1) { 236 return "(" + digits; 237 } 238 return digits; 239 } 240 241 $(document).on("input change blur", "#txtPhone", function () { 242 $(this).val(formatPhone($(this).val())); 243 var digits = $(this).val().replace(/\D/g, ""); 244 if (digits.length > 0 && digits.length < 10) { 245 showInlineError(this, "Please enter a valid phone number."); 246 } else { 247 clearInlineError(this); 248 } 249 }); 250 251 $(document).on("blur", "#txtEmail", function () { 252 var val = $(this).val().trim(); 253 var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; 254 if (val.length > 0 && !emailPattern.test(val)) { 255 showInlineError(this, "Please enter a valid email address."); 256 } else { 257 clearInlineError(this); 258 } 259 }); 260 261 function showInlineError(field, message) { 262 $(field).addClass("field-invalid"); 263 var $container = $(field).closest(".field-group, .element");
264 if ($container.length && $container.find(".inline-error").length === 0) { 265 $container.append('<span class="inline-error">' + message + "</span>"); 266 } 267 } 268 269 function clearInlineError(field) { 270 $(field).removeClass("field-invalid"); 271 $(field).closest(".field-group, .element").find(".inline-error").remove(); 272 } 273 274 /** 275 * CUSTOM VALIDATION MESSAGES 276 * To update a message, edit the value in this object. 277 * To add a new field, add a new key/value pair using the field's name attribute. 278 **/ 279 var validationMessages = { 280 txtFirstName: "Please enter your first name.", 281 txtLastName: "Please enter your last name.", 282 txtEmail: "Please enter a valid email address.", 283 txtPhone: "Please enter a valid phone number.", 284 txtZip: "Please enter a valid 5-digit zip code.", 285 cboState: "Please select a state.", 286 cboTotalDebtID: "Please select a range.", 287 cboClientPaymentStatusID: "Please select a status.", 288 }; 289 290 Object.keys(validationMessages).forEach(function (name) { 291 $(document).on("input change", "[name='" + name + "']", function () { 292 this.setCustomValidity(""); 293 if (this.tagName === "SELECT") { 294 if (!this.value) { 295 showInlineError(this, validationMessages[name]); 296 } else { 297 clearInlineError(this); 298 } 299 } else { 300 clearInlineError(this); 301 } 302 }); 303 }); 304 305 function validateForm(form) { 306 var fields = $(form).find("input, select, textarea"); 307 var firstInvalid = null; 308 var isValid = true; 309 310 var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; 311 312 for (var i = 0; i < fields.length; i++) { 313 var field = fields[i]; 314 var name = field.name; 315 var fieldInvalid = false; 316 var message = validationMessages[name] || "This field is required."; 317 318 if (name === "txtEmail" && field.value.trim().length > 0 && !emailPattern.test(field.value.trim())) { 319 fieldInvalid = true; 320 } else if (name === "txtPhone" && field.value.replace(/\D/g, "").length > 0 && field.value.replace(/\D/g, "").length < 10) { 321 fieldInvalid = true; 322 } else if (name === "txtZip" && field.value.length > 0 && field.value.length < 5) { 323 fieldInvalid = true; 324 } else if (!field.validity.valid) { 325 fieldInvalid = true; 326 } 327 328 if (fieldInvalid) { 329 isValid = false; 330 field.setCustomValidity(message); 331 showInlineError(field, message); 332 if (!firstInvalid) { 333 firstInvalid = field; 334 } 335 } else { 336 field.setCustomValidity(""); 337 clearInlineError(field); 338 } 339 } 340 341 if (firstInvalid) { 342 $(firstInvalid).focus(); 343 firstInvalid.scrollIntoView({ behavior: "smooth", block: "center" }); 344 } 345 346 return isValid; 347 } 348 349 /** 350 * ZERO DEBT PANEL LOGIC 351 * Shows panel when no debt option is selected on form submit 352 * Hides panel when a debt amount (not "No Credit Card Debt") is selected 353 **/ 354 var $debtSelect = $("#cboTotalDebtID"); 355 var $zeroDebtPanel = $("#zeroDebtPanel"); 356 var $otherServiceSelect = $("#cboServiceID"); 357 var $otherServiceTextGroup = $("#otherServiceTextGroup"); 358 var $otherServiceText = $("#txtServiceOther"); 359 360 // Handle debt selection change 361 $debtSelect.on("change", function () { 362 var selectedValue = $(this).val(); 363 364 // Hide panel and remove required if a debt amount is selected (values 1-5) or "Select Range" is re-selected 365 if (selectedValue !== "6") { 366 $zeroDebtPanel.hide(); 367 $otherServiceSelect.removeAttr("required"); 368 $otherServiceSelect.val(""); 369 // Also hide and reset the other service text field 370 $otherServiceTextGroup.hide(); 371 $otherServiceText.removeAttr("required"); 372 $otherServiceText.val(""); 373 $("#txtServiceOtherCount").text("0 / 50"); 374 $("#cboClientPaymentStatusID").attr("required", "required"); 375 } 376 // Show panel if "No Credit Card Debt" is selected 377 else { 378 $zeroDebtPanel.show(); 379 $otherServiceSelect.attr("required", "required"); 380 $("#cboClientPaymentStatusID").removeAttr("required"); 381 } 382 }); 383 384 // Handle other service selection change 385 $otherServiceSelect.on("change", function () { 386 this.setCustomValidity(""); 387 $(this).removeClass("field-invalid"); 388 $(this).closest(".field-group, .element").find(".inline-error").remove(); 389 var selectedValue = $(this).val(); 390 391 // Show text field if "Other" is selected (value 7) 392 if (selectedValue === "7") { 393 $otherServiceTextGroup.show(); 394 $otherServiceText.attr("required", "required"); 395 } else { 396 // Hide text field and remove required for any other selection 397 $otherServiceTextGroup.hide(); 398 $otherServiceText.removeAttr("required"); 399 $otherServiceText.val(""); 400 $("#txtServiceOtherCount").text("0 / 50"); 401 } 402 }); 403 404 // Character counter for "Other" service text field 405 $otherServiceText.on("input", function () { 406 var len = $(this).val().length; 407 $("#txtServiceOtherCount").text(len + " / 50"); 408 if (len > 0) { 409 this.setCustomValidity(""); 410 $(this).removeClass("field-invalid"); 411 $(this).closest(".field-group, .element").find(".inline-error").remove(); 412 } 413 }); 414 415 /** 416 * PROCESSES FORMS 417 **/ 418 419 // checks full form on submit 420 $("form#fillInfo").on("submit", function (e) { 421 e.preventDefault(); 422 423 // Run custom validation since novalidate is set on the form 424 if (!validateForm(this)) { 425 return false;
426 } 427 428 // Check if debt option is not selected - show panel and stop submission 429 var debtValue = $debtSelect.val(); 430 if (debtValue === "") { 431 $zeroDebtPanel.show(); 432 $otherServiceSelect.attr("required", "required"); 433 $otherServiceSelect.focus(); 434 return false; 435 } 436 437 // If "No Credit Card Debt" is selected, ensure zero debt reason is selected 438 if (debtValue === "6" && $otherServiceSelect.val() === "") { 439 $otherServiceSelect.focus(); 440 return false; 441 } 442 443 var thisForm = $(this); 444 var thisSubmit = $(this).find('input[type="submit"]'); 445 446 //adds a key to check spam 447 jQuery("<input>").attr("type", "hidden").attr("name", "check_key").attr("value", "efw3fkDmvlkD24DvuYCmdlkdefFJkDCmHdf356GfFVknxqGpuJhbF5gJdGvdCJM").appendTo(jQuery("#fillInfo")); 448 449 // submits account form â disable button and show loading state 450 thisSubmit.attr("disabled", "disabled").val("Submitting\u2026").css("opacity", "0.7"); 451 $("#formLoadingState").css("display", "flex"); 452 453 // Strip formatting from phone before submission so ACCC receives digits only 454 var $phoneField = thisForm.find("#txtPhone"); 455 var digitsOnly = $phoneField.val().replace(/\D/g, ""); 456 $phoneField.val(digitsOnly); 457 458 var formData = thisForm.serialize(); 459 460 // Reformat phone back to display format after serializing 461 $phoneField.val(formatPhone(digitsOnly)); 462 var dev = ""; 463 if (thisForm.hasClass("dev")) { 464 dev = "&dev=true"; 465 } 466 $.ajax({ 467 url: _baseURL + "/debthelp/php/config.php?action=addLead&form=fillInfo" + dev, 468 data: formData, 469 type: "post", 470 dataType: "json", 471 error: function (jqXHR, textStatus, errorThrown) { 472 thisSubmit.removeAttr("disabled").val("Start your journey").css("opacity", ""); 473 $("#formLoadingState").hide(); 474 }, 475 success: function (data) { 476 // Push enhanced conversion data to GTM data layer 477 window.dataLayer = window.dataLayer || []; 478 479 // Get email and phone values (handle different field IDs across forms) 480 var emailValue = $("#email").length ? $("#email").val() : $("#txtEmail").val(); 481 var phoneValue = $("#phone").length ? $("#phone").val() : $("#txtPhone").val(); 482 483 if (data.accc == null) { 484 alert("Your information has been received. Please give us a call at 800-769-3571 so a counselor can further assist you."); 485 } else if (data.accc.status == "success" && data.ovr.status == "success") { 486 window.dataLayer.push({ 487 event: "formSubmitted", 488 leadsUserData: { 489 email: emailValue.toLowerCase().trim(), 490 phone_number: "+1" + phoneValue.replace(/\D/g, ""), 491 }, 492 }); 493 // NEW: Handle seQualify and redirectUrl fields 494 if (data.accc.seQualify === true) { 495 // Use dynamic redirectUrl if provided, otherwise fall back to default 496 if (data.accc.redirectUrl) { 497 window.location = data.accc.redirectUrl; 498 } else { 499 window.location = "https://myplan.consumercredit.com/concerns-01-01"; 500 } 501 } else if (data.accc.seQualify === false) { 502 if (dev != "") { 503 window.location = "https://www.secure-consumercredit.com/dev/clientportal/Enrollment/step2.aspx?cn=" + data.accc.cn; 504 } else { 505 window.location = "https://www.secure-consumercredit.com/clientportal/Enrollment/step2.aspx?cn=" + data.accc.cn; 506 } 507 } else { 508 // Fallback to old behavior if seQualify is not present 509 if (dev != "") { 510 window.location = "https://www.secure-consumercredit.com/dev/clientportal/Enrollment/step2.aspx?cn=" + data.accc.cn; 511 } else { 512 window.location = "https://www.secure-consumercredit.com/clientportal/Enrollment/step2.aspx?cn=" + data.accc.cn; 513 } 514 } 515 } else if (data.ovr.message != undefined && data.ovr.message != "") { 516 alert(data.ovr.message); 517 thisSubmit.removeAttr("disabled").val("Start your journey").css("opacity", ""); 518 $("#formLoadingState").hide(); 519 } else if (data.accc.message != undefined && data.accc.message != "") { 520 alert(data.accc.message); 521 thisSubmit.removeAttr("disabled").val("Start your journey").css("opacity", ""); 522 $("#formLoadingState").hide(); 523 } else { 524 alert("We are unable to process your request. Please check your data and try again."); 525 thisSubmit.removeAttr("disabled").val("Start your journey").css("opacity", ""); 526 $("#formLoadingState").hide(); 527 } 528 }, 529 }); // ends ajax 530 }); // ends on click of submit 531}); // ends init function 532 533/** 534 * GETS QUERY PARAMETERS FROM URL 535 **/ 536function getQueryParams(qs) { 537 qs = qs.split("+").join(" "); 538 var params = {}, 539 tokens, 540 re = /[?&]?([^=]+)=([^&]*)/g; 541 542 while ((tokens = re.exec(qs))) { 543 params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]); 544 } 545 546 return params; 547}
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.