PageSourceSearch

https://www.manateepao.gov/wp-content/themes/frontier-child/compon…/shared/pao-uploads-parcelid-module.esm.js

js manateepao.gov collected 2026-09-28 06:48:04 UTC 29,832 bytes, 908 lines download raw bytes

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.