PageSourceSearch

https://www.avrrdd.org/Assets/Scripts/DateTimePicker/cp.datetimepicker.js

js avrrdd.org collected 2026-10-06 12:30:46 UTC 30,438 bytes, 665 lines download raw bytes

1/**
2    cp.datepicker.js provides an JavaScript Date picker control.
3 */
4var cp = cp || {};
5
6cp.datetimepicker = (function ($) {
7    var keyCodes = {
8        tab: 9,
9        downArrow: 40
10    };
11
12    // These are the publicly-accessible methods
13    if (!$) { return; }
14    return {
15        createTimePicker: createTimePicker,
16        createDatePicker: createDatePicker,
17    };
18
19
20    // getOptionsFromHtmlAttributes parses through any attribute in the user-specific HTML date or time picker and
21    // overwrites the values in "options" with values corresponding to "data-cp-datetimepicker-{optionName}".  The
22    // "optionName" portion of the attribute should correspond to a property of the pickadate or pickatime
23    // options element.
24    function getOptionsFromHtmlAttributes($inputElement, originalOptions) {
25        $($inputElement[0].attributes).each(function () {
26            if (this.name.match('^data-cp-datetimepicker-')) {
27                var optionName = this.name.replace('data-cp-datetimepicker-', '');
28                var originalValue = originalOptions[optionName];
29                if (!originalValue) {
30                    // We only want to set the option value if it was not already set in the JavaScript options.
31                    // That is, the JavaScript options should always win over the HTML5 options.
32
33                    var optionVal = this.value;
34                    if (parseInt(optionVal)) {
35                        optionVal = parseInt(optionVal);
36                    }
37
38                    originalOptions[optionName] = optionVal;
39                }
40            }
41        });
42        return originalOptions;
43    }
44
45    // createTimePicker creates a new time picker object out of the DOM object specified by timeTextboxSelector.
46    // The timeTextboxSelector object must be an HTML INPUT element.
47    function createTimePicker(timeTextboxSelector, options) {
48
49        // The actualy Input Time component will be a hidden field.  The DOM object in the source HTML
50        // will be the editable text field for the user.
51
52        options = options || {};
53
54        var $inputTextBox = $(timeTextboxSelector);
55
56        if (!($inputTextBox) || $inputTextBox.length === 0) {
57            // We got passed a bad selector
58            console.log('ERR: cp.datetimepicker :: Could not find element: ' + timeTextboxSelector);
59            return;
60        }
61
62        // Set any options that were specified directly from within the HTML tag.
63        options = getOptionsFromHtmlAttributes($inputTextBox, options);
64
65        //Wrap fieldSetSelector inside div if wrapInsideDiv is true
66        var fieldSetSelector = '<div class="fieldset__datetimepicker__wrapper">';
67
68        if (options.wrapInsideDiv) {
69            fieldSetSelector = '<div class="t-widget t-timepicker">' + fieldSetSelector + '</div>';
70        }
71
72        $fieldset = $(fieldSetSelector);
73        $inputTextBox.wrap($fieldset);
74
75        var $hiddenTimeInput = $('<input type="text" class="cp_input_datetime" tabindex="-1"/>');
76        $hiddenTimeInput.attr('data-cp-time-textbox-selector', timeTextboxSelector);
77
78        $hiddenTimeInput.attr('aria-hidden', true);
79
80        $hiddenTimeInput.insertAfter($inputTextBox);
81
82        // We need to force "editable" in the options, otherwise things start to break.
83        options.editable = true;
84        $hiddenTimeInput.pickatime(options);
85
86        var pickerObject = $hiddenTimeInput.pickatime('picker');	// reference to the pickatime object
87        $inputTextBox.attr("role", "combobox");
88        $inputTextBox.attr("aria-haspopup", "listbox");
89        $inputTextBox.attr("aria-expanded", "false");
90        $inputTextBox.attr("aria-controls", pickerObject.$root.attr("id"));
91
92        // Bugfix - https://civicplus.tpondemand.com/entity/182182-211-agenda-center-module-main-page
93        // Move aria-owns from the hidden <input> to the interactive one
94        $inputTextBox.attr("aria-owns", pickerObject.$node.attr("aria-owns"));
95        pickerObject.$node.removeAttr("aria-owns");
96
97        $inputTextBox.on({
98            change: function () {
99                var inputTime = this.value;
100                pickerObject.set('customSelect', insertColonIfOverFourChars(inputTime), options);
101            },
102            keydown: function (e) {
103                if (e.keyCode === keyCodes.downArrow) {
104                    e.preventDefault();
105                    pickerObject.open(true);
106                }
107            },
108            focus: function (e) {
109                if (e.relatedTarget !== pickerObject.$holder[0]) {
110                    // If the previously focused control was the picker object, don't open it again after closing it
111                    pickerObject.open(false);
112                }
113                // We have to set the tab-index of the "clear" button, so tabbing through fields works properly.
114                $('.picker__button--clear').attr('tabindex', -1);
115            },
116            blur: function (e) {
117                // If user shifts focus from the input element to its datepicker, then we do not want to close the datepicker.
118                if (!e.relatedTarget?.closest(".picker")) {
119                    pickerObject.close(true);
120                }
121            }
122        });
123
124        pickerObject.on({
125            open: function () {
126                $inputTextBox.attr("aria-expanded", "true");
127            },
128            close: function () {
129                $inputTextBox.attr("aria-expanded", "false");
130                $inputTextBox.focus();
131            },
132            set: function (e) {
133                var inputVal = $inputTextBox.val();
134                var selectedVal = autoTimeFormat(inputVal);
135                if (typeof e.clear === "object" || (typeof e.select !== "undefined" && (!isNaN(e.select) || !isNaN(e.select.pick))) || (e.customSelect && !selectedVal.match(/^([1-9]|1[012])(:[0-5]\d) [APap][mM]$/))) {
136                    selectedVal = this.get('value') === '' ? '12:00 AM' : this.get('value');
137                }
138                $inputTextBox.val(selectedVal);
139                $inputTextBox.attr('value', selectedVal);
140                // closing the selection area if the user had picked a time.
141                if (!e.relatedTarget?.closest(".picker")) {
142                    pickerObject.close(true);
143                    $inputTextBox.attr("aria-expanded", "false");
144                }
145            }
146        });
147
148        // Priming initialization if there was a value specified for the input
149        if ($inputTextBox.val() !== '') {
150            pickerObject.set('select', $inputTextBox.val(), options);
151        }
152
153        $(pickerObject.$root).find('.picker__list').attr('aria-label', 'Time List');
154
155        return pickerObject;
156    }
157
158    // createDatePicker creates a new date picker object using the element specified by "dateTextboxSelector".
159    // The dateTextboxSelector object must be an HTML INPUT element.
160    function createDatePicker(dateTextboxSelector, options) {
161        // The actualy Input Date component will be a hidden field.  The DOM object in the source HTML
162        // will be the editable text field for the user.
163        options = options || {};
164
165        var $inputTextBox = $(dateTextboxSelector);
166
167        if (!($inputTextBox) || $inputTextBox.length === 0) {
168            // We got passed a bad selector
169            console.log('ERR: cp.datetimepicker :: Could not find element: ' + dateTextboxSelector);
170            return;
171        }
172
173        // Set any options that were specified directly from within the HTML tag.
174        options = getOptionsFromHtmlAttributes($inputTextBox, options);
175        var dateAsString = $inputTextBox.val();
176        if (options.format == 'dd/mm/yyyy' && dateAsString.length > 0) {
177            var splitDate = autoCompleteDate(dateAsString, options.format).split('/');
178            $inputTextBox.val(splitDate[1] + '/' + splitDate[0] + '/' + splitDate[2]);
179        }
180
181        if (options.useNativeControls) {
182            $inputTextBox.prop('type', 'date');
183            return;
184        }
185
186        var $hiddenDateInput = $('<input type="text" class="cp_input_datetime" tabindex="-1"/>');
187        $hiddenDateInput.attr('data-cp-date-textbox-selector', dateTextboxSelector);
188
189        $hiddenDateInput.attr('aria-hidden', true);
190        var fieldsetSelector = '<div class="fieldset__datetimepicker__wrapper"></div>';
191        if (options.wrapInsideDiv)
192            fieldsetSelector = '<div class="t-widget t-datepicker">' + fieldsetSelector + '</div>';
193
194        $fieldset = $(fieldsetSelector);
195        $fieldset.attr("data-cp-datetimepicker-selector", dateTextboxSelector);
196        $inputTextBox.wrap($fieldset);
197        $hiddenDateInput.insertAfter($inputTextBox);
198
199        // We have to force the editable option, otherwise things start to break.
200        options.editable = true;
201
202        $hiddenDateInput.pickadate(options);
203
204        var pickerObject = $hiddenDateInput.pickadate('picker');	// reference to the pickadate object
205        $inputTextBox.attr("role", "combobox");
206        $inputTextBox.attr("aria-haspopup", "dialog");
207        $inputTextBox.attr("aria-expanded", "false");
208        $inputTextBox.attr("aria-controls", pickerObject.$root.attr("id"));
209
210        // Bugfix - https://civicplus.tpondemand.com/entity/182182-2
21011-agenda-center-module-main-page
211        // Move aria-owns from the hidden <input> to the interactive one
212        $inputTextBox.attr("aria-owns", pickerObject.$node.attr("aria-owns"));
213        pickerObject.$node.removeAttr("aria-owns");
214
215        var allowDatePickerFocus = false;
216        var isTabbingAwayFromDatePicker = false;
217
218        // Keep only the visible picker action controls in the keyboard path; date cells are tracked through aria-activedescendant.
219        function getPickerControls($holder) {
220            return $holder.find('.picker__nav--prev, .picker__nav--next, .picker__button--today, .picker__button--clear, .picker__button--close').filter(function () {
221                return !$(this).hasClass('picker__nav--disabled') && $(this).attr('aria-hidden') !== 'true';
222            });
223        }
224
225        function enablePickerControlTabbing() {
226            getPickerControls(pickerObject.$holder).attr('tabindex', '0');
227        }
228
229        function restorePickerControlFocus(selector) {
230            setTimeout(function () {
231                updateActiveDescendant();
232                enablePickerControlTabbing();
233                pickerObject.$holder.find(selector).first().focus();
234            }, 0);
235        }
236
237        function getNextTabbableElement() {
238            const $focusableElements = $('a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], [contenteditable=true]').filter(function () {
239                const $element = $(this);
240                const tabindex = $element.attr('tabindex');
241
242                return $element.is(':visible') && tabindex !== '-1' && $element.attr('aria-hidden') !== 'true' && this !== pickerObject.$holder[0] && !$.contains(pickerObject.$holder[0], this);
243            });
244
245            const currentInputIndex = $focusableElements.index($inputTextBox);
246            if (currentInputIndex !== -1 && currentInputIndex < $focusableElements.length - 1) {
247                return $focusableElements.eq(currentInputIndex + 1);
248            }
249
250            return $();
251        }
252
253        // Add handler to make sure datepicker is visible when shown
254        pickerObject && pickerObject.on('open', function () {
255            $inputTextBox.attr("aria-expanded", "true");
256            $inputTextBox.attr('aria-live', 'off');
257            $inputTextBox.attr('aria-atomic', 'false');
258            const selected = pickerObject.get('select');
259            if (!selected) {
260                pickerObject.set('highlight', new Date(), { muted: true });
261            }
262
263            const $holder = pickerObject.$holder;
264            const inputId = $inputTextBox.attr('id');
265
266            const inputLabel = ($('label[for="' + inputId + '"]').text() || '').trim();
267
268            const labelText = inputLabel || $inputTextBox.attr('aria-label') || $inputTextBox.attr('title') || 'Date picker calendar';
269
270            //Use the application role so screen readers pass arrow keys to the custom keyboard interaction.
271            $holder.attr({
272                'tabindex': allowDatePickerFocus ? '0' : '-1',
273                'role': 'application',
274                'aria-label': labelText
275            });
276
277            $holder.find('.picker__nav--prev, .picker__nav--next, .picker__button--today, .picker__button--clear, .picker__button--close').attr('tabindex', '-1');
278
279            //Only ONE focusable element
280            $holder.find('.picker__day').attr('tabindex', '-1');
281            $holder.find('.picker__day').attr('aria-hidden', 'true');
282
283            //Set aria-selected
284            $holder.find('.picker__day').each(function () {
285                const $day = $(this);
286                $day.attr('aria-selected', $day.hasClass('picker__day--selected') ? 'true' : 'false');
287            });
288
289            //Set active descendant
290            setTimeout(updateActiveDescendant, 0);
291
292            $holder.off('keydown.grid').on('keydown.grid', function (e) {
293                if (e.keyCode === keyCodes.tab) {
294                    const $controls = getPickerControls($holder);
295                    const currentIndex = $controls.index(e.target);
296
297                    if (currentIndex !== -1) {
298                        if (e.shiftKey && currentIndex === 0) {
299                            e.preventDefault();
300                            $holder.focus();
301                            return;
302                        }
303
304                        if (!e.shiftKey && currentIndex < $controls.length - 1) {
305                            e.preventDefault();
306                            $controls.eq(currentIndex + 1).focus();
307                        }
308
309                        if (!e.shiftKey && currentIndex === $controls.length - 1) {
310                            e.preventDefault();
311                            // Capture the next real page control before closing because picker DOM removal can disrupt native Tab focus.
312                            const $nextTabbableElement = getNextTabbableElement();
313                            isTabbingAwayFromDatePicker = true;
314                            allowDatePickerFocus = false;
315                            setTimeout(function () {
316                                pickerObject.close(true);
317                                setTimeout(function () {
318                                    $nextTabbableElement.focus();
319                                }, 0);
320                            }, 0);
321                        }
322
323                        return;
324                    }
325
326                    if ($holder.is(e.target) || $holder.has(e.target).length) {
327                        e.preventDefault();
328                        enablePickerControlTabbing();
329                        (e.shiftKey ? $controls.last() : $controls.first()).focus();
330                    }
331
332                    return;
333                }
334
335                if ($holder.is(e.target) && e.keyCode === 32) {
336                    e.preventDefault();
337                    $holder.find('.picker__day--highlighted:not(.picker__day--disabled)').click();
338                    return;
339                }
340
341                const $target = $(e.target);
342                if ($target.is('.picker__nav--prev, .picker__nav--next') && (e.keyCode === keyCodes.downArrow || e.
342which === keyCodes.downArrow || e.key === 'ArrowDown' || e.key === 'Down')) {
343                    e.preventDefault();
344                    $holder.focus();
345                    return;
346                }
347
348                if ($target.is('.picker__nav--prev, .picker__nav--next') && e.keyCode === 32) {
349                    e.preventDefault();
350                    $target.click();
351                }
352
353                setTimeout(() => {
354                    updateActiveDescendant();
355
356                    $holder.find('.picker__day').attr('aria-selected', 'false');
357
358                    const $selected = $holder.find('.picker__day--selected');
359                    if ($selected.length) {
360                        $selected.attr('aria-selected', 'true');
361                    }
362                }, 0);
363            });
364
365            $holder.off('click.grid', '.picker__nav--prev, .picker__nav--next').on('click.grid', '.picker__nav--prev, .picker__nav--next', function () {
366                const $target = $(this);
367                if (!$target.hasClass('picker__nav--disabled')) {
368                    restorePickerControlFocus($target.hasClass('picker__nav--prev') ? '.picker__nav--prev' : '.picker__nav--next');
369                }
370            });
371
372            // Add a slight delay to ensure that the flyout has been added to the dom and the flyoutHeight is nonzero
373            setTimeout(function () {
374                // Get the position of the datepicker flyout relative to the top of the document
375                var flyoutTop = pickerObject.$holder[0].getBoundingClientRect().top;
376
377                // Get the height of the datepicker flyout
378                var flyoutHeight = pickerObject.$holder[0].offsetHeight;
379
380                // Get the height of the viewport
381                var viewportHeight = window.innerHeight;
382
383                // Calculate the amount of scrolling needed to make the entire datepicker flyout visible
384                var scrollAmount = flyoutTop + flyoutHeight - viewportHeight;
385
386                // If the datepicker flyout is not fully visible, scroll the viewport down to make it visible
387                if (scrollAmount > 0) {
388                    window.scrollTo(0, scrollAmount + window.scrollY);
389                }
390            }, 50);
391        });
392
393        function focusInput() {
394            $inputTextBox.off("focus", openPicker);
395            $inputTextBox.focus();
396            setTimeout(function () {
397                $inputTextBox.on("focus", openPicker);
398            }, 0);
399        }
400
401        pickerObject.on('close', function () {
402            //Trigger the change event on the picker object's element.
403            window.parent.$(dateTextboxSelector).change();
404            $inputTextBox.attr("aria-expanded", "false");
405            pickerObject.$holder.attr('tabindex', '-1');
406            pickerObject.$holder.find('.picker__nav--prev, .picker__nav--next, .picker__button--today, .picker__button--clear, .picker__button--close').attr('tabindex', '-1');
407            if (!isTabbingAwayFromDatePicker) {
408                focusInput();
409            }
410            isTabbingAwayFromDatePicker = false;
411            allowDatePickerFocus = false;
412        });
413
414        // setDate is a helper function that should only be called from within this module.
415        function setDate(dateAsString, placeholder) {
416            if (dateAsString === '') {
417                pickerObject.set('clear', null, null);
418            } else {
419                if (pickerObject.component.settings.format == 'dd/mm/yyyy') {
420                    var splitDate = autoCompleteDate(dateAsString, pickerObject.component.settings.format).split('/');
421                    var date = splitDate[1] + '/' + splitDate[0] + '/' + splitDate[2];
422                    var epochDate = Date.parse(date);
423                } else {
424                    var epochDate = Date.parse(autoCompleteDate(dateAsString, pickerObject.component.settings.format));
425                }
426                if (!epochDate) {
427                    return;
428                } else {
429                    var parsedDate = new Date(epochDate);
430                    pickerObject.set('select',
431                        [parsedDate.getFullYear(), parsedDate.getMonth(), parsedDate.getDate()]);
432                }
433            }
434        }
435
436        function updateActiveDescendant() {
437            const $holder = pickerObject.$holder;
438            const $active = $holder.find('.picker__day--highlighted');
439            $holder.find('.picker__day').attr('aria-hidden', 'true');
440
441            if ($active.length) {
442                $active.attr('aria-hidden', 'false');
443                $holder.attr('aria-activedescendant', $active.attr('id'));
444
445                const dateValue = $active.data('pick');
446                if (dateValue) {
447                    const date = new Date(dateValue);
448
449                    const formatted = date.toLocaleDateString('en-US', {
450                        month: 'long',
451                        day: 'numeric',
452                        year: 'numeric'
453                    });
454
455                    // override for active cell
456                    $active.attr('aria-label', formatted);
457                }
458            }
459        }
460
461        var intervalID;
462
463        //Moves the date picker further up the DOM so it isn't overlapped https://civicplus.tpondemand.com/entity/22312
464        function adjustDTPicker() {
465            if (intervalID === 0) {
466                return;
467            }
468
469            var elemPicker = $('.picker--opened')[0];
470            if (elemPicker) {
471                $(elemPicker).appendTo('#cpDatePickerWrapper');
472                elemPicker.style.fontSize = 'inherit';
473            }
474
475            clearInterval(intervalID);
476
477            $('.cpDatePickerElevate').each(function () {
478                var $dateInput = $(this);
479                if ($dateInput.is(':focus')) {
480                    adjustFlyoutPosition($dateInput, $('#cpDatePickerWrapper'));
481                }
482            });
483
484            intervalID = 0;
485        }
486
487        if ($('#cpDatePickerWrapper').length > 0) {
488            $(window).resize(function () {
489                $('.cpDatePickerElevate').each(function () {
490                    var $dateInput = $(this);
491                    if ($dateInput.is(':focus')) {
492                        adjustFlyoutPosition($dateInput, $('#cpDatePickerWrapper'));
493                    }
494                });
495            });
496        }
497
498        function openPicker() {
499            allowDatePickerFocus = false;
500            // We have to set the tab-index of the "today", "close", and "clear" buttons, so tabbing through fields works properly.
501            $('.picker__button--close').attr('tabindex', -1);
502            $('.picker__button--today').attr('tabindex', -1);
503            $('.picker__button--clear').attr('tabindex', -1);
504            // pickerObject.$holder.find('[tabindex="-1"]').attr('tabindex', 0);
505            pickerObject.open(false);
506            if ($('#cpDatePickerWrapper').length > 0)
507                intervalID = setInterval(adjustDTPicker, 50);
508        }
509
510        $inputTextBox.on({
511            change: function () {
512                setDate(this.value);
513            },
514            focus: openPicker,
515            click: openPicker,
516            keydown: function (e) {
517                if (e.keyCode === keyCodes.tab) {
518                    isTabbingAwayFromDatePicker = true;
519                    pickerObject.$holder.attr('tabindex', -1);
520                    pickerObject.$holder.find('[tabindex="0"]').attr('tabindex', -1);
521                    pickerObject.close();
522                    isTabbingAwayFromDatePicker = false;
523                }
524                if (e.keyCode === keyCodes.downArrow) {
525                    e.preventDefault();
526                    allowDatePickerFocus = true;
527                    pickerObject.open();
528                    setTimeout(function () {
529                        enablePickerControlTabbing();
530                        pickerObject.$holder.attr('tabindex', '0').focus();
531                    }, 0);
532                }
533            },
534            blur: function (e) {
535                // If user shifts focus from the input element to its datepicker, then we do not want to close the datepicker.
536                if (!allowDatePickerFocus || !e.relatedTarget?.closest(".picker")) {
537                    pickerObject.close(true);
538                    $inputTextBox.attr("aria-expanded", "false");
539                }
540            },
541        });
542
543        pickerObject.on('set', function () {
544            $inputTextBox.val(this.get('value'));
545            $inputTextBox.attr('value', this.get('value'));
546
547            setTimeout(updateActiveDescendant, 0);
548        });
549
550        // Priming initialization if there was a value specified for the input
551        if ($inputTextBox.val() !== '') {
552            setDate($inputTextBox.val());
553        }
554
555
556        return pickerObject;
557    }
558
559    function insertColonIfOverFourChars(inputString) {
560        if (inputString != null && inputString.length > 3 && inputString.indexOf(":") < 0) {
561            inputString = inputString.slice(0, 2) + ":" + inputString.slice(2, inputString.length);
562        }
563        return inputString;
564    }
565
566    function autoCompleteDate(dateAsString, formatString) {
567        try {
568            var fdts = null;
569            var currentDate = new Date();
570
571            //guard clauses
572            if (formatString == null || formatString.length === 0) {
573                formatString === "mm/dd/yyyy";
574            }
575            if ((dateAsString == null || dateAsString.length == 0 || dateAsString.indexOf(".") != -1) && formatString.toLowerCase == "dd/mm/yyyy") {
576                return ('0' + currentDate.getDate()).slice(-2) + '/' + ('0' + (currentDate.getMonth() + 1)).slice(-2) + '/' + currentDate.getFullYear();
577            } else if (dateAsString == null || dateAsString.length == 0 || dateAsString.indexOf(".") != -1) {
578                return ('0' + (currentDate.getMonth() + 1)).slice(-2) + '/' + ('0' + currentDate.getDate()).slice(-2) + '/' + currentDate.getFullYear();
579            }
580
581            fdts = dateAsString.split("/");
582
583            if (fdts != null) {
584                //switch mm/dd/yyyy to be dd/mm/yyyy for logic further down
585                if (formatString.toLowerCase() !== "dd/mm/yyyy") {
586                    var day = fdts[1];
587                    var month = fdts[0];
588                    fdts[0] = day;
589                    fdts[1] = month;
590                }
591
592                if (fdts[0] == null || fdts[0] === '0' || fdts[0].length < 1 || fdts[0].length > 2) {
593                    fdts[0] = currentDate.getDate();
594                }
595                if (fdts[1] == null || fdts[1] === '0' || fdts[1].length < 1 || fdts[1].length > 2) {
596                    fdts[1] = currentDate.getMonth() + 1;
597                }
598                if (fdts[2] == null || (fdts[2].length !== 2 && fdts[2].length !== 4)) {
599                    //For last year's date it also adds time at the end of date so extracting year
600                    fdts[2] = !isNaN(fdts[2].substr(0, 4)) ? fdts[2].substr(0, 4) : currentDate.getFullYear();
601                } else if (fdts[2].length === 2) {
602                    var yr = fdts[2];
603                    var crDate = new Date();
604                    var crCtry = crDate.getFullYear();
605                    var pstCnry = crCtry - 100;
606                    crCtry = crCtry + ' ';
607                    pstCnry = pstCnry + ' ';
608                    crCtry = crCtry.substr(0, 2);
609                    pstCnry = pstCnry.substr(0, 2);
610                    if (yr >= 32)
611                        yr = pstCnry + yr;
612                    else
613                        yr = crCtry + yr;
614                    fdts[2] = yr;
615                }
616            }
617            if (formatString.toLowerCase() === "dd/mm/yyyy") {
618                dateAsString = ('0' + fdts[0]).slice(-2) + '/' + ('0' + fdts[1]).slice(-2) + '/' + fdts[2];
619            } else {
620                dateAsString = ('0' + fdts[1]).slice(-2) + '/' + ('0' + fdts[0]).slice(-2) + '/' + fdts[2];
621            }
622            return dateAsString;
623        } catch (e) {
624            return "";
625        }
626    }
627
628    function autoTimeFormat(inputString) {
629
630        const regex1 = /^(0?[1-9]|1[0-2]) ?([ap]m)$/i; //eg: 5AM -> 5:00 AM
631        const regex2 = /^(\d{1,2})(\d{2}) ?([ap]m)$/i; //eg: 500AM -> 5:00 AM
632        const regex3 = /^(\d{1,2})(?::(\d{2}))?\s*([ap]m)?$/i; //eg: 05:00 am or 5:00 am -> 5:00 AM
633
634        if (regex1.test(inputString)) {
635            return inputString.replace(regex1, (match, hour, period) => {
636                const hourNum = parseInt(hour);
637                const formattedHour = hourNum === 12 ? 12 : hourNum % 12; // Convert to 12-hour format
638                const formattedMinute = "00"; // Add 00 as minutes
639                const formattedPeriod = period.toUpperCase();
639 // Convert period to uppercase
640                return `${formattedHour}:${formattedMinute} ${formattedPeriod}`;
641            });
642        }
643        else if (regex2.test(inputString)) {
644            return inputString.replace(regex2, (match, hour, minute, period) => {
645                const hourNum = parseInt(hour);
646                const formattedHour = hourNum === 12 ? 12 : hourNum % 12; // Convert to 12-hour format
647                const formattedMinute = minute.padStart(2, "0"); // Pad minute with zero if necessary
648                const formattedPeriod = period.toUpperCase(); // Convert period to uppercase
649                return `${formattedHour}:${formattedMinute} ${formattedPeriod}`;
650            });
651        }
652        else if (regex3.test(inputString)) {
653            return inputString.replace(regex3, (match, hour, minute, period) => {
654                const hourNum = parseInt(hour);
655                const formattedHour = hourNum === 12 ? 12 : hourNum % 12; // Convert to 12-hour format
656                const formattedMinute = minute ? minute : "00"; // Set minute to "00" if not provided
657                const formattedPeriod = period ? period.toUpperCase() : ""; // Convert period to uppercase if provided
658                return `${formattedHour}:${formattedMinute} ${formattedPeriod}`;
659            });
660        }
661        else {
662            return inputString;
663        }
664    }
665})(jQuery);

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.