import { isIE11 } from '@ledge/is-ie-11'; import { h } from '@ledge/jsx'; import { NgInputController, NgInputOptions } from './shared'; function isNumber(n: any): n is number { return typeof n === 'number' && !isNaN(n); } class DateInputController extends NgInputController { public ngModel: Date | number | string | null | undefined; private minDate?: Date | number | string; private maxDate?: Date | number | string; public $onInit() { this.ngModelCtrl.$validators.minDate = modelVal => { if (isNumber(this.minDate) || this.minDate instanceof Date) { return this.minDate.valueOf() <= modelVal?.valueOf() ?? 0; } return true; }; this.ngModelCtrl.$validators.maxDate = modelVal => { if (isNumber(this.maxDate) || this.maxDate instanceof Date) { return this.maxDate.valueOf() >= modelVal?.valueOf(); } return true; }; } public $postLink() { setTimeout(() => { if (document.querySelector('input[type="date"]') == null) { const daySelect = document.querySelector(`#day_${this.uniqueId}`) as HTMLSelectElement; const monthSelect = document.querySelector(`#month_${this.uniqueId}`) as HTMLSelectElement; const yearSelect = document.querySelector(`#year_${this.uniqueId}`) as HTMLSelectElement; const updateNgModel = () => { this.ngModel = new Date( Number(yearSelect.value), Number(monthSelect.value), Number(daySelect.value), ); this.$scope.$applyAsync(); }; daySelect.onchange = () => { updateNgModel(); }; monthSelect.onchange = () => { updateNgModel(); this.update(); }; yearSelect.onchange = () => { updateNgModel(); this.update(); }; this.update(); } }); } public update() { const day = new Date(this.ngModel?.valueOf() ?? Date.now()); const daySelect = document.querySelector(`#day_${this.uniqueId}`) as HTMLSelectElement; while (daySelect.options.length > 0) { const option = daySelect.options.item(0) as HTMLOptionElement; daySelect.removeChild(option); } const currentDay = day.getDate(); const day2 = new Date(day.valueOf()); day2.setDate(0); const maxDay = day2.getDate(); let dayOption = 1; while (dayOption <= maxDay) { const option = as HTMLOptionElement; if (dayOption === currentDay) { option.setAttribute('selected', 'selected'); } else { option.removeAttribute('selected'); } daySelect.appendChild(option); dayOption++; } const currentMonth = day.getMonth(); const monthSelect = document.querySelector(`#month_${this.uniqueId}`) as HTMLSelectElement; if (Number(monthSelect.value) !== currentMonth) { for (const option of Array.prototype.slice.call(monthSelect.options)) { if (Number(option.value) === currentMonth) { option.setAttribute('selected', 'selected'); } else { option.removeAttribute('selected'); } } } const currentYear = day.getFullYear(); const yearSelect = document.querySelector(`#year_${this.uniqueId}`) as HTMLSelectElement; if (Number(yearSelect.value) !== currentYear) { for (const option of Array.prototype.slice.call(yearSelect.options)) { if (Number(option.value) === currentYear) { option.setAttribute('selected', 'selected'); } else { option.removeAttribute('selected'); } } } } } export const dateInput: NgInputOptions = { type: 'input', render() { const useFallback = this.$attrs.hasOwnProperty('useFallback'); let useNativeDatepicker = !useFallback && !isIE11(); let input = ; if (useNativeDatepicker) { try { (input as HTMLInputElement).type = 'date'; useNativeDatepicker = (input as HTMLInputElement).type === 'date'; } catch { useNativeDatepicker = false; } } if (useNativeDatepicker === false) { const currentDate = new Date(); const currentMonth = currentDate.getMonth(); const currentYear = currentDate.getFullYear(); let { minYear, maxYear, defaultYear, defaultMonth } = this.$attrs; minYear = Number(minYear ?? currentYear - 99); maxYear = Number(maxYear ?? currentYear + 99); defaultYear = Number(defaultYear ?? currentYear); defaultMonth = Number(defaultMonth ?? currentMonth); const monthSelect = as HTMLSelectElement; const yearSelect = as HTMLSelectElement; let yearOption = minYear; while (yearOption <= maxYear) { const option = as HTMLOptionElement; if (yearOption === defaultYear) option.setAttribute('selected', 'selected'); yearSelect.appendChild(option); yearOption++; } input =
{monthSelect}
{yearSelect}
; } return (
{useNativeDatepicker ? undefined : (

{'{{$ctrl.ngModel | date:"MMMM d, yyyy (EEEE)"}}'}

)} {input}
); }, bindings: { minDate: '<', maxDate: '<', }, validators: { minDate: 'Date must be on or after {{$ctrl.getMinDate()}}', maxDate: 'Date must be on or before {{$ctrl.getMaxDate()}}', }, controller: DateInputController, };