PageSourceSearch

https://www.northtampabehavioralhealth.com/wp-content/plugins/SFWFA/js/formval_too.min.js?ver=20260710.1

js northtampabehavioralhealth.com collected 2026-09-29 21:47:53 UTC 51,450 bytes, 1,744 lines download raw bytes

1// var nbsp = 160;		// non-breaking space char
2var node_text = 3;	// DOM text node-type
3var emptyString = /^\s*$/ ;
4var global_valfield;	// retain valfield for timer thread
5
6// --------------------------------------------
7//                  trim
8// Trim leading/trailing whitespace off string
9// --------------------------------------------
10
11function trim(str)
12{
13    return str.replace(/^\s+|\s+$/g, '');
14}
15
16
17// --------------------------------------------
18//                  setfocus
19// Delayed focus setting to get around IE bug
20// --------------------------------------------
21
22function setFocusDelayed()
23{
24    global_valfield.focus();
25}
26
27function setfocus(valfield)
28{
29    // save valfield in global variable so value retained when routine exits
30    global_valfield = valfield;
31    setTimeout( 'setFocusDelayed()', 100 );
32}
33
34
35// --------------------------------------------
36//                  msg
37// Display warn/error message in HTML element.
38// commonCheck routine must have previously been called
39// --------------------------------------------
40
41function msg(fld,     // id of element to display message in
42             msgtype, // class to give element ("warn" or "error")
43             message) // string to display
44{
45    console.log(fld);
46    // setting an empty string can give problems if later set to a
47    // non-empty string, so ensure a space present. (For Mozilla and Opera one could
48    // simply use a space, but IE demands something more, like a non-breaking space.)
49    var dispmessage;
50    if (emptyString.test(message))
51        dispmessage = '';
52    else
53        dispmessage = message;
54    var elem = document.getElementById(fld);
55    // console.log(dispmessage);
56    // elem.firstChild.nodeValue = dispmessage;
57    jQuery('#'+fld).text(dispmessage);
58
59    elem.className = msgtype;   // set the CSS class to adjust appearance of message
60}
61
62// --------------------------------------------
63//            commonCheck
64// Common code for all validation routines to:
65// (a) check for older / less-equipped browsers
66// (b) check if empty fields are required
67// Returns true (validation passed),
68//         false (validation failed) or
69//         proceed (don't know yet)
70// --------------------------------------------
71
72var proceed = 2;
73
74function commonCheck(valfield, infofield, required)
75{
76    if (!document.getElementById) {
77        return true;
78    }
79
80    var elem = document.getElementById(infofield);
81    if (elem == null) {
82        return true;
83    }
84
85    if (emptyString.test(valfield.value)) {
86        if (required) {
87            msg(infofield, "errorNode", "Required");
88            jQuery('#' + infofield).show();
89            jQuery(valfield).css('border', '1px solid #FF0000');
90            return false;
91        } else {
92            msg(infofield, "warn", "");
93            jQuery('#' + infofield).hide();
94            jQuery(valfield).css('border', '');
95            return true;
96        }
97    }
98
99    jQuery('#' + infofield).hide();
100    return proceed;
101}
102
103// --------------------------------------------
104//            greenLight
105// Simply removes red borders assuming all is ok
106// Returns void
107// --------------------------------------------
108
109function greenLight (valfield) // element to be green lit
110{
111    jQuery(valfield).css('border', '1px solid #008000');
112}
113
114// --------------------------------------------
115//            redLight
116// Simply makes border red
117// Returns void
118// --------------------------------------------
119
120function redLight (valfield) // element to be red lit
121{
122    jQuery(valfield).css('border', '1px solid #FF0000');
123}
124
125// --------------------------------------------
126//               validateEmailAddress
127// Validate if e-mail address
128// Returns true if so (and also if could not be executed because of old browser)
129// --------------------------------------------
130
131function validateEmailAddress  (valfield,   // element to be validated
132                                infofield,  // id of element to receive info/error msg
133                                required)   // true if required
134{
135    if (required) {
136        var stat = commonCheck (valfield, infofield, required);
137        if (stat !== proceed) return stat;
138    }
139    var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
140    if (required || tfld.length > 0) {
141        var email = /^[^@]+@[^@.]+\.[^@]*\w\w$/;
142        if (!email.test(tfld)) {
143            msg(infofield, "errorNode", "Invalid email");
144            jQuery('#' + infofield).show();
145            // setfocus(valfield);
146            redLight(valfield);
147            return false;
148        }
149
150        var email2 = /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/;
151        if (!email2.test(tfld)) {
152            msg(infofield, "errorNode", "Malformed email");
153            jQuery('#' + infofield).show();
154            redLight(valfield);
155            return false;
156        }
157    } else {
158        msg (infofield, "errorNode", "");
159    }
160    greenLight(valfield);
161    return true;
162}
163
164// --------------------------------------------
165//            validatePhone
166// Validate telephone number
167// Returns true if so (and also if could not be executed because of old browser)
168// Permits spaces, hyphens, brackets and leading +
169// --------------------------------------------
170
171function validatePhone  (valfield,   // element to be validated
172                         infofield,  // id of element to receive info/error msg
173                         required)   // true if required
174{
175    if (required) {
176        var stat = commonCheck (valfield, infofield, required);
177        if (stat !== proceed) return stat;
178    }
179
180    var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
181    if (required || tfld.length > 0) {
182        var phone1 = /^\+?[0-9 .()-]+[0-9]$/  ;
183        if (!phone1.test(tfld)) {
184            msg (infofield, "errorNode", "Invalid phone");
185            jQuery('#' + infofield).show();
186            // setfocus(valfield);
187            redLight(valfield);
188            return false;
189        }
190
191        //Checks for 555 area codes (movie phones)
192        var filteredPhone = valfield.value.replace(/[^0-9]/g, "");
193        var moviePhone = /^(555)(.*)$/;
194        if (moviePhone.test(filteredPhone)) {
195            msg (infofield, "errorNode", "Invalid area code");
196            jQuery('#' + infofield).show();
197            // setfocus(valfield);
198            redLight(valfield);
199            return false;
200        }
201
202        var numdigits = 0;
203        for (var j=0; j<tfld.length; j++)
204            if (tfld.charAt(j)>='0' && tfld.charAt(j)<='9') numdigits++;
205
206        if (numdigits<7) {
207            msg (infofield, "errorNode", "Only " + numdigits + " digits: please correct.");
208            jQuery('#' + infofield).show();
209            // setfocus(valfield);
210            redLight(valfield);
211            return false;
212        }
213
214        if (numdigits>14) {
215            msg (infofield, "errorNode", asterisk + numdigits + " digits?");
216            jQuery('#' + infofield).show();
217            redLight(valfield);
218            return false;
219        } else {
220            if (numdigits<10) {
221                msg (infofield, "errorNode", asterisk + numdigits + " digits: no area code?");
222                jQuery('#' + infofield).show();
223                redLight(valfield);
224                return false;
225            } else {
226                msg (infofield, "errorNode", "");
227                jQuery('#' + infofield).hide();
228            }
229        }
230    }
231    greenLight(valfield);
232    return true;
233}
234
235// --------------------------------------------
236//             validateAge
237// Validate person's age
238// Returns true if OK
239// --------------------------------------------
240
241function validateAge    (valfield,   // element to be validated
242                         infofield,  // id of element to receive info/error msg
243                         required)   // true if required
244{
245    var stat = commonCheck (valfield, infofield, required);
246    if (stat !== proceed) {
247        if (!required) {
248            jQuery('#' + infofield).hide();
249            greenLight(valfield);
250        }
251        return stat;
252    }
253
254    var tfld = trim(valfield.value);
255    var ageRE = /^[0-9]{1,3}$/
256    if (!ageRE.test(tfld)) {
257        msg (infofield, "errorNode", "Invalid age");
258        jQuery('#' + infofield).show();
259        redLight(valfield);
260        // setfocus(valfield);
261        return false;
262    }
263
264    if (tfld>125) {
265        msg (infofield, "errorNode", "Invalid age");
266        jQuery('#' + infofield).show();
267        redLight(valfield);
268    } else {
269        if (tfld<9) {
270            msg (infofield, "errorNode", "Invalid age");
271            jQuery('#' + infofield).show();
272            redLight(valfield);
273        } else {
274            msg (infofield, "errorNode", "");
275            jQuery('#' + infofield).hide();
276            greenLight(valfield);
277        }
278    }
279
280    return true;
281}
282
283// --------------------------------------------
284//             validateZip
285// Validate zipcode
286// Returns true if OK
287// --------------------------------------------
288
289function validateZip(valfield, infofield, required)
290{
291    var stat = commonCheck(valfield, infofield, required);
292    if (stat !== proceed) return stat;
293
294    var zfld = trim(valfield.value);
295    var zipRE = /^[0-9]{5}$/;
296
297    // Optional zip fields are valid when left blank. If supplied, they must
298    // still contain exactly five digits.
299    if (!required && zfld.length === 0) {
300        msg(infofield, "errorNode", "");
301        jQuery('#' + infofield).hide();
302        greenLight(valfield);
303        return true;
304    }
305
306    if (!zipRE.test(zfld)) {
307        msg(infofield, "errorNode", "Invalid zip");
308        jQuery('#' + infofield).show();
309        redLight(valfield);
310        return false;
311    }
312
313    msg(infofield, "errorNode", "");
314    jQuery('#' + infofield).hide();
315    greenLight(valfield);
316    return true;
317}
318
319function validateIntZip    (valfield,   // element to be validated
320                            infofield,  // id of element to receive info/error msg
321                            required)   // true if required
322{
323    if (required) {
324        var stat = commonCheck (valfield, infofield, required);
325        if (stat !== proceed) return stat;
326    }
327    var zfld = trim(valfield.value);
328    var ageRE = /^[a-zA-Z0-9\s\-]{1,15}$/
329    if (required || zfld.length > 0) {
330        if (!ageRE.test(zfld)) {
331            msg (infofield, "errorNode", "Invalid zip");
332            jQuery('#' + infofield).show();
333            redLight(valfield);
334            return false;
335        }
336    }
337    msg (infofield, "errorNode", "");
338    jQuery('#' + infofield).hide();
339    greenLight(valfield);
340    return true;
341}
342
343// *** --------------------------------------------
344//             validateName
345// Validate the input tag for Name
346// Returns true if OK
347// --------------------------------------------
348
349function validateName(valfield,   // element to be validated
350                      infofield,  // id of element to receive info/error msg
351                      required  )
352{
353    if (required) {
354        var stat = commonCheck (valfield, infofield, required);
355        if (stat !== proceed) return stat;
356    }
357    var tfld = trim(valfield.value);
358    if (required || tfld.length > 0) {
359        if(tfld.length < 2) {
360            msg(infofield,"errorNode", "Must be at least 2 characters");
361            jQuery('#' + infofield).show();
362            // setfocus(valfield);
363            redLight(valfield);
364            return false;
365        }
366    }
367    msg (infofield, "errorNode", "");
368    jQuery('#' + infofield).hide();
369    greenLight(valfield);
370    return true;
371}
372
373// *** --------------------------------------------
374//             validateSchedulerDate
375// Validate the CTC Scheduler dateSelect
376// Returns true if OK
377// --------------------------------------------
378
379function validateSchedulerDate(valfield, infofield, required)
380{
381    var radioName = 'ctc_scheduler_date';
382    var isoRegex = /^\d{4}-\d{2}-\d{2}$/;
383
384    var $selected = jQuery('input[name="' + radioName + '"]:checked');
385    var $dateField = jQuery('.dayBtn-datepicker').first();
386    var schedulerConfig = getSchedulerConfig();
387    var holidays = schedulerConfig.holidays || [];
388
389    if (!$selected.length) {
390        if (required) {
391            msg(infofield, "errorNode", "Required");
392            jQuery('#' + infofield).show();
393            redLight(jQuery('input[name="' + radioName + '"]'));
394            return false;
395        }
396
397        msg(infofield, "errorNode", "");
398        jQuery('#' + infofield).hide();
399        return true;
400    }
401
402    var isCustomOption = $selected.closest('.dayBtn-picker').length > 0;
403
404    if (isCustomOption) {
405        var dateVal = $dateField.val();
406
407        if (!dateVal) {
408            msg(infofield, "errorNode", "Please select a date");
409            jQuery('#' + infofield).show();
410            redLight($dateField);
411            return false;
412        }
413
414        if (!isoRegex.test(dateVal)) {
415            msg(infofield, "errorNode", "Invalid date");
416            jQuery('#' + infofield).show();
417            redLight($dateField);
418            return false;
419        }
420
421        var isHoliday = holidays.indexOf(dateVal) !== -1;
422
423        if (isHoliday) {
424            msg(infofield, "errorNode", "Selected date is unavailable");
425            jQuery('#' + infofield).show();
426            redLight($dateField);
427            return false;
428        }
429
430        if (!getScheduleWindowForDate(dateVal)) {
431            msg(infofield, "errorNode", "Selected date is unavailable");
432            jQuery('#' + infofield).show();
433            redLight($dateField);
434            return false;
435        }
436
437        msg(infofield, "errorNode", "");
438        jQuery('#' + infofield).hide();
439        greenLight($dateField);
440        return true;
441    }
442
443    var value = $selected.val();
444
445    if (!isoRegex.test(value)) {
446        msg(infofield, "errorNode", "Invalid date");
447        jQuery('#' + infofield).show();
448        redLight($selected);
449        return false;
450    }
451
452    msg(infofield, "errorNode", "");
453    jQuery('#' + infofield).hide();
454    greenLight($selected);
455    return true;
456}
457
458function validateSchedulerTime(valfield, infofield, required)
459{
460    var radioName = 'ctc_scheduler_time';
461    var $selected = jQuery('input[name="' + radioName + '"]:checked');
462    var $all = jQuery('input[name="' + radioName + '"]');
463
464    if (!$selected.length) {
465        if (required) {
466            msg(infofield, "errorNode", "Required");
467            jQuery('#' + infofield).show();
468            redLight($all);
469            return false;
470        }
471
472        msg(infofield, "errorNode", "");
473        jQuery('#' + infofield).hide();
474        return true;
475    }
476
477    if ($selected.prop('disabled')) {
478        msg(infofield, "errorNode", "Please select an available time");
479        jQuery('#' + infofield).show();
480        redLight($all);
481        return false;
482    }
483
484    msg(infofield, "errorNode", "");
485    jQuery('#' + infofield).hide();
486    greenLight($selected);
487    return true;
488}
489
490var schedulerFallbackConfig = null;
491var schedulerNearbyAvailabilityExhausted = false;
492
493
494function safeParseSchedulerJson(rawValue, fallbackValue) {
495    if (typeof rawValue === 'undefined' || rawValue === null || rawValue === '') {
496        return fallbackValue;
497    }
498
499    if (typeof rawValue === 'object') {
500        return rawValue;
501    }
502
503    try {
504        return JSON.parse(rawValue);
505    } catch (e) {
506        return fallbackValue;
507    }
508}
509
510function readSchedulerConfigFromElement($element, attrNames) {
511    if (!$element || !$element.length) {
512        return null;
513    }
514
515    return {
516        holidays: safeParseSchedulerJson($element.attr(attrNames.holidays), []),
517        schedule: safeParseSchedulerJson($element.attr(attrNames.schedule), {}),
518        specialSchedule: safeParseSchedulerJson($element.attr(attrNames.specialSchedule), {})
519    };
520}
521
522function getFallbackSchedulerConfig() {
523    if (schedulerFallbackConfig !== null) {
524        return schedulerFallbackConfig;
525    }
526
527    var $group = jQuery('.dayBtn-group').first();
528    schedulerFallbackConfig = readSchedulerConfigFromElement($group, {
529        holidays: 'data-holidays',
530        schedule: 'data-schedule',
531        specialSchedule: 'data-special-schedule'
532    }) || {
533        holidays: [],
534        schedule: {},
535        specialSchedule: {}
536    };
537
538    return schedulerFallbackConfig;
539}
540
541function getSelectedFacilitySchedulerConfig() {
542    var $select = jQuery('select[name="facilityChoice"]').first();
543
544    if (!$select.length || !$select.val() || $select.val() === '0') {
545        return null;
546    }
547
548    var $option = $select.find('option:selected').first();
549
550    if (!$option.length) {
551        return null;
552    }
553
554    if ($option.attr('data-scheduler-config') !== '1') {
555        if (getSchedulerMode() === 'homepage') {
556            return {
557                holidays: [],
558                schedule: {},
559                specialSchedule: {}
560            };
561        }
562
563        return null;
564    }
565
566    return readSchedulerConfigFromElement($option, {
567        holidays: 'data-scheduler-holidays',
568        schedule: 'data-scheduler-schedule',
569        specialSchedule: 'data-scheduler-special-schedule'
570    });
571}
572
573function getSchedulerConfig() {
574    return getSelectedFacilitySchedulerConfig() || getFallbackSchedulerConfig();
575}
576
577function getSchedulerController() {
578    return jQuery('.ctc-scheduler-controller').first();
579}
580
581function getSchedulerMode() {
582    var $controller = getSchedulerController();
583    return $controller.length ? String($controller.attr('data-ctc-scheduler-mode') || '') : '';
584}
585
586function getSchedulerWrapper() {
587    var $controller = getSchedulerController();
588
589    if ($controller.length) {
590        var $wrapper = $controller.closest('.ctcscheduler_mainWrapper');
591        if ($wrapper.length) {
592            return $wrapper;
593        }
594    }
595
596    return jQuery('.ctcscheduler_mainWrapper').first();
597}
598
599function initializeSchedulerWrapperState() {
600    var mode = getSchedulerMode();
601    var $wrapper = getSchedulerWrapper();
602
603    if (!$wrapper.length) {
604        return;
605    }
606
607    $wrapper
608        .removeClass('ctc-scheduler-mode-homepage ctc-scheduler-mode-lp')
609        .addClass(mode === 'homepage' ? 'ctc-scheduler-mode-homepage' : (mode === 'lp' ? 'ctc-scheduler-mode-lp' : ''));
610
611    if (mode === 'lp') {
612        jQuery('#scheduler_shortname_selector').hide();
613    } else if (mode === 'homepage') {
614        jQuery('#scheduler_shortname_selector').show();
615    }
616}
617
618function getFacilitySchedulerStatusFromOption($option) {
619    if (!$option || !$option.length) {
620        return null;
621    }
622
623    if ($option.attr('data-scheduler-config') !== '1') {
624        return {
625            schedulerEnabled: '0',
626            holdAdmits: false,
627            noHours: true,
628            missingSchedulerConfig: true
629        };
630    }
631
632    return {
633        schedulerEnabled: $option.attr('data-scheduler-enabled'),
634        holdAdmits: $option.attr('data-scheduler-hold-admits') === '1',
635        noHours: $option.attr('data-scheduler-no-hours') === '1'
636    };
637}
638
639function isFacilitySchedulerStatusAvailable(status) {
640    if (!status) {
641        return false;
642    }
643
644    if (String(status.schedulerEnabled || '') !== '1') {
645        return false;
646    }
647
648    return !status.holdAdmits && !status.noHours;
649}
650
651function isFacilityOptionSchedulerAvailable($option) {
652    return isFacilitySchedulerStatusAvailable(getFacilitySchedulerStatusFromOption($option));
653}
654
655function getSelectedFacilitySchedulerStatus() {
656    var $select = jQuery('select[name="facilityChoice"]').first();
657
658    if (!$select.length || !$select.val() || $select.val() === '0') {
659        return null;
660    }
661
662    return getFacilitySchedulerStatusFromOption($select.find('option:selected').first());
663}
664
665function shouldShowSchedulerUnavailableMessage() {
666    if (getSchedulerMode() !== 'homepage') {
667        return false;
668    }
669
670    if (schedulerNearbyAvailabilityExhausted) {
671        return true;
672    }
673
674    var status = getSelectedFacilitySchedulerStatus();
675
676    if (!status) {
677        return false;
678    }
679
680    return !isFacilitySchedulerStatusAvailable(status);
681}
682
683function getNearbyFacilityOptions() {
684    var $select = jQuery('select[name="facilityChoice"]').first();
685
686    if (!$select.length) {
687        return jQuery();
688    }
689
690    return $select.find('option[data-scheduler-nearby="1"]').slice(0, 5);
691}
692
693function selectNearbyFacilityWithAvailability() {
694    schedulerNearbyAvailabilityExhausted = false;
695
696    if (getSchedulerMode() !== 'homepage') {
697        return false;
698    }
699
700    var $select = jQuery('select[name="facilityChoice"]').first();
701    var $nearbyOptions = getNearbyFacilityOptions();
702
703    if (!$select.length || !$nearbyOptions.length) {
704        return false;
705    }
706
707    var $selected = $select.find('option:selected').first();
708
709    if (!$selected.length || $selected.attr('data-scheduler-nearby') !== '1') {
710        return false;
711    }
712
713    if (isFacilityOptionSchedulerAvailable($selected)) {
714        return false;
715    }
716
717    var selectedOption = null;
718
719    $nearbyOptions.each(function() {
720        var $option = jQuery(this);
721
722        if (selectedOption === null && isFacilityOptionSchedulerAvailable($option)) {
723            selectedOption = this;
724        }
725    });
726
727    if (selectedOption) {
728        $select.prop('selectedIndex', selectedOption.index);
729        return true;
730    }
731
732    schedulerNearbyAvailabilityExhausted = true;
733    return false;
734}
735
736function isSchedulerCurrentlyUnavailable() {
737    var $wrapper = getSchedulerWrapper();
738    return $wrapper.length && $wrapper.hasClass('ctc-scheduler-unavailable');
739}
740
741function updateSchedulerUnavailableState() {
742    var $wrapper = getSchedulerWrapper();
743
744    if (!$wrapper.length) {
745        return false;
746    }
747
748    var unavailable = shouldShowSchedulerUnavailableMessage();
749    $wrapper
750        .toggleClass('ctc-scheduler-unavailable', unavailable)
751        .toggleClass('ctc-scheduler-nearby-unavailable', unavailable && schedulerNearbyAvailabilityExhausted);
752
753    if (unavailable) {
754        clearSchedulerSelections();
755    }
756
757    return unavailable;
758}
759
760function writeSchedulerConfigToDateControls(config) {
761    var $group = jQuery('.dayBtn-group').first();
762    var $dateField = jQuery('.dayBtn-datepicker').first();
763
764    if (!$group.length) {
765        return;
766    }
767
768    var holidaysJson = JSON.stringify(config.holidays || []);
769    var scheduleJson = JSON.stringify(config.schedule || {});
770    var specialScheduleJson = JSON.stringify(config.specialSchedule || {});
771
772    $group
773        .attr('data-holidays', holidaysJson)
774        .attr('data-schedule', scheduleJson)
775        .attr('data-special-schedule', specialScheduleJson)
776        .data('holidays', config.holidays || [])
777        .data('schedule', config.schedule || {})
778        .data('special-schedule', config.specialSchedule || {});
779
780    $dateField
781        .attr('data-holidays', holidaysJson)
782        .attr('data-schedule', scheduleJson)
783        .attr('data-special-schedule', specialScheduleJson)
784        .data('holidays', config.holidays || [])
785        .data('schedule', config.schedule || {})
786        .data('special-schedule', config.specialSchedule || {});
787}
788
789function getTodayIsoDate() {
790    var today = new Date();
791    return (
792        today.getFullYear() + '-' +
793        String(today.getMonth() + 1).padStart(2, '0') + '-' +
794        String(today.getDate()).padStart(2, '0')
795    );
796}
797
798function addDaysToIsoDate(isoDate, daysToAdd) {
799    var parts = String(isoDate).split('-');
800    var d = new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
801    d.setDate(d.getDate() + daysToAdd);
802
803    return (
804        d.getFullYear() + '-' +
805        String(d.getMonth() + 1).padStart(2, '0') + '-' +
806        String(d.getDate()).padStart(2, '0')
807    );
808}
809
810function formatSchedulerDateLabel(isoDate) {
811    var parts = String(isoDate).split('-');
812    var d = new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
813
814    return d.toLocaleDateString('en-US', {
815        weekday: 'short',
816        month: 'short',
817        day: 'numeric'
818    });
819}
820
821function getSelectedSchedulerDate() {
822    var $selectedDateRadio = jQuery('input[name="ctc_scheduler_date"]:checked');
823    var $customDateField = jQuery('.dayBtn-datepicker').first();
824
825    if (!$selectedDateRadio.length) {
826        return '';
827    }
828
829    if ($selectedDateRadio.closest('.dayBtn-picker').length) {
830        return $customDateField.val() || '';
831    }
832
833    return $selectedDateRadio.val() || '';
834}
835
836function isoToMonthDayKey(isoDate) {
837    var parts = String(isoDate).split('-');
838    if (parts.length !== 3) {
839        return '';
840    }
841
842    return parseInt(parts[1], 10) + '/' + parseInt(parts[2], 10) + '/' + parseInt(parts[0], 10);
843}
844
845function isoToDayKey(isoDate) {
846    var parts = String(isoDate).split('-');
847    if (parts.length !== 3) {
848        return '';
849    }
850
851    var d = new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
852    var keys = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
853    return keys[d.getDay()];
854}
855
856function parse24HourTimeToMinutes(value) {
857    var match = String(value).match(/^(\d{1,2}):(\d{2})$/);
858    if (!match) {
859        return null;
860    }
861
862    var hour = parseInt(match[1], 10);
863    var minute = parseInt(match[2], 10);
864
865    if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
866        return null;
867    }
868
869    return (hour * 60) + minute;
870}
871
872function parseSchedulerTimeToMinutes(timeValue) {
873    var match = String(timeValue).match(/^(\d{1,2}):(\d{2}) ([AP]M)$/);
874    if (!match) {
875        return null;
876    }
877
878    var hour = parseInt(match[1], 10);
879    var minute = parseInt(match[2], 10);
880    var meridiem = match[3];
881
882    if (meridiem === 'AM') {
883        if (hour === 12) {
884            hour = 0;
885        }
886    } else {
887        if (hour !== 12) {
888            hour += 12;
889        }
890    }
891
892    return (hour * 60) + minute;
893}
894
895function getScheduleWindowForDateFromConfig(isoDate, config) {
896    config = config || {
897        holidays: [],
898        schedule: {},
899        specialSchedule: {}
900    };
901
902    var mdKey = isoToMonthDayKey(isoDate);
903    var dayKey = isoToDayKey(isoDate);
904    var window = null;
905
906    if (config.schedule && config.schedule[dayKey]) {
907        window = config.schedule[dayKey];
908    }
909
910    if (config.specialSchedule && Object.prototype.hasOwnProperty.call(config.specialSchedule, mdKey)) {
911        var specialWindow = config.specialSchedule[mdKey];
912
913        if (
914            jQuery.isArray(specialWindow) &&
915            specialWindow.length === 2 &&
916            specialWindow[0] !== '' &&
917            specialWindow[1] !== ''
918        ) {
919            window = specialWindow;
920        } else {
921            window = null;
922        }
923    }
924
925    if (config.holidays && config.holidays.indexOf(isoDate) !== -1) {
926        return null;
927    }
928
929    return window;
930}
931
932function getScheduleWindowForDate(isoDate) {
933    return getScheduleWindowForDateFromConfig(isoDate, getSchedulerConfig());
934}
935
936function getNextSchedulerDates(count, config) {
937    var dates = [];
938    var $dateField = jQuery('.dayBtn-datepicker').first();
939    var maxDate = $dateField.attr('max') || '';
940    var cursor = getTodayIsoDate();
941    var daysChecked = 0;
942
943    while (dates.length < count && daysChecked < 62) {
944        cursor = addDaysToIsoDate(cursor, 1);
945        daysChecked++;
946
947        if (maxDate && cursor > maxDate) {
948            break;
949        }
950
951        if (getScheduleWindowForDateFromConfig(cursor, config)) {
952            dates.push({
953                value: cursor,
954                display: formatSchedulerDateLabel(cursor)
955            });
956        }
957    }
958
959    return dates;
960}
961
962function clearSchedulerSelections() {
963    jQuery('input[name="ctc_scheduler_date"]').prop('checked', false);
964    jQuery('.dayBtn-datepicker').val('');
965    jQuery('input[name="ctc_scheduler_time"]').prop('checked', false);
966
967    resetCustomDateOption(false);
968
969    msg('ctc_scheduler_dateError', "errorNode", "");
970    jQuery('#ctc_scheduler_dateError').hide();
971    msg('ctc_scheduler_timeError', "errorNode", "");
972    jQuery('#ctc_scheduler_timeError').hide();
973}
974
975function refreshSchedulerDateButtons(config) {
976    var $group = jQuery('.dayBtn-group').first();
977    var $dateButtons = $group.find('label.dayBtn').not('.dayBtn-picker');
978    var dates = getNextSchedulerDates(2, config);
979
980    $dateButtons.each(function(index) {
981        var $button = jQuery(this);
982        var $input = $button.find('input[type="radio"]').first();
983        var $span = $button.find('span').first();
984        var dateInfo = dates[index];
985
986        if (dateInfo) {
987            $input.val(dateInfo.value).prop('disabled', false).prop('checked', false);
988            $button.removeClass('disabled');
989            $span.text(dateInfo.display);
990        } else {
991            $input.val('').prop('disabled', true).prop('checked', false);
992            $button.addClass('disabled');
993            $span.text(index === 0 ? 'No dates available' : '');
994        }
995    });
996}
997
998function refreshSchedulerForSelectedFacility(clearSelections, autoSelectNearby) {
999    if (autoSelectNearby) {
1000        selectNearbyFacilityWithAvailability();
1001    } else {
1002        schedulerNearbyAvailabilityExhausted = false;
1003    }
1004
1005    var config = getSchedulerConfig();
1006
1007    writeSchedulerConfigToDateControls(config);
1008    refreshSchedulerDateButtons(config);
1009
1010    if (clearSelections) {
1011        clearSchedulerSelections();
1012    }
1013
1014    if (updateSchedulerUnavailableState()) {
1015        return;
1016    }
1017
1018    updateSchedulerTimeAvailability();
1019}
1020
1021function resetCustomDateOption(selectPicker) {
1022    var $group = jQuery('.dayBtn-group').first();
1023    var $pickerLabel = $group.find('.dayBtn-picker').first();
1024    var $radio = $pickerLabel.find('input[type="radio"]');
1025    var $span = $pickerLabel.find('span');
1026    var $dateInput = $group.find('.dayBtn-datepicker').first();
1027
1028    if (typeof selectPicker === 'undefined') {
1029        selectPicker = true;
1030    }
1031
1032    $dateInput.val('');
1033    $radio.val('other').prop('checked', selectPicker);
1034    $span.text('Pick another date');
1035}
1036
1037var schedulerClosedTodayAlertShown = false;
1038
1039function updateSchedulerTimeAvailability() {
1040    var selectedDate = getSelectedSchedulerDate();
1041    var $timeInputs = jQuery('input[name="ctc_scheduler_time"]');
1042
1043    if (isSchedulerCurrentlyUnavailable()) {
1044        schedulerClosedTodayAlertShown = false;
1045        $timeInputs.prop('checked', false).prop('disabled', true).closest('.timeBtn').addClass('disabled');
1046        return;
1047    }
1048
1049    if (!selectedDate) {
1050        schedulerClosedTodayAlertShown = false;
1051        $timeInputs.each(function() {
1052            jQuery(this)
1053                .prop('disabled', false)
1054                .prop('checked', false)
1055                .closest('.timeBtn')
1056                .removeClass('disabled');
1057        });
1058        return;
1059    }
1060
1061    var window = getScheduleWindowForDate(selectedDate);
1062
1063    var today = new Date();
1064    var todayIso =
1065        today.getFullYear() + '-' +
1066        String(today.getMonth() + 1).padStart(2, '0') + '-' +
1067        String(today.getDate()).padStart(2, '0');
1068
1069    var isToday = (selectedDate === todayIso);
1070    var currentMinutes = (today.getHours() * 60) + today.getMinutes();
1071
1072    var openMinutes = null;
1073    var closeMinutes = null;
1074
1075    if (window && window.length === 2) {
1076        openMinutes = parse24HourTimeToMinutes(window[0]);
1077        closeMinutes = parse24HourTimeToMinutes(window[1]);
1078    }
1079
1080    $timeInputs.each(function() {
1081        var $input = jQuery(this);
1082        var timeMinutes = parseSchedulerTimeToMinutes($input.val());
1083        var disableThis = false;
1084
1085        if (openMinutes === null || closeMinutes === null || timeMinutes === null) {
1086            disableThis = true;
1087        } else {
1088            if (timeMinutes < openMinutes || timeMinutes >= closeMinutes) {
1089                disableThis = true;
1090            }
1091
1092            if (isToday && timeMinutes <= currentMinutes) {
1093                disableThis = true;
1094            }
1095        }
1096
1097        $input.prop('disabled', disableThis);
1098        $input.closest('.timeBtn').toggleClass('disabled', disableThis);
1099
1100        if (disableThis && $input.is(':checked')) {
1101            $input.prop('checked', false);
1102        }
1103    });
1104
1105    if (isToday && (openMinutes === null || closeMinutes === null)) {
1106        if (!schedulerClosedTodayAlertShown) {
1107            schedulerClosedTodayAlertShown = true;
1108            alert('This location is closed today.');
1109        }
1110    } else {
1111        schedulerClosedTodayAlertShown = false;
1112    }
1113}
1114
1115jQuery(document).on('click', '.dayBtn-picker', function(e) {
1116    e.preventDefault();
1117
1118    var $pickerBtn = jQuery(this);
1119    var $group = $pickerBtn.closest('.dayBtn-group');
1120    var $radio = $pickerBtn.find('input[type="radio"]');
1121    var $dateInput = $group.find('.dayBtn-datepicker').first();
1122
1123    $radio.prop('checked', true).trigger('change');
1124
1125    if ($dateInput.length) {
1126        if (typeof $dateInput[0].showPicker === 'function') {
1127            $dateInput[0].showPicker();
1128        } else {
1129            $dateInput.trigger('focus').trigger('click');
1130        }
1131    }
1132});
1133
1134jQuery(document).on('change', '.dayBtn-datepicker', function() {
1135    var $dateInput = jQuery(this);
1136    var selectedDate = $dateInput.val();
1137    var infofield = 'ctc_scheduler_dateError';
1138    var schedulerConfig = getSchedulerConfig();
1139    var holidays = schedulerConfig.holidays || [];
1140    var minDate = $dateInput.attr('min') || '';
1141    var maxDate = $dateInput.attr('max') || '';
1142    var $group = $dateInput.closest('.dayBtn-group');
1143    var $pickerLabel = $group.find('.dayBtn-picker').first();
1144    var $radio = $pickerLabel.find('input[type="radio"]');
1145    var $span = $pickerLabel.find('span');
1146
1147    if (!selectedDate) {
1148        return;
1149    }
1150
1151    var isoRegex = /^\d{4}-\d{2}-\d{2}$/;
1152
1153    if (!isoRegex.test(selectedDate)) {
1154        msg(infofield, "errorNode", "Invalid date");
1155        jQuery('#' + infofield).show();
1156        redLight($dateInput);
1157        resetCustomDateOption();
1158        updateSchedulerTimeAvailability();
1159        return;
1160    }
1161
1162    if (minDate && selectedDate < minDate) {
1163        msg(infofield, "errorNode", "Invalid date");
1164        jQuery('#' + infofield).show();
1165        redLight($dateInput);
1166        resetCustomDateOption();
1167        updateSchedulerTimeAvailability();
1168        return;
1169    }
1170
1171    if (maxDate && selectedDate > maxDate) {
1172        msg(infofield, "errorNode", "Invalid date");
1173        jQuery('#' + infofield).show();
1174        redLight($dateInput);
1175        resetCustomDateOption();
1176        updateSchedulerTimeAvailability();
1177        return;
1178    }
1179
1180    var parts = selectedDate.split('-');
1181    var year = parseInt(parts[0], 10);
1182    var month = parseInt(parts[1], 10);
1183    var day = parseInt(parts[2], 10);
1184
1185    var d = new Date(year, month - 1, day);
1186
1187    if (
1188        d.getFullYear() !== year ||
1189        d.getMonth() !== (month - 1) ||
1190        d.getDate() !== day
1191    ) {
1192        msg(infofield, "errorNode", "Invalid date");
1193        jQuery('#' + infofield).show();
1194        redLight($dateInput);
1195        resetCustomDateOption();
1196        updateSchedulerTimeAvailability();
1197        return;
1198    }
1199
1200    var isHoliday = holidays.indexOf(selectedDate) !== -1;
1201
1202    if (isHoliday) {
1203        msg(infofield, "errorNode", "Selected date is unavailable");
1204        jQuery('#' + infofield).show();
1205        redLight($dateInput);
1206        resetCustomDateOption();
1207        updateSchedulerTimeAvailability();
1208        return;
1209    }
1210
1211    var window = getScheduleWindowForDate(selectedDate);
1212    if (!window) {
1213        msg(infofield, "errorNode", "Selected date is unavailable");
1214        jQuery('#' + infofield).show();
1215        redLight($dateInput);
1216        resetCustomDateOption();
1217        updateSchedulerTimeAvailability();
1218        return;
1219    }
1220
1221    var displayDate = d.toLocaleDateString('en-US', {
1222        weekday: 'short',
1223        month: 'short',
1224        day: 'numeric'
1225    });
1226
1227    $radio.val(selectedDate).prop('checked', true).trigger('change');
1228    $span.text(displayDate);
1229
1230    msg(infofield, "errorNode", "");
1231    jQuery('#' + infofield).hide();
1232    greenLight($dateInput);
1233
1234    updateSchedulerTimeAvailability();
1235});
1236
1237function validateYesNo(valfield, infofield, required)
1238{
1239    var radioName = '';
1240
1241    if (valfield && typeof valfield.length !== 'undefined' && valfield.length > 0 && valfield[0] && valfield[0].name) {
1242        radioName = valfield[0].name;
1243    } else if (valfield && valfield.name) {
1244        radioName = valfield.name;
1245    }
1246
1247    if (!radioName) {
1248        msg(infofield, "errorNode", "Invalid selection");
1249        jQuery('#' + infofield).show();
1250        return false;
1251    }
1252
1253    var $selected = jQuery('input[name="' + radioName + '"]:checked');
1254    var $all = jQuery('input[name="' + radioName + '"]');
1255
1256    if (!$selected.length) {
1257        if (required) {
1258            msg(infofield, "errorNode", "Required");
1259            jQuery('#' + infofield).show();
1260            redLight($all);
1261            return false;
1262        }
1263
1264        msg(infofield, "errorNode", "");
1265        jQuery('#' + infofield).hide();
1266        return true;
1267    }
1268
1269    var value = String($selected.val()).toLowerCase();
1270
1271    if (value !== 'yes' && value !== 'no') {
1272        msg(infofield, "errorNode", "Invalid selection");
1273        jQuery('#' + infofield).show();
1274        redLight($all);
1275        return false;
1276    }
1277
1278    msg(infofield, "errorNode", "");
1279    jQuery('#' + infofield).hide();
1280    greenLight($selected);
1281    return true;
1282}
1283
1284function isUsingInsuranceYes()
1285{
1286    return jQuery('input[name="using_insurance"]:checked').val() === 'yes';
1287}
1288
1289function getInsuranceEligibilityOption()
1290{
1291    return jQuery('input[name="insurance_eligibility_option"]:checked').val() || '';
1292}
1293
1294function isInsuranceSSNRequired()
1295{
1296    return isUsingInsuranceYes() && getInsuranceEligibilityOption() === 'ssn';
1297}
1298
1299function isInsuranceDetailsRequired()
1300{
1301    return isUsingInsuranceYes() && getInsuranceEligibilityOption() === 'insurance_details';
1302}
1303
1304function clearInsuranceEligibilityErrors()
1305{
1306    ['insurance_eligibility_optionError', 'insurance_ssnError', 'insurance_provider_nameError', 'insurance_member_idError'].forEach(function(errorId) {
1307        if (document.getElementById(errorId)) {
1308            msg(errorId, 'errorNode', '');
1309            jQuery('#' + errorId).hide();
1310        }
1311    });
1312    greenLight(jQuery('input[name="insurance_eligibility_option"]'));
1313    greenLight(jQuery('#insurance_ssn'));
1314    greenLight(jQuery('#insurance_provider_name'));
1315    greenLight(jQuery('#insurance_member_id'));
1316}
1317
1318function resetInsuranceEligibilityFields(clearOption)
1319{
1320    if (clearOption) {
1321        jQuery('input[name="insurance_eligibility_option"]').prop('checked', false);
1322    }
1323    jQuery('#insurance_ssn').val('');
1324    jQuery('#insurance_provider_name').val('');
1325    jQuery('#insurance_member_id').val('');
1326    clearInsuranceEligibilityErrors();
1327}
1328
1329function updateInsuranceEligibilityFields(clearHiddenValues)
1330{
1331    var useInsurance = isUsingInsuranceYes();
1332    var option = getInsuranceEligibilityOption();
1333
1334    jQuery('#insuranceEligibilityRow').toggle(useInsurance);
1335    jQuery('#insuranceEligibilitySSNFields').toggle(useInsurance && option === 'ssn');
1336    jQuery('#insuranceEligibilityDetailFields').toggle(useInsurance && option === 'insurance_details');
1337
1338    jQuery('#insurance_ssn').attr('aria-required', useInsurance && option === 'ssn' ? 'true' : 'false');
1339    jQuery('#insurance_provider_name').attr('aria-required', useInsurance && option === 'insurance_details' ? 'true' : 'false');
1340    jQuery('#insurance_member_id').attr('aria-required', useInsurance && option === 'insurance_details' ? 'true' : 'false');
1341
1342    if (!useInsurance) {
1343        resetInsuranceEligibilityFields(true);
1344        return;
1345    }
1346
1347    if (clearHiddenValues) {
1348        if (option !== 'ssn') {
1349            jQuery('#insurance_ssn').val('');
1350            msg('insurance_ssnError', 'errorNode', '');
1351            jQuery('#insurance_ssnError').hide();
1352            greenLight(jQuery('#insurance_ssn'));
1353        }
1354        if (option !== 'insurance_details') {
1355            jQuery('#insurance_provider_name').val('');
1356            jQuery('#insurance_member_id').val('');
1357            msg('insurance_provider_nameError', 'errorNode', '');
1358            msg('insurance_member_idError', 'errorNode', '');
1359            jQuery('#insurance_provider_nameError, #insurance_member_idError').hide();
1360            greenLight(jQuery('#insurance_provider_name'));
1361            greenLight(jQuery('#insurance_member_id'));
1362        }
1363    }
1364}
1365
1366function formatInsuranceSSNValue(value)
1367{
1368    var digits = String(value || '').replace(/[^0-9]/g, '').slice(0, 9);
1369
1370    if (digits.length > 5) {
1371        return digits.slice(0, 3) + '-' + digits.slice(3, 5) + '-' + digits.slice(5);
1372    }
1373
1374    if (digits.length > 3) {
1375        return digits.slice(0, 3) + '-' + digits.slice(3);
1376    }
1377
1378    return digits;
1379}
1380
1381function validateInsuranceEligibilityOption(required)
1382{
1383    if (!required) {
1384        msg('insurance_eligibility_optionError', 'errorNode', '');
1385        jQuery('#insurance_eligibility_optionError').hide();
1386        return true;
1387    }
1388
1389    var option = getInsuranceEligibilityOption();
1390    if (option !== 'ssn' && option !== 'insurance_details' && option !== 'none') {
1391        msg('insurance_eligibility_optionError', 'errorNode', 'Required');
1392        jQuery('#insurance_eligibility_optionError').show();
1393        redLight(jQuery('input[name="insurance_eligibility_option"]'));
1394        return false;
1395    }
1396
1397    msg('insurance_eligibility_optionError', 'errorNode', '');
1398    jQuery('#insurance_eligibility_optionError').hide();
1399    greenLight(jQuery('input[name="insurance_eligibility_option"]'));
1400    return true;
1401}
1402
1403function validateInsuranceSSN(valfield, infofield, required)
1404{
1405    var stat = commonCheck(valfield, infofield, required);
1406    if (stat !== proceed) return stat;
1407
1408    var value = trim(valfield.value);
1409    if (!required && value.length === 0) {
1410        msg(infofield, 'errorNode', '');
1411        jQuery('#' + infofield).hide();
1412        greenLight(valfield);
1413        return true;
1414    }
1415
1416    if (!/^\d{3}-\d{2}-\d{4}$/.test(value)) {
1417        msg(infofield, 'errorNode', 'Invalid SSN');
1418        jQuery('#' + infofield).show();
1419        redLight(valfield);
1420        return false;
1421    }
1422
1423    msg(infofield, 'errorNode', '');
1424    jQuery('#' + infofield).hide();
1425    greenLight(valfield);
1426    return true;
1427}
1428
1429function validateInsuranceProviderName(valfield, infofield, required)
1430{
1431    var stat = commonCheck(valfield, infofield, required);
1432    if (stat !== proceed) return stat;
1433
1434    var value = trim(valfield.value);
1435    if (!required && value.length === 0) {
1436        msg(infofield, 'errorNode', '');
1437        jQuery('#' + infofield).hide();
1438        greenLight(valfield);
1439        return true;
1440    }
1441
1442    if (!/^[A-Za-z0-9 .&'\-]{2,80}$/.test(value)) {
1443        msg(infofield, 'errorNode', 'Invalid provider name');
1444        jQuery('#' + infofield).show();
1445        redLight(valfield);
1446        return false;
1447    }
1448
1449    msg(infofield, 'errorNode', '');
1450    jQuery('#' + infofield).hide();
1451    greenLight(valfield);
1452    return true;
1453}
1454
1455function validateInsuranceMemberId(valfield, infofield, required)
1456{
1457    var stat = commonCheck(valfield, infofield, required);
1458    if (stat !== proceed) return stat;
1459
1460    var value = trim(valfield.value);
1461    if (!required && value.length === 0) {
1462        msg(infofield, 'errorNode', '');
1463        jQuery('#' + infofield).hide();
1464        greenLight(valfield);
1465        return true;
1466    }
1467
1468    if (!/^[A-Za-z0-9 \-_]{2,40}$/.test(value)) {
1469        msg(infofield, 'errorNode', 'Invalid member ID');
1470        jQuery('#' + infofield).show();
1471        redLight(valfield);
1472        return false;
1473    }
1474
1475    msg(infofield, 'errorNode', '');
1476    jQuery('#' + infofield).hide();
1477    greenLight(valfield);
1478    return true;
1479}
1480
1481
1482function validateProfessionalText(valfield, infofield, required)
1483{
1484    var stat = commonCheck(valfield, infofield, required);
1485    if (stat !== proceed) return stat;
1486
1487    var value = trim(valfield.value);
1488    if (!required && value.length === 0) {
1489        msg(infofield, 'errorNode', '');
1490        jQuery('#' + infofield).hide();
1491        greenLight(valfield);
1492        return true;
1493    }
1494
1495    if (!/^[A-Za-z0-9 .,&'()\-\/]{2,100}$/.test(value)) {
1496        msg(infofield, 'errorNode', 'Invalid company name');
1497        jQuery('#' + infofield).show();
1498        redLight(valfield);
1499        return false;
1500    }
1501
1502    msg(infofield, 'errorNode', '');
1503    jQuery('#' + infofield).hide();
1504    greenLight(valfield);
1505    return true;
1506}
1507
1508function validateInsuranceEligibilityFields()
1509{
1510    if (!jQuery('#insuranceEligibilityRow').length) {
1511        return true;
1512    }
1513
1514    updateInsuranceEligibilityFields(false);
1515
1516    if (!isUsingInsuranceYes()) {
1517        clearInsuranceEligibilityErrors();
1518        return true;
1519    }
1520
1521    var errs = 0;
1522    if (!validateInsuranceEligibilityOption(true)) errs++;
1523
1524    if (isInsuranceSSNRequired()) {
1525        if (!validateInsuranceSSN(document.getElementById('insurance_ssn'), 'insurance_ssnError', true)) errs++;
1526    } else if (isInsuranceDetailsRequired()) {
1527        if (!validateInsuranceProviderName(document.getElementById('insurance_provider_name'), 'insurance_provider_nameError', true)) errs++;
1528        if (!validateInsuranceMemberId(document.getElementById('insurance_member_id'), 'insurance_member_idError', true)) errs++;
1529    }
1530
1531    return errs === 0;
1532}
1533
1534jQuery(document).on('change', 'input[name="using_insurance"]', function() {
1535    updateInsuranceEligibilityFields(true);
1536});
1537
1538jQuery(document).on('change', 'input[name="insurance_eligibility_option"]', function() {
1539    updateInsuranceEligibilityFields(true);
1540    validateInsuranceEligibilityOption(isUsingInsuranceYes());
1541});
1542
1543jQuery(document).on('input', '#insurance_ssn', function() {
1544    this.value = formatInsuranceSSNValue(this.value);
1545});
1546
1547jQuery(document).on('input', '#insurance_provider_name', function() {
1548    this.value = this.value.replace(/[^A-Za-z0-9 .&'\-]/g, '').slice(0, 80);
1549});
1550
1551jQuery(document).on('input', '#insurance_member_id', function() {
1552    this.value = this.value.replace(/[^A-Za-z0-9 \-_]/g, '').slice(0, 40);
1553});
1554
1555jQuery(function() {
1556    updateInsuranceEligibilityFields(false);
1557});
1558
1559jQuery(document).on('change', 'input[name="ctc_scheduler_date"]', function() {
1560    updateSchedulerTimeAvailability();
1561});
1562
1563jQuery(document).on('change', 'select[name="facilityChoice"]', function() {
1564    refreshSchedulerForSelectedFacility(true, false);
1565});
1566
1567jQuery(function() {
1568    initializeSchedulerWrapperState();
1569    refreshSchedulerForSelectedFacility(true, true);
1570});
1571
1572// *** --------------------------------------------
1573//             validateSelect
1574// Validate the input tag for Relationship
1575// Returns true if OK
1576// --------------------------------------------
1577
1578function validateSelect(valfield,   // element to be validated
1579                        infofield,  // id of element to receive info/error msg
1580                        required  )
1581{
1582    var stat = commonCheck (valfield, infofield, required);
1583    if (stat !== proceed) return stat;
1584
1585    var selection = valfield.value;
1586    if(selection === '0' && required) {
1587        msg(infofield,"errorNode", "Required");
1588        jQuery('#' + infofield).show();
1589        // setfocus(valfield);
1590        redLight(valfield);
1591        return false;
1592    } else {
1593        msg (infofield, "errorNode", "");
1594        jQuery('#' + infofield).hide();
1595        greenLight(valfield);
1596        return true;
1597    }
1598    msg (infofield, "errorNode", "");
1599    jQuery('#' + infofield).hide();
1600    greenLight(valfield);
1601    return true;
1602}
1603
1604// *** --------------------------------------------
1605//             validateTimeToCall
1606// Validate the input tag for TimeToCall
1607// Returns true if OK
1608// --------------------------------------------
1609
1610function validateTimeToCall(valfield,   // element to be validated
1611                            infofield,  // id of element to receive info/error msg
1612                            required  )
1613{
1614    var stat = commonCheck (valfield, infofield, required);
1615    if (stat !== proceed) return stat;
1616
1617    var selection = valfield.value;
1618    if(selection === '0' && required === true) {
1619        msg(infofield,"errorNode", "Required");
1620        jQuery('#' + infofield).show();
1621        redLight(valfield);
1622        return false;
1623    } else {
1624        msg (infofield, "errorNode", "");
1625        jQuery('#' + infofield).hide();
1626        greenLight(valfield);
1627        return true;
1628    }
1629}
1630
1631function validateDOB(valfield, infofield, required)
1632{
1633    var stat = commonCheck(valfield, infofield, required);
1634    if (stat !== proceed) return stat;
1635
1636    var value = trim(valfield.value);
1637    var dobRegex = /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/;
1638
1639    if (!dobRegex.test(value)) {
1640        msg(infofield, "errorNode", "Invalid date");
1641        jQuery('#' + infofield).show();
1642        redLight(valfield);
1643        return false;
1644    }
1645
1646    var parts = value.split('/');
1647    var month = parseInt(parts[0], 10);
1648    var day = parseInt(parts[1], 10);
1649    var year = parseInt(parts[2], 10);
1650
1651    var d = new Date(year, month - 1, day);
1652
1653    if (
1654        d.getFullYear() !== year ||
1655        d.getMonth() !== (month - 1) ||
1656        d.getDate() !== day
1657    ) {
1658        msg(infofield, "errorNode", "Invalid date");
1659        jQuery('#' + infofield).show();
1660        redLight(valfield);
1661        return false;
1662    }
1663
1664    msg(infofield, "errorNode", "");
1665    jQuery('#' + infofield).hide();
1666    greenLight(valfield);
1667    return true;
1668}
1669
1670jQuery(document).on('input', '#dob', function () {
1671    var value = this.value.replace(/[^\d]/g, '').slice(0, 8);
1672
1673    if (value.length >= 5) {
1674        value = value.slice(0, 2) + '/' + value.slice(2, 4) + '/' + value.slice(4);
1675    } else if (value.length >= 3) {
1676        value = value.slice(0, 2) + '/' + value.slice(2);
1677    }
1678
1679    this.value = value;
1680});
1681
1682function validateComments(valfield, infofield, required)
1683{
1684    var stat = commonCheck (valfield, infofield, required);
1685    if (stat !== proceed) return stat;
1686    msg (infofield, "errorNode", "");
1687    jQuery('#' + infofield).hide();
1688    greenLight(valfield);
1689    return true;
1690}
1691
1692function validateOnSubmit() {
1693    let errs = 0;
1694    var sfwfaRequired = getSFWFAValidation();
1695
1696    if (sfwfaRequired.length === 0) {
1697        console.log("Val array is empty.");
1698        return;
1699    }
1700
1701    for (let i = 0; i < sfwfaRequired.length; i++) {
1702        const valField = sfwfaRequired[i];
1703        const functionName = valField[1];
1704
1705        if (typeof window[functionName] === 'function') {
1706            const field = document.forms['SFWFA_main_form'][valField[0]];
1707            const errorField = valField[2];
1708            const req = valField[3];
1709
1710            if (!window[functionName](field, errorField, req)) errs += 1;
1711        } else {
1712            console.log("No formval function " + functionName);
1713        }
1714    }
1715
1716    if (typeof validateInsuranceEligibilityFields === 'function' && !validateInsuranceEligibilityFields()) {
1717        errs += 1;
1718    }
1719
1720    if (errs >= 1) {
1721        alert('There are fields which need correction before sending');
1722        jQuery('html, body').animate({scrollTop: (jQuery('#SFWFA_main_form').offset().top - 300)}, 1000);
1723    }
1724
1725    if (errs > 0) {
1726        return false;
1727    } else {
1728        return true;
1729    }
1730}
1731
1732function show(id) {
1733    if (document.getElementById(id).style.display == 'none') {
1734        document.getElementById(id).style.display = '';
1735    }
1736}
1737
1738function hide(id) {
1739    document.getElementById(id).style.display = 'none';
1740}
1741
1742document.onload = function() {
1743    document.getElementById('inquiringAbout').onchange();
1744}

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.