diff --git a/src/public/app/widgets/buttons/calendar.ts b/src/public/app/widgets/buttons/calendar.ts
index 11e9092bc..97445a507 100644
--- a/src/public/app/widgets/buttons/calendar.ts
+++ b/src/public/app/widgets/buttons/calendar.ts
@@ -29,7 +29,7 @@ const DROPDOWN_TPL = `
@@ -59,10 +59,13 @@ const DROPDOWN_TPL = `
- `;
const DAYS_OF_WEEK = [t("calendar.sun"), t("calendar.mon"), t("calendar.tue"), t("calendar.wed"), t("calendar.thu"), t("calendar.fri"), t("calendar.sat")];
@@ -71,9 +74,15 @@ interface DateNotesForMonth {
[date: string]: string;
}
+interface WeekCalculationOptions {
+ firstWeekType: number;
+ minDaysInFirstWeek: number;
+}
+
export default class CalendarWidget extends RightDropdownButtonWidget {
private $month!: JQuery;
private $weekHeader!: JQuery;
+ private $weekNumbers!: JQuery;
private $monthSelect!: JQuery;
private $yearSelect!: JQuery;
private $next!: JQuery;
@@ -82,6 +91,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
private $previousYear!: JQuery;
private monthDropdown!: Dropdown;
private firstDayOfWeek!: number;
+ private weekCalculationOptions!: WeekCalculationOptions;
private activeDate: Date | null = null;
private todaysDate!: Date;
private date!: Date;
@@ -95,8 +105,10 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
this.$month = this.$dropdownContent.find('[data-calendar-area="month"]');
this.$weekHeader = this.$dropdownContent.find(".calendar-week");
+ this.$weekNumbers = this.$dropdownContent.find(".calendar-week-numbers");
this.manageFirstDayOfWeek();
+ this.initWeekCalculation();
// Month navigation
this.$monthSelect = this.$dropdownContent.find('[data-calendar-input="month"]');
@@ -187,6 +199,52 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
this.$weekHeader.html(localeDaysOfWeek.map((el) => `${el}`).join(''));
}
+ initWeekCalculation() {
+ this.weekCalculationOptions = {
+ firstWeekType: options.getInt("firstWeekOfYear") || 0,
+ minDaysInFirstWeek: options.getInt("minDaysInFirstWeek") || 4
+ };
+ }
+
+ getWeekNumber(date: Date): number {
+ const utcDate = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
+
+ const year = utcDate.getUTCFullYear();
+ const jan1 = new Date(Date.UTC(year, 0, 1));
+ const jan1Day = jan1.getUTCDay();
+
+ let firstWeekStart = new Date(jan1);
+
+ let dayOffset = (jan1Day - this.firstDayOfWeek + 7) % 7;
+ firstWeekStart.setUTCDate(firstWeekStart.getUTCDate() - dayOffset);
+
+ switch (this.weekCalculationOptions.firstWeekType) {
+ case 1: {
+ const thursday = new Date(firstWeekStart);
+ const day = thursday.getUTCDay();
+ const offset = (4 - day + 7) % 7;
+ thursday.setUTCDate(thursday.getUTCDate() + offset);
+ if (thursday.getUTCFullYear() < year) {
+ firstWeekStart.setUTCDate(firstWeekStart.getUTCDate() + 7);
+ }
+ break;
+ }
+ case 2: {
+ const daysInFirstWeek = 7 - dayOffset;
+ if (daysInFirstWeek < this.weekCalculationOptions.minDaysInFirstWeek) {
+ firstWeekStart.setUTCDate(firstWeekStart.getUTCDate() + 7);
+ }
+ break;
+ }
+ // case 0 is default: week containing Jan 1
+ }
+
+ const diffMillis = utcDate.getTime() - firstWeekStart.getTime();
+ const diffDays = Math.floor(diffMillis / (24 * 60 * 60 * 1000));
+
+ return Math.floor(diffDays / 7) + 1;
+ }
+
async dropdownShown() {
this.init(appContext.tabManager.getActiveContextNote()?.getOwnedLabelValue("dateNote") ?? null);
}
@@ -246,13 +304,19 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
}
async createMonth() {
- const month = utils.formatDateISO(this.date).substr(0, 7);
+ const month = utils.formatDateISO(this.date).substring(0, 7);
const dateNotesForMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${month}`);
this.$month.empty();
+ this.$weekNumbers.empty();
const currentMonth = this.date.getMonth();
+ const weekNumbers: Set = new Set();
+
while (this.date.getMonth() === currentMonth) {
+ const safeDate = new Date(Date.UTC(this.date.getFullYear(), this.date.getMonth(), this.date.getDate()));
+ weekNumbers.add(this.getWeekNumber(safeDate));
+
const $day = this.createDay(dateNotesForMonth, this.date.getDate(), this.date.getDay());
this.$month.append($day);
@@ -265,14 +329,24 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
this.$monthSelect.text(MONTHS[this.date.getMonth()]);
this.$yearSelect.val(this.date.getFullYear());
+
+ for (const weekNumber of weekNumbers) {
+ const $weekNumber = $("")
+ .addClass("calendar-week-number")
+ .text(weekNumber);
+ this.$weekNumbers.append($weekNumber);
+ }
}
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
- if (!loadResults.getOptionNames().includes("firstDayOfWeek")) {
+ if (!loadResults.getOptionNames().includes("firstDayOfWeek") &&
+ !loadResults.getOptionNames().includes("firstWeekOfYear") &&
+ !loadResults.getOptionNames().includes("minDaysInFirstWeek")) {
return;
}
this.manageFirstDayOfWeek();
+ this.initWeekCalculation();
this.createMonth();
}
}
diff --git a/src/public/stylesheets/calendar.css b/src/public/stylesheets/calendar.css
index e1c39e52a..85b73381e 100644
--- a/src/public/stylesheets/calendar.css
+++ b/src/public/stylesheets/calendar.css
@@ -35,7 +35,7 @@
padding: 0 0.5rem 0.5rem 0.5rem;
}
-.calendar-dropdown-widget .calendar-header > div {
+.calendar-dropdown-widget .calendar-header>div {
display: flex;
justify-content: center;
flex-grow: 1;
@@ -67,7 +67,34 @@
}
.calendar-dropdown-widget .calendar-header .dropdown-toggle::after {
- border: unset; /* Disable the dropdown arrow */
+ border: unset;
+ /* Disable the dropdown arrow */
+}
+
+.calendar-container {
+ display: flex;
+}
+
+.calendar-dropdown-widget .calendar-week-numbers {
+ width: 30px;
+ border-right: 1px solid var(--main-border-color);
+ padding-right: 5px;
+ margin-right: 5px;
+ padding-top: 2.4rem;
+}
+
+.calendar-dropdown-widget .calendar-week-number {
+ /* height: 2.4rem; */
+ /* line-height: 2.4rem; */
+ text-align: center;
+ color: var(--muted-text-color);
+ font-size: 0.9em;
+}
+
+.calendar-main {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
}
.calendar-dropdown-widget .calendar-week {