1const ParcelIdModule = (() => { 2 3 let form = null; 4 let parcelId = null; 5 let paridError = null; 6 let requiredInputFilled = null; 7 let fileInput = null; 8 let validateForm = null; 9 let showDefaultErrorMessage = null; 10 11 let timeoutID = null; 12 let requiresParid = false; 13 let isValid_Parid = false; 14 let last_valid_parid = ""; 15 let last_situs_address = ''; 16 let last_mailing_address = ''; 17 let _pao_mailing_address_on_file = ''; 18 19 const _pao_contact_name = document.getElementById('pao_contact_name'); 20 const _pao_situs_input = document.getElementById('pao_situs_address'); 21 const _pao_mailing_address_input = document.getElementById('pao_mailing_address'); 22 23 function initialize(config) { 24 25 form = config.form; 26 parcelId = config.parcelId; 27 paridError = config.paridError; 28 requiredInputFilled = config.requiredInputFilled; 29 fileInput = config.fileInput; 30 validateForm = config.validateForm; 31 showDefaultErrorMessage = config.showDefaultErrorMessage; 32 33 // Parcel input is lazy-rendered. 34 // DOM bindings and typeahead initialization 35 // occur after renderParidInput(). 36 37 } 38 39 async function renderParidInput() { 40 41 const container = 42 document.getElementById( 43 'pao-parcelid-container' 44 ); 45 46 if (!container) { 47 return; 48 } 49 50 // Already rendered 51 if ( 52 container.dataset.rendered === '1' 53 ) { 54 return; 55 } 56 57 const response = await fetch( 58 '/wp-content/themes/frontier-child/components/shared/pao-uploads-parcelid.php' 59 ); 60 61 if (!response.ok) { 62 return; 63 } 64 65 container.innerHTML = 66 await response.text(); 67 68 // Rehydrate DOM references after lazy render 69 parcelId = 70 document.getElementById( 71 'pao_parcel_id' 72 ); 73 74 paridError = 75 document.getElementById( 76 'pao-parid-error' 77 ); 78 79 // Bind runtime events after render 80 bindEvents(); 81 82 // Initialize typeahead AFTER input exists 83 initializeTypeahead(); 84 85 container.dataset.rendered = '1'; 86 87 } 88 89 function bindEvents() { 90 91 parcelId.addEventListener("blur", handleBlur); 92 93 parcelId.addEventListener("keydown", function (event) { 94 95 // If the Enter key (keyCode 13 or key === "Enter") is pressed 96 if (event.key === "Enter") { 97 event.preventDefault(); // Prevent the form from being submitted 98 } 99 100 }); 101 102 } 103 104 function handleBlur() { 105 106 const paridLabel = 107 form.querySelector('label[for="pao_parcel_id"]'); 108 109 const valid = 110 isParcelIdValid(); 111 112 if (valid) { 113 114 validateField(parcelId, true, requiredInputFilled?.parcelId); 115 116 if (paridError) { 117 118 paridError.classList.remove("is-invalid"); 119 paridError.style.display = "none"; 120 121 } 122 } 123 else { 124 125 validateField(parcelId, false, requiredInputFilled?.parcelId); 126 127 clearTypeaheadSuggestionFields(); 128 129 if (requiredInputFilled?.parcelId) { 130 if (paridError) { 131 132 paridError.innerHTML = 133 '<i class="fas fa-exclamation-circle"></i> A Parcel Id is required.'; 134 135 paridError.classList.add('is-invalid'); 136 paridError.style.display = 'block'; 137 138 } 139 } 140 } 141 142 // Toggle asterisk color on label 143 if (paridLabel) { 144 145 paridLabel.classList.toggle("valid", valid); 146 147 paridLabel.classList.toggle( 148 "invalid", 149 !valid && requiredInputFilled?.parcelId 150 ); 151 152 } 153 154 // Recalculate full form + toggle drop area/file input 155 if (typeof validateForm === "function") { 156 157 validateForm(); 158 159 } 160 } 161 162 function setLastValidParid(parid) { 163 164 last_valid_parid = parid ?? ''; 165 166 if (parcelId) { 167 168 parcelId.value = 169 last_valid_parid; 170 171 isValid_Parid = true; 172 173 requiredInputFilled.parcelId = true; 174 } 175 } 176 177 async function showParidInput() { 178 179 await renderParidInput(); 180 181 const container = 182 document.getElementById( 183 'pao-parcelid-container' 184 ); 185 186 if (container) { 187 188 container.style.display = ''; 189 190 } 191 } 192 193 function hideParidInput() { 194 195 const container = 196 document.getElementById( 197 'pao-parcelid-container' 198 ); 199 200 if (container) { 201 202 container.style.display = 'none'; 203 204 } 205 } 206 207 async function hydrateRequired(isRequired) { 208 209 requiresParid = isRequired; 210 211 if (requiresParid) { 212 213 await showParidInput(); 214 215 } 216 else { 217 218 hideParidInput(); 219 220 } 221 222 if (!parcelId) { 223 return; 224 } 225 226 const parcelLabel = 227 document.querySelector(`label[for="${parcelId.id}"]`); // pao_parcel_id 228 229 if (!parcelLabel) { 230 return; 231 } 232 233 parcelLabel.classList.toggle('input-required-icon', requiresParid); 234 235 parcelId.required = requiresParid; 236 237 // Remove parid requirement 238 if (!requiresParid) { 239 240 delete requiredInputFilled.parcelId; 241 242 parcelId.classList.remove("is-valid", "is-invalid"); 243 parcelId.setCustomValidity(""); 244 245 if (paridError) { 246 247 paridError.classList.remove("is-valid", "is-invalid"); 248 paridError.style.display = "none"; 249 250 } 251 252 clearTypeaheadSuggestionFields(); 253 254 $(parcelId).typeahead("val", ""); 255 $(parcelId).typeahead("close"); 256 257 parcelLabel.textContent = "Real Property Parcel ID (Optional)"; 258 259 hideParidInput(); 260 261 } 262 else { 263 264 // Add parid to required fields 265 requiredInputFilled.parcelId = false; 266 267 parcelLabel.textContent = "Real Property Parcel ID:"; 268 269 } 270 } 271 272 /** 273 * Validates the parcel ID input field. 274 * 275 * Checks that the field exists, has more than 9 characters, and contains only numeric values. 276 * 277 * @returns {boolean} True if the parcel ID is valid, false otherwise. 278 */ 279 function isParcelIdValid() { 280 281 return ( 282 parcelId?.value?.length > 5 && 283 isNumeric(parcelId?.value?.trim()) 284 ); 285 286 } 287 288 function isValidParidSelected() { 289 290 return isValid_Parid; 291 292 } 293 294 /** 295 * Toggles Bootstrap validation classes on an input element based on its validity. 296 * 297 * If the field has no value (`hasValue` is false), all validation classes are removed. 298 * Otherwise, the `is-valid` class is added when `condition` is true, and `is-invalid` 299 * is added when `condition` is false. 300 * 301 * @param {HTMLElement} el - The input element to validate. 302 * @param {boolean} condition - The result of the validation check. 303 * @param {boolean} hasValue - Whether the field currently has a value. 304 */ 305 function validateField(el, condition, hasValue) { 306 307 if (!hasValue) { 308 309 el.classList.remove("is-valid", "is-invalid"); 310 311 } 312 else { 313 314 el.classList.toggle("is-valid", condition); 315 316 el.classList.toggle("is-invalid", !condition); 317 318 } 319 } 320 321 // Trigger mailing address validation whenever the user inputs data into the 'pao_mailing_address' field 322 document.getElementById('pao_mailing_address')?.addEventListener('input', function (event) { 323 mailingAddressValidation(); 324 });
325 326 // Validate the mailing address when the 'pao_mailing_address' field loses focus 327 document.getElementById('pao_mailing_address')?.addEventListener('blur', function (event) { 328 mailingAddressValidation(); 329 }); 330 331 /** 332 * Validates and compares the mailing address input with the address on file. 333 * - If the mailing address input is not empty, it is cleaned and compared with the saved address. 334 * - If the addresses differ, a digital signature input for changing the address is added to the page. 335 * - If the addresses are the same, any previously displayed address change section is hidden and the digital signature input is removed. 336 */ 337 function mailingAddressValidation() { 338 if (_pao_mailing_address_input?.value?.length > 0) { 339 let clean = new PaoAddressCleaner(_pao_mailing_address_input.value); 340 let address1 = clean.getCleanedAddress(); 341 342 clean = new PaoAddressCleaner(_pao_mailing_address_on_file); 343 let address2 = clean.getCleanedAddress(); 344 345 let el = document.getElementById('pao-address-change-digital-signature-block'); 346 if (address1 !== address2) { 347 if (!el) 348 addChangeAddressSignatureInput(); 349 } 350 if (address1 === address2) { 351 if (el) { 352 const pcab = document.getElementById('pao-change-address-block'); 353 pcab?.classList.add('d-none'); 354 pcab?.setAttribute('aria-hidden', 'true'); 355 el.remove(); 356 } 357 } 358 } 359 } 360 361 /** 362 * Dynamically creates and inserts a block for capturing a digital signature when a mailing address change is detected. 363 * The block contains a small instructional text and an input field for the user to provide their digital signature 364 * (by typing their name). 365 * 366 * Steps: 367 * 1. Check if the address change section (`#pao-change-address-block`) exists in the DOM. 368 * 2. If it exists, create a new block containing a message asking the user for their digital signature. 369 * 3. Add an input field where the user can type their name to provide the digital signature. 370 * 4. Append the newly created block to the address change section and make it visible. 371 */ 372 function addChangeAddressSignatureInput() { 373 try { 374 let el = document.getElementById('pao-change-address-block'); 375 if (el) { 376 377 let fragment = document.createDocumentFragment(); 378 379 let block = document.createElement('div'); 380 block.id = 'pao-address-change-digital-signature-block'; 381 382 let small = document.createElement('small'); 383 small.classList.add('form-text', 'text-primary', 'question-icon'); 384 small.ariaLabelledby = 'pao_address_change_digital_signature'; 385 small.style.fontSize = '0.9rem'; 386 small.style.fontWeight = 600; 387 small.textContent = "We've detected a mailing address change. Provide your digital signature (type your name) to change your parcel's mailing address." 388 fragment.appendChild(small); 389 390 let signatureInput = document.createElement('input'); 391 signatureInput.type = 'text'; 392 signatureInput.id = 'pao_address_change_digital_signature'; 393 signatureInput.name = 'pao_address_change_digital_signature'; 394 signatureInput.classList.add('form-control'); 395 signatureInput.name = 'pao_address_change_digital_signature'; 396 signatureInput.required = false; 397 signatureInput.ariaLabelledby = 'pao_address_change_digital_signature'; 398 signatureInput.ariaRequired = 'false'; // Required field for accessibility 399 signatureInput.style.width = '365px'; 400 signatureInput.style.marginBottom = '16px'; 401 signatureInput.value = ''; 402 // Remove the 'is-valid' class if it gets added by any validation logic 403 signatureInput.classList.remove('is-valid'); 404 fragment.appendChild(signatureInput); 405 406 block.appendChild(fragment); 407 408 el.appendChild(block); 409 el.classList.add('bg-light', 'p-2', 'mt-2', 'border', 'border-primary'); 410 el.classList.remove('d-none'); 411 el.setAttribute('aria-hidden', 'false'); 412 } 413 } catch (error) { 414 415 showDefaultErrorMessage(); 416 } 417 } 418 419 // ========================= 420 // AUTOCOMPLETE FUNCTIONS 421 // ========================= 422 423 /** 424 * Initializes the typeahead functionality for the PARID input field. 425 * - The input will trigger the suggestion list after typing 3 characters. 426 * - Debounces the request to fetch suggestions to avoid excessive calls (300ms delay). 427 * - Displays suggestions in a custom template showing the Parcel ID, Owner, and Situs Address. 428 * - Limits the number of displayed suggestions to 5. 429 * - Clears the suggestion list if the input is less than 3 characters. 430 */ 431 function initializeTypeahead() { 432 433 $(parcelId).typeahead( 434 { 435 hint: true, 436 highlight: true, 437 minLength: 3, // Trigger after 3 characters typed 438 }, 439 { 440 name: 'suggestions', 441 limit: 5, // also set in php 442 443 source: function (query, syncResults, asyncResults) { 444 445 // console.log("asyncResults function:", asyncResults); // Debugging to check asyncResults 446 447 if (query.length >= 3) { 448 // If the input is more than 3 characters, debounce the request 449 clearTimeout(timeoutID); // Clear the previous timeout 450 timeoutID = setTimeout(function () { 451 lookupParid(query, asyncResults); // Call lookupParid after the debounce delay 452 }, 300); // Adjust debounce delay as needed (300ms here) 453 } 454 else { 455 asyncResults([]); // Clear results if query is less than 3 characters 456 } 457 }, 458 display: function (item) { 459 return item.PARID; // Show only the first part (e.g., "123000059") in the input box 460 }, 461 templates: { 462 suggestion: function (data) { 463 return ` 464 <div class="pao-tt-suggestion" role="listbox" aria-l
464ive="polite" aria-label="Search suggestions"> 465 <div class="pao-tt-item" role="option" aria-selected="false"> 466 <div><strong>Parcel Id:</strong> ${data.PARID}</div> 467 <div><strong>Owner:</strong> ${data.OWNER}</div> 468 <div><strong>Situs Address:</strong> ${data.SITUS}</div> 469 </div> 470 </div>`; 471 } 472 } 473 } 474 ); 475 476 /** 477 * Event handler for when a suggestion is selected from the typeahead list. 478 * - Calls the `setTypeaheadSuggestionFields` function to populate the form fields with the selected suggestion's data. 479 */ 480 $(parcelId).on('typeahead:selected', function (event, suggestions) { 481 setTypeaheadSuggestionFields(suggestions); 482 if (typeof validateForm === "function") { 483 validateForm(); 484 } 485 }); 486 487 /** 488 * Event handler for when the PARID input field gains focus. 489 * Adjust the suggestion list width dynamically based on the input width 490 * - Adjusts the width of the typeahead dropdown to match the width of the input field with a small delay, ensuring proper alignment. 491 */ 492 $(parcelId).on('focus', function () { 493 var inputWidth = $(this).outerWidth(); 494 // Delay the width change after the typeahead dropdown has opened 495 setTimeout(function () { 496 $('.tt-menu').css('width', inputWidth); // Set the width of the dropdown 497 }, 50); // Small delay to ensure the dropdown is visible 498 }); 499 500 // Fired when the suggestion menu is closed. 501 // Sets input elements to the last selected typeahead value. 502 // Last values are cleared with every typeahead change. 503 $(parcelId).on('typeahead:close', function () { 504 505 parcelId.value = ""; 506 507 if (last_valid_parid) { 508 parcelId.value = last_valid_parid; 509 } 510 511 const selectedParcel = document.getElementById('pao_parcel_id'); 512 const situsAddress = document.getElementById('pao_situs_address'); 513 const mailingAddress = document.getElementById('pao_mailing_address'); 514 515 document.dispatchEvent( 516 new CustomEvent( 517 'pao:parcel-selected', 518 { 519 detail: { 520 parid: 521 selectedParcel?.value || '', 522 situsAddress: 523 situsAddress?.value || 524 last_situs_address || 525 '', 526 mailingAddress: 527 mailingAddress?.value || 528 last_mailing_address || 529 '' 530 } 531 } 532 ) 533 ); 534 }); 535 536 // Fired when input loses focus and the value has changed since it originally received focus. 537 $(parcelId).on('typeahead:change', function (event, query) { 538 //console.log('Query changed to: ', query); 539 if (!(query?.length > 0)) { 540 clearTypeaheadSuggestionFields(); 541 } 542 }); 543 } 544 545 /** 546 * Clears the input fields related to contact name, situs, and mailing address. 547 * - Sets the values of the fields _pao_contact_name, _pao_situs_input, and _pao_mailing_address_input to empty strings. 548 */ 549 function clearTypeaheadSuggestionFields() { 550 551 isValid_Parid = false; 552 553 fileInput?.classList.add('disabled'); 554 555 last_situs_address = ''; 556 last_mailing_address = ''; 557 _pao_mailing_address_on_file = ''; 558 559 // Set to empty string 560 _pao_contact_name && (_pao_contact_name.value = ''); 561 _pao_situs_input && (_pao_situs_input.value = ''); 562 _pao_mailing_address_input && (_pao_mailing_address_input.value = ''); 563 564 } 565 566 function cleanContactName(value) { 567 if (typeof value !== 'string') { 568 return ''; 569 } 570 const v = value.split(';')[0].trim().substring(0, 50); 571 // console.log(v); 572 return v; 573 } 574 575 /** 576 * Updates the typeahead suggestion fields with provided values. 577 * - Sets the values for PARID, contact name, situs, and mailing address. 578 * - Resets and restarts the animation on the input fields by manipulating CSS classes. 579 * - Stores the mailing address on file if not already set. 580 */ 581 function setTypeaheadSuggestionFields(suggestions) { 582 try { 583 584 isValid_Parid = true; 585 requiredInputFilled.parcelId = true; 586 last_valid_parid = suggestions.PARID; 587 588 if (parcelId.value !== suggestions.PARID) { 589 parcelId.value = suggestions.PARID; 590 } 591 592 if (_pao_contact_name) { 593 _pao_contact_name.value = suggestions.OWNER; 594 595 // 2026-09-04, gwb, fix issue with contact name being too long 596 // and containing multiple names separated by semicolons. 597 // Only the first name is kept and limited to 50 characters. 598 599 // Typeahead populates the field 600 if (_pao_contact_name) { 601 const owner = Array.isArray(suggestions.OWNER) 602 ? suggestions.OWNER[0] 603 : suggestions.OWNER; 604 605 _pao_contact_name.value = cleanContactName(owner); 606 } 607 608 // User manually changes the field 609 if (_pao_contact_name) { 610 _pao_contact_name.addEventListener('blur', function () { 611 this.value = cleanContactName(this.value); 612 }); 613 } 614 615 requiredInputFilled.contactName = 616 _pao_contact_name.value.trim().length > 0;
617 618 _pao_contact_name.classList.remove( 619 'is-invalid' 620 ); 621 } 622 623 if(_pao_situs_input) 624 _pao_situs_input.value = suggestions.SITUS; 625 626 last_situs_address = suggestions.SITUS; 627 628 if (_pao_mailing_address_input) { 629 _pao_mailing_address_input.value = suggestions.MAILING; 630 631 if (!_pao_mailing_address_on_file) 632 _pao_mailing_address_on_file = _pao_mailing_address_input?.value; 633 634 } 635 636 last_mailing_address = suggestions.MAILING; 637 638 // Remove the class to reset the animation 639 if (_pao_contact_name) { 640 _pao_contact_name.classList.remove('trans-font'); 641 } 642 643 if (_pao_situs_input) { 644 _pao_situs_input.classList.remove('trans-font'); 645 } 646 647 if (_pao_mailing_address_input) { 648 _pao_mailing_address_input.classList.remove('trans-font'); 649} 650 651 // Trigger reflow to ensure the animation is restarted 652 // This forces the reflow 653 if (_pao_contact_name) { 654 void _pao_contact_name.offsetWidth; 655 } 656 657 if (_pao_situs_input) { 658 void _pao_situs_input.offsetWidth; 659 } 660 661 if (_pao_mailing_address_input) { 662 void _pao_mailing_address_input.offsetWidth; 663 } 664 665 // Re-add the class to start the animation 666 if (_pao_contact_name) { 667 _pao_contact_name.classList.add('trans-font'); 668 } 669 670 if (_pao_situs_input) { 671 _pao_situs_input.classList.add('trans-font'); 672 } 673 674 if (_pao_mailing_address_input) { 675 _pao_mailing_address_input.classList.add('trans-font'); 676 } 677 678 if (typeof validateForm === "function") { 679 680 validateForm(); 681 682 } 683 684 } 685 catch (error) { 686 if (typeof showDefaultErrorMessage === "function") { 687 688 showDefaultErrorMessage(); 689 } 690 } 691 } 692 693 /** 694 * Fetches the PARID search results based on the provided search value. 695 * - Determines if the search value is numeric or a name and formats the request accordingly. 696 * - Sends a POST request to a PHP endpoint to retrieve matching PARID records. 697 * - If results are found, formats and sets the typeahead suggestion fields with the data. 698 * - If the data structure is not as expected or an error occurs, clears the suggestions. 699 * - Returns the results asynchronously to the typeahead suggestion box. 700 */ 701 function lookupParid(lu_value, asyncResults) { 702 try { 703 704 const isNumeric = !/[^0-9]/.test(lu_value); 705 706 const obj = { 707 job: "parid_search", 708 findBy: isNumeric ? "findby-number" : "findby-name", 709 findText: lu_value, 710 rollType: 'R' 711 }; 712 713 const json = JSON.stringify(obj); 714 715 // asyncResults is a function that is used to pass back the results to the 716 // Typeahead suggestion box asynchronously. 717 718 // Fetch the data using the Fetch API 719 const url = `${window.PAOPATH.theme}/models/pao-model-find-parid.php`; 720 721 fetch(url, { 722 method: 'POST', 723 headers: { 724 'Content-Type': 'application/x-www-form-urlencoded', 725 }, 726 body: 'Request=' + encodeURIComponent(json) 727 }) 728 .then(response => response.json()) 729 .then(data => { 730 731 let suggestions = null; 732 733 if (Array.isArray(data)) { 734 735 // If the data is already an array of arrays, pass it directly 736 if (data?.length === 1) { 737 738 // If 'data' is an array of objects, use reduce to transform it into an object 739 suggestions = data.reduce((acc, item) => { 740 741 acc.PARID.push(item.PARID); 742 acc.OWNER.push(item.OWNER); 743 acc.SITUS.push(item.SITUS); 744 acc.MAILING.push(item.MAILING); 745 746 return acc; 747 748 }, { PARID: [], OWNER: [], SITUS: [], MAILING: [] }); 749 750 setTypeaheadSuggestionFields(suggestions); 751 752 } 753 else { 754 755 clearTypeaheadSuggestionFields(); 756 757 } 758 759 asyncResults(data); 760 761 } 762 else if (Array.isArray(data.items)) { 763 764 // Item was selected. 765 // If the data structure contains an array under 'items', map the results accordingly 766 suggestions = data.map(item => [item.PARID, item.OWNER, item.SITUS, item.MAILING]); 767 768 asyncResults(suggestions); 769 770 } 771 else { 772 773 asyncResults([]); // If the structure is unexpected, return an empty array 774 775 } 776 777 }) 778 .catch(error => { 779 780 if (typeof showDefaultErrorMessage === "function") { 781 782 showDefaultErrorMessage(); 783 } 784 785 asyncResults([]); 786 787 }); 788 } 789 catch (error) { 790 791 if (typeof showDefaultErrorMessage === "function") { 792 793 showDefaultErrorMessage(); 794 } 795 } 796 } 797 798 799 /** 800 * Looks up a Parcel ID and populates the 801 * related fields exactly as if the user 802 * had selected a typeahead suggestion. 803 * 804 * @param {string} parid 805 */ 806 function populateFromParid(parid) { 807 808 lookupParid( 809 parid, 810 function (results) { 811 812 if ( 813 Array.isArray(results) && 814 results.length === 1 815 ) { 816 817 setTypeaheadSuggestionFields( 818 results[0] 819 ); 820 821 } 822 823 } 824 ); 825 826 } 827 828 // Initialize Bloodhound suggestion engine without a remote URL 829 function initializeBloodhound() { 830 831 if (typeof Bloodhound === "undefined") { 832 return; 833 } 834 835 const engine = new Bloodhound({ 836 datumTokenizer: Bloodhound.tokenizers.whitespace, 837 queryTokenizer: Bloodhound.tokenizers.whitespace, 838 local: [], // Start with an empty local list (which will be populated by the AJAX response) 839 }); 840 841 return engine; 842 843 } 844 845 /** 846 * Checks if the input string is a valid number. 847 * Returns true if the string is numeric, otherwise false. 848 * 849 * @param {string} str - The string to validate. 850 * @returns {boolean} - Whether the string is numeric. 851 */ 852 function isNumeric(str) { 853 854 return !isNaN(str) && !isNaN(parseFloat(str)); 855 856 } 857 858 function reset() { 859 860 clearTypeaheadSuggestionFields(); 861 862 if (!parcelId) { 863 return; 864 } 865 866 // clear value 867 $(parcelId).typeahead("val", ""); 868 869 $(parcelId).typeahead("close"); 870 871 parcelId.classList.remove("is-valid", "is-invalid"); 872 873 parcelId.setCustomValidity(""); 874 875 if (paridError) { 876 877 paridError.innerHTML = ""; 878 879 paridError.classList.remove("is-valid", "is-invalid"); 880 881 paridError.style.display = "none"; 882 883 } 884 885 const paridLabel = 886 form.querySelector('label[for="pao_parcel_id"]'); 887 888 if (paridLabel) { 889 890 paridLabel.classList.remove("valid", "invalid"); 891 892 } 893 } 894 895 return { 896 initialize, 897 hydrateRequired, 898 isParcelIdValid, 899 isValidParidSelected, 900 clearTypeaheadSuggestionFields, 901 reset, 902 setLastValidParid, 903 populateFromParid 904 }; 905 906})(); 907 908export default ParcelIdModule;
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.