From efc8053e756156cca5e239f1886469c6b92c2cf7 Mon Sep 17 00:00:00 2001
From: Tsanislav Gatev
Date: Fri, 23 Aug 2024 16:38:09 +0300
Subject: [PATCH] feat(ui5-calendar): implement calendar week numbering (#9694)
With this feature you can select one of four options to sete to the Calendar, DatePicker, DateTimePicker, DateRangePicker components.
Default -Determined by active format locale
ISO_8601 - Official calendar week numbering in most of Europe (ISO 8601standard)
WesternTraditional -Official calendar week numbering in the United States, Canada, Brazil, Israel, Japan, and other countries
MiddleEastern - Official calendar week numbering in much of the Middle East
It can be used as:
This property will control the week numbering and the first day of the week in a way explained in the enumeration documentation.
---
packages/localization/src/CalendarUtils.ts | 8 +++
.../src/dates/calculateWeekNumber.ts | 55 -------------------
packages/main/src/Calendar.hbs | 1 +
packages/main/src/DateComponentBase.ts | 11 ++++
packages/main/src/DatePickerPopover.hbs | 1 +
packages/main/src/DateRangePicker.hbs | 1 +
packages/main/src/DateTimePickerPopover.hbs | 1 +
packages/main/src/DayPicker.ts | 20 +++++--
.../main/src/types/CalendarWeekNumbering.ts | 50 +++++++++++++++++
packages/main/test/pages/Calendar.html | 17 ++++++
packages/main/test/pages/DatePicker.html | 14 +++++
packages/main/test/pages/DateRangePicker.html | 12 ++++
packages/main/test/pages/DateTimePicker.html | 14 +++++
packages/main/test/specs/Calendar.spec.js | 25 +++++++++
packages/main/test/specs/DatePicker.spec.js | 2 +-
.../main/Calendar/Calendar.mdx | 7 ++-
.../_components_pages/main/DatePicker.mdx | 7 ++-
.../CalendarWeekNumbering.md | 4 ++
.../Calendar/CalendarWeekNumbering/main.js | 7 +++
.../CalendarWeekNumbering/sample.html | 31 +++++++++++
.../CalendarWeekNumbering.md | 4 ++
.../DatePicker/CalendarWeekNumbering/main.js | 7 +++
.../CalendarWeekNumbering/sample.html | 31 +++++++++++
23 files changed, 267 insertions(+), 63 deletions(-)
create mode 100644 packages/localization/src/CalendarUtils.ts
delete mode 100644 packages/localization/src/dates/calculateWeekNumber.ts
create mode 100644 packages/main/src/types/CalendarWeekNumbering.ts
create mode 100644 packages/website/docs/_samples/main/Calendar/CalendarWeekNumbering/CalendarWeekNumbering.md
create mode 100644 packages/website/docs/_samples/main/Calendar/CalendarWeekNumbering/main.js
create mode 100644 packages/website/docs/_samples/main/Calendar/CalendarWeekNumbering/sample.html
create mode 100644 packages/website/docs/_samples/main/DatePicker/CalendarWeekNumbering/CalendarWeekNumbering.md
create mode 100644 packages/website/docs/_samples/main/DatePicker/CalendarWeekNumbering/main.js
create mode 100644 packages/website/docs/_samples/main/DatePicker/CalendarWeekNumbering/sample.html
diff --git a/packages/localization/src/CalendarUtils.ts b/packages/localization/src/CalendarUtils.ts
new file mode 100644
index 000000000000..455a75abaecc
--- /dev/null
+++ b/packages/localization/src/CalendarUtils.ts
@@ -0,0 +1,8 @@
+import type CaledndarUtilsOpenui5T from "sap/ui/core/date/CalendarUtils";
+// @ts-ignore
+import CalendarUtilsNative from "./sap/ui/core/date/CalendarUtils.js";
+
+const CalendarUtilsWrapped = CalendarUtilsNative as typeof CaledndarUtilsOpenui5T;
+const CalendarUtils = CalendarUtilsWrapped;
+
+export default CalendarUtils;
diff --git a/packages/localization/src/dates/calculateWeekNumber.ts b/packages/localization/src/dates/calculateWeekNumber.ts
deleted file mode 100644
index 6d98e89d8a61..000000000000
--- a/packages/localization/src/dates/calculateWeekNumber.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import type Locale from "@ui5/webcomponents-base/dist/locale/Locale.js";
-import type CalendarType from "@ui5/webcomponents-base/dist/types/CalendarType.js";
-import UniversalDate from "./UniversalDate.js";
-import type LocaleData from "../LocaleData.js";
-import type UI5Date from "./UI5Date.js";
-
-const calculateWeekNumber = (confFirstDayOfWeek: number | undefined, oDate: Date | UI5Date, iYear: number, oLocale: Locale, oLocaleData: LocaleData, calendarType: CalendarType) => {
- let iWeekNum = 0;
- let iWeekDay = 0;
- const iFirstDayOfWeek = Number.isInteger(confFirstDayOfWeek) ? confFirstDayOfWeek! : oLocaleData.getFirstDayOfWeek();
-
- // search Locale for containing "en-US", since sometimes
- // when any user settings have been defined, subtag "sapufmt" is added to the locale name
- // this is described inside sap.ui.core.Configuration file
- if (oLocale && (oLocale.getLanguage() === "en" && oLocale.getRegion() === "US")) {
- /*
- * in US the week starts with Sunday
- * The first week of the year starts with January 1st. But Dec. 31 is still in the last year
- * So the week beginning in December and ending in January has 2 week numbers
- */
- const oJanFirst = UniversalDate.getInstance(oDate, calendarType);
- oJanFirst.setUTCFullYear(iYear, 0, 1);
- iWeekDay = oJanFirst.getUTCDay();
-
- // get the date for the same weekday like jan 1.
- const oCheckDate = UniversalDate.getInstance(oDate, calendarType);
- oCheckDate.setUTCDate(oCheckDate.getUTCDate() - oCheckDate.getUTCDay() + iWeekDay);
-
- iWeekNum = Math.round((oCheckDate.getTime() - oJanFirst.getTime()) / 86400000 / 7) + 1;
- } else {
- // normally the first week of the year is the one where the first Thursday of the year is
- // find Thursday of this week
- // if the checked day is before the 1. day of the week use a day of the previous week to check
- const oThursday = UniversalDate.getInstance(oDate, calendarType);
- oThursday.setUTCDate(oThursday.getUTCDate() - iFirstDayOfWeek);
- iWeekDay = oThursday.getUTCDay();
- oThursday.setUTCDate(oThursday.getUTCDate() - iWeekDay + 4);
-
- const oFirstDayOfYear = UniversalDate.getInstance(new Date(oThursday.getTime()), calendarType);
- oFirstDayOfYear.setUTCMonth(0, 1);
- iWeekDay = oFirstDayOfYear.getUTCDay();
- let iAddDays = 0;
- if (iWeekDay > 4) {
- iAddDays = 7; // first day of year is after Thursday, so first Thursday is in the next week
- }
- const oFirstThursday = UniversalDate.getInstance(new Date(oFirstDayOfYear.getTime()), calendarType);
- oFirstThursday.setUTCDate(1 - iWeekDay + 4 + iAddDays);
-
- iWeekNum = Math.round((oThursday.getTime() - oFirstThursday.getTime()) / 86400000 / 7) + 1;
- }
-
- return iWeekNum;
-};
-
-export default calculateWeekNumber;
diff --git a/packages/main/src/Calendar.hbs b/packages/main/src/Calendar.hbs
index 2e370b3f3b9b..e7ab7af3b6c8 100644
--- a/packages/main/src/Calendar.hbs
+++ b/packages/main/src/Calendar.hbs
@@ -15,6 +15,7 @@
.selectionMode="{{selectionMode}}"
.minDate="{{minDate}}"
.maxDate="{{maxDate}}"
+ .calendarWeekNumbering="{{calendarWeekNumbering}}"
timestamp="{{_timestamp}}"
?hide-week-numbers="{{hideWeekNumbers}}"
@ui5-change="{{onSelectedDatesChange}}"
diff --git a/packages/main/src/DateComponentBase.ts b/packages/main/src/DateComponentBase.ts
index ef16ecfc0d12..627486e399bf 100644
--- a/packages/main/src/DateComponentBase.ts
+++ b/packages/main/src/DateComponentBase.ts
@@ -13,6 +13,7 @@ import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js";
import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js";
import { getMaxCalendarDate, getMinCalendarDate } from "@ui5/webcomponents-localization/dist/dates/ExtremeDates.js";
import UI5Date from "@ui5/webcomponents-localization/dist/dates/UI5Date.js";
+import type CalendarWeekNumbering from "./types/CalendarWeekNumbering.js";
/**
* @class
@@ -81,6 +82,16 @@ class DateComponentBase extends UI5Element {
@property()
maxDate = "";
+ /**
+ * Defines how to calculate calendar weeks and first day of the week.
+ * If not set, the calendar will be displayed according to the currently set global configuration.
+ * @default "Default"
+ * @since 2.2.0
+ * @public
+ */
+ @property()
+ calendarWeekNumbering: `${CalendarWeekNumbering}` = "Default";
+
static i18nBundle?: I18nBundle;
/**
diff --git a/packages/main/src/DatePickerPopover.hbs b/packages/main/src/DatePickerPopover.hbs
index f4b6fe9e76be..0f9b624168c8 100644
--- a/packages/main/src/DatePickerPopover.hbs
+++ b/packages/main/src/DatePickerPopover.hbs
@@ -47,6 +47,7 @@
.selectionMode="{{_calendarSelectionMode}}"
.minDate="{{minDate}}"
.maxDate="{{maxDate}}"
+ .calendarWeekNumbering="{{calendarWeekNumbering}}"
@ui5-selection-change="{{onSelectedDatesChange}}"
@ui5-show-month-view="{{onHeaderShowMonthPress}}"
@ui5-show-year-view="{{onHeaderShowYearPress}}"
diff --git a/packages/main/src/DateRangePicker.hbs b/packages/main/src/DateRangePicker.hbs
index 46562a1fcf89..d1b22957b158 100644
--- a/packages/main/src/DateRangePicker.hbs
+++ b/packages/main/src/DateRangePicker.hbs
@@ -10,6 +10,7 @@
.selectionMode="{{_calendarSelectionMode}}"
.minDate="{{minDate}}"
.maxDate="{{maxDate}}"
+ .calendarWeekNumbering="{{calendarWeekNumbering}}"
@ui5-selection-change="{{onSelectedDatesChange}}"
@ui5-show-month-view="{{onHeaderShowMonthPress}}"
@ui5-show-year-view="{{onHeaderShowYearPress}}"
diff --git a/packages/main/src/DateTimePickerPopover.hbs b/packages/main/src/DateTimePickerPopover.hbs
index c3a63d7b17a7..b78b6a9837b4 100644
--- a/packages/main/src/DateTimePickerPopover.hbs
+++ b/packages/main/src/DateTimePickerPopover.hbs
@@ -23,6 +23,7 @@
.selectionMode="{{_calendarSelectionMode}}"
.minDate="{{minDate}}"
.maxDate="{{maxDate}}"
+ .calendarWeekNumbering="{{calendarWeekNumbering}}"
@ui5-selection-change="{{onSelectedDatesChange}}"
@ui5-show-month-view="{{onHeaderShowMonthPress}}"
@ui5-show-year-view="{{onHeaderShowYearPress}}"
diff --git a/packages/main/src/DayPicker.ts b/packages/main/src/DayPicker.ts
index f532e69ade7d..aa36aab519f1 100644
--- a/packages/main/src/DayPicker.ts
+++ b/packages/main/src/DayPicker.ts
@@ -3,7 +3,6 @@ import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import event from "@ui5/webcomponents-base/dist/decorators/event.js";
import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js";
import type LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js";
-import { getFirstDayOfWeek } from "@ui5/webcomponents-base/dist/config/FormatSettings.js";
import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import {
@@ -29,9 +28,10 @@ import {
isPageDownShiftCtrl,
} from "@ui5/webcomponents-base/dist/Keys.js";
import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js";
-import calculateWeekNumber from "@ui5/webcomponents-localization/dist/dates/calculateWeekNumber.js";
import CalendarType from "@ui5/webcomponents-base/dist/types/CalendarType.js";
import UI5Date from "@ui5/webcomponents-localization/dist/dates/UI5Date.js";
+import CalendarUtils from "@ui5/webcomponents-localization/dist/CalendarUtils.js";
+import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js";
import CalendarSelectionMode from "./types/CalendarSelectionMode.js";
import CalendarPart from "./CalendarPart.js";
import type {
@@ -304,8 +304,10 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
week.push(day);
if (dayOfTheWeek === DAYS_IN_WEEK - 1) { // 0-indexed so 6 is the last day of the week
+ const weekNumber = this._calculateWeekNumber(tempDate.toLocalJSDate());
+
week.unshift({
- weekNum: calculateWeekNumber(getFirstDayOfWeek(), tempDate.toUTCJSDate(), tempDate.getYear(), getLocale(), localeData, this._primaryCalendarType as CalendarType),
+ weekNum: weekNumber,
isHidden: this.shouldHideWeekNumbers,
});
}
@@ -322,6 +324,13 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
}
}
+ _calculateWeekNumber(date: Date): number {
+ const oDateFormat = DateFormat.getDateInstance({ pattern: "w", calendarType: this.primaryCalendarType, calendarWeekNumbering: this.calendarWeekNumbering });
+ const weekNumber = oDateFormat.format(date);
+
+ return Number(weekNumber);
+ }
+
/**
* Builds the dayNames object (header of the month).
* @param localeData
@@ -793,9 +802,10 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
}
_getFirstDayOfWeek(): number {
+ const result = CalendarUtils.getWeekConfigurationValues(this.calendarWeekNumbering);
+
const localeData = getCachedLocaleDataInstance(getLocale());
- const confFirstDayOfWeek = getFirstDayOfWeek();
- return Number.isInteger(confFirstDayOfWeek) ? confFirstDayOfWeek! : localeData.getFirstDayOfWeek();
+ return result?.firstDayOfWeek ? result.firstDayOfWeek : localeData.getFirstDayOfWeek();
}
get styles() {
diff --git a/packages/main/src/types/CalendarWeekNumbering.ts b/packages/main/src/types/CalendarWeekNumbering.ts
new file mode 100644
index 000000000000..7b8ea696811c
--- /dev/null
+++ b/packages/main/src/types/CalendarWeekNumbering.ts
@@ -0,0 +1,50 @@
+/**
+ * The CalendarWeekNumbering
enum defines how to calculate calendar weeks. Each
+ * value defines:
+ * - The first day of the week,
+ * - The first week of the year.
+ *
+ * @public
+ * @since 2.2.0
+ */
+
+enum CalendarWeekNumbering {
+
+ /**
+ * The default calendar week numbering:
+ *
+ * The framework determines the week numbering scheme; currently it is derived from the
+ * active format locale. Future versions of ui5-webcomponents might select a different week numbering
+ * scheme.
+ *
+ * @public
+ */
+ Default = "Default",
+
+ /**
+ * Official calendar week numbering in most of Europe (ISO 8601 standard):
+ * Monday is first day of the week, the week containing January 4th is first week of the year.
+ *
+ * @public
+ */
+ ISO_8601 = "ISO_8601",
+
+ /**
+ * Official calendar week numbering in much of the Middle East (Middle Eastern calendar):
+ * Saturday is first day of the week, the week containing January 1st is first week of the year.
+ *
+ * @public
+ */
+ MiddleEastern = "MiddleEastern",
+
+ /**
+ * Official calendar week numbering in the United States, Canada, Brazil, Israel, Japan, and
+ * other countries (Western traditional calendar):
+ * Sunday is first day of the week, the week containing January 1st is first week of the year.
+ *
+ * @public
+ */
+ WesternTraditional = "WesternTraditional",
+}
+
+export default CalendarWeekNumbering;
diff --git a/packages/main/test/pages/Calendar.html b/packages/main/test/pages/Calendar.html
index d76332b2c57d..3849394025ed 100644
--- a/packages/main/test/pages/Calendar.html
+++ b/packages/main/test/pages/Calendar.html
@@ -86,6 +86,23 @@
+
+ Calendar with CalendarWeekNumbering ISO_8601
+
+
+
+
+ Calendar with CalendarWeekNumbering MiddleEastern
+
+
+
+
+ Calendar with CalendarWeekNumbering WesternTraditional
+
+
+
+
+
+
+
+
+ ISO_8601
+ MiddleEastern
+ WesternTraditional
+
+
+
+
+