diff --git a/src/components/base/DateTimeSelectionBase.ts b/src/components/base/DateTimeSelectionBase.ts new file mode 100644 index 00000000..eaa1b904 --- /dev/null +++ b/src/components/base/DateTimeSelectionBase.ts @@ -0,0 +1,113 @@ +import { ref, computed } from 'vue'; + +import { useI18n } from '@/locales/helpers.ts'; + +import { useUserStore } from '@/stores/user.ts'; + +import { type NameValue } from '@/core/base.ts'; +import { type WeekDayValue } from '@/core/datetime.ts'; +import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; +import { getCurrentYear } from '@/lib/datetime.ts'; + +export interface TimePickerValue { + value: string; + itemsIndex: number; +} + +export function useDateTimeSelectionBase() { + const { + getAllMinWeekdayNames, + getAllMeridiemIndicators, + isLongDateMonthAfterYear, + isLongTime24HourFormat, + isLongTimeMeridiemIndicatorFirst, + isLongTimeHourTwoDigits, + isLongTimeMinuteTwoDigits, + isLongTimeSecondTwoDigits + } = useI18n(); + + const userStore = useUserStore(); + + const is24Hour = ref(isLongTime24HourFormat()); + const isHourTwoDigits = ref(isLongTimeHourTwoDigits()); + const isMinuteTwoDigits = ref(isLongTimeMinuteTwoDigits()); + const isSecondTwoDigits = ref(isLongTimeSecondTwoDigits()); + const isMeridiemIndicatorFirst = ref(isLongTimeMeridiemIndicatorFirst() || false); + + const yearRange = ref([ + 2000, + getCurrentYear() + 1 + ]); + + const meridiemItems = computed(() => getAllMeridiemIndicators()); + + const firstDayOfWeek = computed(() => userStore.currentUserFirstDayOfWeek); + const dayNames = computed(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value)); + const isYearFirst = computed(() => isLongDateMonthAfterYear()); + + function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string { + if (forceTwoDigits && value < 10) { + return `0${value}`; + } else { + return value.toString(); + } + } + + function generateAllHours(count: number, forceTwoDigits: boolean): TimePickerValue[] { + const ret: TimePickerValue[] = []; + const startHour = is24Hour.value ? 0 : 1; + const endHour = is24Hour.value ? 23 : 11; + + for (let i = 0; i < count; i++) { + if (!is24Hour.value) { + ret.push({ + value: '12', + itemsIndex: i + }); + } + + for (let j = startHour; j <= endHour; j++) { + ret.push({ + value: getDisplayTimeValue(j, forceTwoDigits), + itemsIndex: i + }); + } + } + + return ret; + } + + function generateAllMinutesOrSeconds(count: number, forceTwoDigits: boolean): TimePickerValue[] { + const ret: TimePickerValue[] = []; + + for (let i = 0; i < count; i++) { + for (let j = 0; j < 60; j++) { + ret.push({ + value: getDisplayTimeValue(j, forceTwoDigits), + itemsIndex: i + }); + } + } + + return ret; + } + + return { + // states + is24Hour, + isHourTwoDigits, + isMinuteTwoDigits, + isSecondTwoDigits, + isMeridiemIndicatorFirst, + yearRange, + // computed + meridiemItems, + firstDayOfWeek, + dayNames, + isYearFirst, + // functions + getDisplayTimeValue, + generateAllHours, + generateAllMinutesOrSeconds + }; +} diff --git a/src/components/desktop/DateTimeSelect.vue b/src/components/desktop/DateTimeSelect.vue index 736068b4..3427c15c 100644 --- a/src/components/desktop/DateTimeSelect.vue +++ b/src/components/desktop/DateTimeSelect.vue @@ -12,10 +12,11 @@ +
+ + {{ tt(`datetime.${currentMeridiemIndicator}.content`) }} + + + : + + : + + + {{ tt(`datetime.${currentMeridiemIndicator}.content`) }} + +
diff --git a/src/components/mobile/DateTimeSelectionSheet.vue b/src/components/mobile/DateTimeSelectionSheet.vue index 7cb37bd5..6c81ed40 100644 --- a/src/components/mobile/DateTimeSelectionSheet.vue +++ b/src/components/mobile/DateTimeSelectionSheet.vue @@ -120,13 +120,11 @@ import VueDatePicker from '@vuepic/vue-datepicker'; import { useI18n } from '@/locales/helpers.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; +import { type TimePickerValue, useDateTimeSelectionBase } from '@/components/base/DateTimeSelectionBase.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts'; -import { useUserStore } from '@/stores/user.ts'; -import { type NameValue } from '@/core/base.ts'; -import { type WeekDayValue } from '@/core/datetime.ts'; -import { isDefined, arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; +import { isDefined } from '@/lib/common.ts'; import { getHourIn12HourFormat, getTimezoneOffsetMinutes, @@ -134,7 +132,6 @@ import { getLocalDatetimeFromUnixTime, getActualUnixTimeForStore, getCurrentUnixTime, - getCurrentYear, getUnixTime, getAMOrPM, getCombinedDateAndTimeValues @@ -142,11 +139,6 @@ import { type VueDatePickerType = InstanceType; -interface TimePickerValue { - value: string; - itemsIndex: number; -} - const props = defineProps<{ modelValue: number; initMode?: string; @@ -160,85 +152,79 @@ const emit = defineEmits<{ const { tt, - getAllMinWeekdayNames, - getAllMeridiemIndicators, getMonthShortName, - formatUnixTimeToLongDateTime, - isLongDateMonthAfterYear, - isLongTime24HourFormat, - isLongTimeMeridiemIndicatorFirst, - isLongTimeHourTwoDigits, - isLongTimeMinuteTwoDigits, - isLongTimeSecondTwoDigits + formatUnixTimeToLongDateTime } = useI18n(); const { showToast } = useI18nUIComponents(); -const environmentsStore = useEnvironmentsStore(); -const userStore = useUserStore(); +const { + is24Hour, + isHourTwoDigits, + isMinuteTwoDigits, + isSecondTwoDigits, + isMeridiemIndicatorFirst, + yearRange, + meridiemItems, + firstDayOfWeek, + dayNames, + isYearFirst, + getDisplayTimeValue, + generateAllHours, + generateAllMinutesOrSeconds +} = useDateTimeSelectionBase(); + +const environmentsStore = useEnvironmentsStore(); + +const datetimepicker = useTemplateRef('datetimepicker'); -const is24Hour: boolean = isLongTime24HourFormat(); -const isHourTwoDigits: boolean = isLongTimeHourTwoDigits(); -const isMinuteTwoDigits: boolean = isLongTimeMinuteTwoDigits(); -const isSecondTwoDigits: boolean = isLongTimeSecondTwoDigits(); -const isMeridiemIndicatorFirst: boolean = isLongTimeMeridiemIndicatorFirst() || false; let resetTimePickerItemPositionItemsClass: string | undefined = undefined; let resetTimePickerItemPositionItemClass: string | undefined = undefined; let resetTimePickerItemPositionItemsLastOffsetTop: number | undefined = undefined; let resetTimePickerItemPositionCheckedFrames: number | undefined = undefined; const mode = ref(props.initMode || 'time'); -const yearRange = ref([ - 2000, - getCurrentYear() + 1 -]); const dateTime = ref(getLocalDatetimeFromUnixTime(props.modelValue || getCurrentUnixTime())); const timePickerContainerHeight = ref(undefined); const timePickerItemHeight = ref(undefined); -const datetimepicker = useTemplateRef('datetimepicker'); +const hourItems = computed(() => generateAllHours(3, isHourTwoDigits.value)); +const minuteItems = computed(() => generateAllMinutesOrSeconds(3, isMinuteTwoDigits.value)); +const secondItems = computed(() => generateAllMinutesOrSeconds(3, isSecondTwoDigits.value)); const currentMeridiemIndicator = computed({ get: () => { return getAMOrPM(dateTime.value.getHours()) }, set: (value: string) => { - dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, currentMinute.value, currentSecond.value, value, is24Hour); + dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, currentMinute.value, currentSecond.value, value, is24Hour.value); } }); const currentHour = computed({ get: () => { - return getDisplayTimeValue(is24Hour ? dateTime.value.getHours() : getHourIn12HourFormat(dateTime.value.getHours()), isHourTwoDigits); + return getDisplayTimeValue(is24Hour.value ? dateTime.value.getHours() : getHourIn12HourFormat(dateTime.value.getHours()), isHourTwoDigits.value); }, set: (value: string) => { - dateTime.value = getCombinedDateAndTimeValues(dateTime.value, value, currentMinute.value, currentSecond.value, currentMeridiemIndicator.value, is24Hour); + dateTime.value = getCombinedDateAndTimeValues(dateTime.value, value, currentMinute.value, currentSecond.value, currentMeridiemIndicator.value, is24Hour.value); } }); const currentMinute = computed({ get: () => { - return getDisplayTimeValue(dateTime.value.getMinutes(), isMinuteTwoDigits); + return getDisplayTimeValue(dateTime.value.getMinutes(), isMinuteTwoDigits.value); }, set: (value: string) => { - dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, value, currentSecond.value, currentMeridiemIndicator.value, is24Hour); + dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, value, currentSecond.value, currentMeridiemIndicator.value, is24Hour.value); } }); const currentSecond = computed({ get: () => { - return getDisplayTimeValue(dateTime.value.getSeconds(), isSecondTwoDigits); + return getDisplayTimeValue(dateTime.value.getSeconds(), isSecondTwoDigits.value); }, set: (value: string) => { - dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, currentMinute.value, value, currentMeridiemIndicator.value, is24Hour); + dateTime.value = getCombinedDateAndTimeValues(dateTime.value, currentHour.value, currentMinute.value, value, currentMeridiemIndicator.value, is24Hour.value); } }); -const hourItems = computed(() => generateAllHours(3, isHourTwoDigits)); -const minuteItems = computed(() => generateAllMinutesOrSeconds(3, isMinuteTwoDigits)); -const secondItems = computed(() => generateAllMinutesOrSeconds(3, isSecondTwoDigits)); -const meridiemItems = computed(() => getAllMeridiemIndicators()); - const isDarkMode = computed(() => environmentsStore.framework7DarkMode || false); -const firstDayOfWeek = computed(() => userStore.currentUserFirstDayOfWeek); -const dayNames = computed(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value)); -const isYearFirst = computed(() => isLongDateMonthAfterYear()); const displayTime = computed(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); const switchButtonTitle = computed(() => mode.value === 'time' ? 'Date' : 'Time'); @@ -274,53 +260,6 @@ function confirm(): void { emit('update:show', false); } -function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string { - if (forceTwoDigits && value < 10) { - return `0${value}`; - } else { - return value.toString(); - } -} - -function generateAllHours(count: number, forceTwoDigits: boolean): TimePickerValue[] { - const ret: TimePickerValue[] = []; - const startHour = is24Hour ? 0 : 1; - const endHour = is24Hour ? 23 : 11; - - for (let i = 0; i < count; i++) { - if (!is24Hour) { - ret.push({ - value: '12', - itemsIndex: i - }); - } - - for (let j = startHour; j <= endHour; j++) { - ret.push({ - value: getDisplayTimeValue(j, forceTwoDigits), - itemsIndex: i - }); - } - } - - return ret; -} - -function generateAllMinutesOrSeconds(count: number, forceTwoDigits: boolean): TimePickerValue[] { - const ret: TimePickerValue[] = []; - - for (let i = 0; i < count; i++) { - for (let j = 0; j < 60; j++) { - ret.push({ - value: getDisplayTimeValue(j, forceTwoDigits), - itemsIndex: i - }); - } - } - - return ret; -} - function getTimerPickerItemStyle(textualValue: string, textualCurrentValue: string, itemsIndex: number, values: TimePickerValue[]): string { if (!timePickerContainerHeight.value || !timePickerItemHeight.value) { return ''; diff --git a/src/lib/ui/desktop.ts b/src/lib/ui/desktop.ts index 9227319c..6bebe74d 100644 --- a/src/lib/ui/desktop.ts +++ b/src/lib/ui/desktop.ts @@ -48,6 +48,22 @@ export function getCssValue(element: HTMLElement | null, name: string): string { return computedStyle.getPropertyValue(name); } +export function setChildInputFocus(parentEl: HTMLElement | undefined, childSelector: string): void { + if (!parentEl) { + return; + } + + const childElement = parentEl.querySelector(childSelector); + + if (!childElement || !(childElement as HTMLInputElement)) { + return; + } + + const childInput = (childElement as HTMLInputElement); + childInput.focus(); + childInput.select(); +} + export function scrollToSelectedItem(parentEl: HTMLElement | null | undefined, containerSelector: string | null, selectedItemSelector: string): void { if (!parentEl) { return;