From b097a8fc370215a0940c249fa74fd01a21871e81 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 17:13:46 +0200 Subject: [PATCH 01/10] client: create a date formatter utility --- src/public/app/utils/formatters.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/public/app/utils/formatters.js diff --git a/src/public/app/utils/formatters.js b/src/public/app/utils/formatters.js new file mode 100644 index 000000000..f59e3144f --- /dev/null +++ b/src/public/app/utils/formatters.js @@ -0,0 +1,14 @@ +/** + * Formats the given date to a string based on the current locale. + * @param {Date | number} date + * @param {"full" | "long" | "medium" | "short" | undefined} dateStyle + * @param {"full" | "long" | "medium" | "short" | undefined} tiemStyle + */ +export function formatDate(date, dateStyle = "medium", tiemStyle = "medium") { + const formatter = new Intl.DateTimeFormat(navigator.language, { + dateStyle: "medium", + timeStyle: "medium" + }); + + return formatter.format(date); +} \ No newline at end of file From 56b6dae44742ffadc9a640c86ad40f386b3ed10f Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 17:13:58 +0200 Subject: [PATCH 02/10] client: refactor --- src/public/app/widgets/type_widgets/options/backup.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/public/app/widgets/type_widgets/options/backup.js b/src/public/app/widgets/type_widgets/options/backup.js index 35cd4b829..d6f8648b7 100644 --- a/src/public/app/widgets/type_widgets/options/backup.js +++ b/src/public/app/widgets/type_widgets/options/backup.js @@ -1,7 +1,8 @@ +import { formatDate } from "../../../utils/formatters.js" import { t } from "../../../services/i18n.js"; +import OptionsWidget from "./options_widget.js"; import server from "../../../services/server.js"; import toastService from "../../../services/toast.js"; -import OptionsWidget from "./options_widget.js"; const TPL = `
@@ -115,15 +116,10 @@ export default class BackupOptions extends OptionsWidget { return 0; }); - const dateTimeFormatter = new Intl.DateTimeFormat(navigator.language, { - dateStyle: "medium", - timeStyle: "medium" - }); - for (const {filePath, mtime} of backupFiles) { this.$existingBackupList.append($(` - ${(mtime) ? dateTimeFormatter.format(new Date(mtime)) : "-"} + ${(mtime) ? formatDate(new Date(mtime)) : "-"} ${filePath} `)); From 88376e115897679a741e20ddbf1d4164d210b64f Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 17:16:20 +0200 Subject: [PATCH 03/10] client: format dates for the ETAPI tokens table --- src/public/app/widgets/type_widgets/options/etapi.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/type_widgets/options/etapi.js b/src/public/app/widgets/type_widgets/options/etapi.js index 1d6d1887f..4976d97ac 100644 --- a/src/public/app/widgets/type_widgets/options/etapi.js +++ b/src/public/app/widgets/type_widgets/options/etapi.js @@ -1,8 +1,9 @@ +import { formatDate } from "../../../utils/formatters.js" import { t } from "../../../services/i18n.js"; -import server from "../../../services/server.js"; import dialogService from "../../../services/dialog.js"; -import toastService from "../../../services/toast.js"; import OptionsWidget from "./options_widget.js"; +import server from "../../../services/server.js"; +import toastService from "../../../services/toast.js"; const TPL = `
@@ -95,7 +96,7 @@ export default class EtapiOptions extends OptionsWidget { $tokensTableBody.append( $("") .append($("").text(token.name)) - .append($("").text(token.utcDateCreated)) + .append($("").text(formatDate(new Date(token.utcDateCreated)))) .append($("").append( $(``) .on("click", () => this.renameToken(token.etapiTokenId, token.name)), From 1268916ad7839ca147e8cef621ec90c996a7a580 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:09:55 +0200 Subject: [PATCH 04/10] client: date formatter utility: add the ability to format exclusively dates or times --- src/public/app/utils/formatters.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/public/app/utils/formatters.js b/src/public/app/utils/formatters.js index f59e3144f..5e3473d8d 100644 --- a/src/public/app/utils/formatters.js +++ b/src/public/app/utils/formatters.js @@ -1,14 +1,22 @@ /** * Formats the given date to a string based on the current locale. * @param {Date | number} date - * @param {"full" | "long" | "medium" | "short" | undefined} dateStyle - * @param {"full" | "long" | "medium" | "short" | undefined} tiemStyle + * @param {"full" | "long" | "medium" | "short" | "none" | undefined} dateStyle + * @param {"full" | "long" | "medium" | "short" | "none" | undefined} tiemStyle */ -export function formatDate(date, dateStyle = "medium", tiemStyle = "medium") { - const formatter = new Intl.DateTimeFormat(navigator.language, { - dateStyle: "medium", - timeStyle: "medium" - }); +export function formatDate(date, dateStyle = "medium", timeStyle = "medium") { + const locale = navigator.language; + + if (timeStyle === "none") { + // Format only the date + return date.toLocaleDateString(locale, {dateStyle}); + } else if (dateStyle === "none") { + // Format only the time + return date.toLocaleTimeString(locale, {timeStyle}); + } else { + // Format the date and time + const formatter = new Intl.DateTimeFormat(navigator.language, {dateStyle, timeStyle}); + return formatter.format(date); + } +} - return formatter.format(date); -} \ No newline at end of file From 83e1ce2bc4ecc1900b178ea0b0d536d10c456673 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:11:55 +0200 Subject: [PATCH 05/10] client: format dates and times in the "Recent Changes" section --- src/public/app/widgets/dialogs/recent_changes.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/public/app/widgets/dialogs/recent_changes.js b/src/public/app/widgets/dialogs/recent_changes.js index 99b255f5a..7a854d81e 100644 --- a/src/public/app/widgets/dialogs/recent_changes.js +++ b/src/public/app/widgets/dialogs/recent_changes.js @@ -1,13 +1,14 @@ +import { formatDate } from "../../utils/formatters.js" import { t } from "../../services/i18n.js"; -import linkService from '../../services/link.js'; -import utils from '../../services/utils.js'; -import server from '../../services/server.js'; -import froca from "../../services/froca.js"; import appContext from "../../components/app_context.js"; -import hoistedNoteService from "../../services/hoisted_note.js"; import BasicWidget from "../basic_widget.js"; import dialogService from "../../services/dialog.js"; +import froca from "../../services/froca.js"; +import hoistedNoteService from "../../services/hoisted_note.js"; +import linkService from '../../services/link.js'; +import server from '../../services/server.js'; import toastService from "../../services/toast.js"; +import utils from '../../services/utils.js'; import ws from "../../services/ws.js"; const TPL = ` @@ -71,10 +72,11 @@ export default class RecentChangesDialog extends BasicWidget { for (const [dateDay, dayChanges] of groupedByDate) { const $changesList = $('
    '); - const dayEl = $('
    ').append($('').text(dateDay)).append($changesList); + const formattedDate = formatDate(new Date(dateDay), "full", "none"); + const dayEl = $('
    ').append($('').text(formattedDate)).append($changesList); for (const change of dayChanges) { - const formattedTime = change.date.substr(11, 5); + const formattedTime = formatDate(new Date(change.date), "none", "short"); let $noteLink; From 19e40bf46b8071f75efded604c1b94f7e8f1ee3d Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:20:12 +0200 Subject: [PATCH 06/10] client: format dates and times in the "Note Info" widget --- src/public/app/widgets/ribbon_widgets/note_info_widget.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/ribbon_widgets/note_info_widget.js b/src/public/app/widgets/ribbon_widgets/note_info_widget.js index d6df63bd9..a45fe16eb 100644 --- a/src/public/app/widgets/ribbon_widgets/note_info_widget.js +++ b/src/public/app/widgets/ribbon_widgets/note_info_widget.js @@ -1,7 +1,9 @@ +import { formatDate } from "../../utils/formatters.js" +import { t } from "../../services/i18n.js"; import NoteContextAwareWidget from "../note_context_aware_widget.js"; import server from "../../services/server.js"; import utils from "../../services/utils.js"; -import { t } from "../../services/i18n.js"; + const TPL = `
    @@ -121,11 +123,11 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$noteId.text(note.noteId); this.$dateCreated - .text(metadata.dateCreated.substr(0, 16)) + .text(formatDate(new Date(metadata.dateCreated))) .attr("title", metadata.dateCreated); this.$dateModified - .text(metadata.dateModified.substr(0, 16)) + .text(formatDate(new Date(metadata.dateModified))) .attr("title", metadata.dateModified); this.$type.text(note.type); From 895d50694b13f641ee563c7d056ddf64ed8fefc6 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:24:41 +0200 Subject: [PATCH 07/10] client: format dates and times in the "About" section --- src/public/app/widgets/dialogs/about.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/dialogs/about.js b/src/public/app/widgets/dialogs/about.js index 794f26dc9..942487ca3 100644 --- a/src/public/app/widgets/dialogs/about.js +++ b/src/public/app/widgets/dialogs/about.js @@ -1,8 +1,9 @@ -import server from "../../services/server.js"; -import utils from "../../services/utils.js"; +import { formatDate } from "../../utils/formatters.js" import { t } from "../../services/i18n.js"; import BasicWidget from "../basic_widget.js"; import openService from "../../services/open.js"; +import server from "../../services/server.js"; +import utils from "../../services/utils.js"; const TPL = ` @@ -68,7 +69,7 @@ export default class AboutDialog extends BasicWidget { this.$appVersion.text(appInfo.appVersion); this.$dbVersion.text(appInfo.dbVersion); this.$syncVersion.text(appInfo.syncVersion); - this.$buildDate.text(appInfo.buildDate); + this.$buildDate.text(formatDate(new Date(appInfo.buildDate))); this.$buildRevision.text(appInfo.buildRevision); this.$buildRevision.attr('href', `https://github.com/TriliumNext/Notes/commit/${appInfo.buildRevision}`); if (utils.isElectron()) { From d7004bc3b58c51c2b6444d2088d1e65615be8981 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:40:24 +0200 Subject: [PATCH 08/10] client: allow date & time to be passed as a string to the date & time formatter, refactor --- src/public/app/utils/formatters.js | 22 ++++++++++++++----- src/public/app/widgets/dialogs/about.js | 4 ++-- .../app/widgets/dialogs/recent_changes.js | 6 ++--- .../ribbon_widgets/note_info_widget.js | 6 ++--- .../widgets/type_widgets/options/backup.js | 4 ++-- .../app/widgets/type_widgets/options/etapi.js | 4 ++-- 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/public/app/utils/formatters.js b/src/public/app/utils/formatters.js index 5e3473d8d..be89f0649 100644 --- a/src/public/app/utils/formatters.js +++ b/src/public/app/utils/formatters.js @@ -1,22 +1,32 @@ /** - * Formats the given date to a string based on the current locale. - * @param {Date | number} date + * Formats the given date and time to a string based on the current locale. + * @param {string | Date | number} date * @param {"full" | "long" | "medium" | "short" | "none" | undefined} dateStyle * @param {"full" | "long" | "medium" | "short" | "none" | undefined} tiemStyle */ -export function formatDate(date, dateStyle = "medium", timeStyle = "medium") { +export function formatDateTime(date, dateStyle = "medium", timeStyle = "medium") { const locale = navigator.language; + let parsedDate; + if (typeof date === "string") { + // Parse the given string as a date + parsedDate = new Date(date); + } else if (typeof date === "number" || date instanceof Date) { + parsedDate = date; + } else { + throw new TypeError(); + }; + if (timeStyle === "none") { // Format only the date - return date.toLocaleDateString(locale, {dateStyle}); + return parsedDate.toLocaleDateString(locale, {dateStyle}); } else if (dateStyle === "none") { // Format only the time - return date.toLocaleTimeString(locale, {timeStyle}); + return parsedDate.toLocaleTimeString(locale, {timeStyle}); } else { // Format the date and time const formatter = new Intl.DateTimeFormat(navigator.language, {dateStyle, timeStyle}); - return formatter.format(date); + return formatter.format(parsedDate); } } diff --git a/src/public/app/widgets/dialogs/about.js b/src/public/app/widgets/dialogs/about.js index 942487ca3..d58cb1091 100644 --- a/src/public/app/widgets/dialogs/about.js +++ b/src/public/app/widgets/dialogs/about.js @@ -1,4 +1,4 @@ -import { formatDate } from "../../utils/formatters.js" +import { formatDateTime } from "../../utils/formatters.js" import { t } from "../../services/i18n.js"; import BasicWidget from "../basic_widget.js"; import openService from "../../services/open.js"; @@ -69,7 +69,7 @@ export default class AboutDialog extends BasicWidget { this.$appVersion.text(appInfo.appVersion); this.$dbVersion.text(appInfo.dbVersion); this.$syncVersion.text(appInfo.syncVersion); - this.$buildDate.text(formatDate(new Date(appInfo.buildDate))); + this.$buildDate.text(formatDateTime(appInfo.buildDate)); this.$buildRevision.text(appInfo.buildRevision); this.$buildRevision.attr('href', `https://github.com/TriliumNext/Notes/commit/${appInfo.buildRevision}`); if (utils.isElectron()) { diff --git a/src/public/app/widgets/dialogs/recent_changes.js b/src/public/app/widgets/dialogs/recent_changes.js index 7a854d81e..515fdfaa5 100644 --- a/src/public/app/widgets/dialogs/recent_changes.js +++ b/src/public/app/widgets/dialogs/recent_changes.js @@ -1,4 +1,4 @@ -import { formatDate } from "../../utils/formatters.js" +import { formatDateTime } from "../../utils/formatters.js" import { t } from "../../services/i18n.js"; import appContext from "../../components/app_context.js"; import BasicWidget from "../basic_widget.js"; @@ -72,11 +72,11 @@ export default class RecentChangesDialog extends BasicWidget { for (const [dateDay, dayChanges] of groupedByDate) { const $changesList = $('
      '); - const formattedDate = formatDate(new Date(dateDay), "full", "none"); + const formattedDate = formatDateTime(dateDay, "full", "none"); const dayEl = $('
      ').append($('').text(formattedDate)).append($changesList); for (const change of dayChanges) { - const formattedTime = formatDate(new Date(change.date), "none", "short"); + const formattedTime = formatDateTime(change.date, "none", "short"); let $noteLink; diff --git a/src/public/app/widgets/ribbon_widgets/note_info_widget.js b/src/public/app/widgets/ribbon_widgets/note_info_widget.js index a45fe16eb..f66cb459a 100644 --- a/src/public/app/widgets/ribbon_widgets/note_info_widget.js +++ b/src/public/app/widgets/ribbon_widgets/note_info_widget.js @@ -1,4 +1,4 @@ -import { formatDate } from "../../utils/formatters.js" +import { formatDateTime } from "../../utils/formatters.js" import { t } from "../../services/i18n.js"; import NoteContextAwareWidget from "../note_context_aware_widget.js"; import server from "../../services/server.js"; @@ -123,11 +123,11 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$noteId.text(note.noteId); this.$dateCreated - .text(formatDate(new Date(metadata.dateCreated))) + .text(formatDateTime(metadata.dateCreated)) .attr("title", metadata.dateCreated); this.$dateModified - .text(formatDate(new Date(metadata.dateModified))) + .text(formatDateTime(metadata.dateModified)) .attr("title", metadata.dateModified); this.$type.text(note.type); diff --git a/src/public/app/widgets/type_widgets/options/backup.js b/src/public/app/widgets/type_widgets/options/backup.js index d6f8648b7..c110a9561 100644 --- a/src/public/app/widgets/type_widgets/options/backup.js +++ b/src/public/app/widgets/type_widgets/options/backup.js @@ -1,4 +1,4 @@ -import { formatDate } from "../../../utils/formatters.js" +import { formatDateTime } from "../../../utils/formatters.js" import { t } from "../../../services/i18n.js"; import OptionsWidget from "./options_widget.js"; import server from "../../../services/server.js"; @@ -119,7 +119,7 @@ export default class BackupOptions extends OptionsWidget { for (const {filePath, mtime} of backupFiles) { this.$existingBackupList.append($(` - ${(mtime) ? formatDate(new Date(mtime)) : "-"} + ${(mtime) ? formatDateTime(mtime) : "-"} ${filePath} `)); diff --git a/src/public/app/widgets/type_widgets/options/etapi.js b/src/public/app/widgets/type_widgets/options/etapi.js index 4976d97ac..b2d939743 100644 --- a/src/public/app/widgets/type_widgets/options/etapi.js +++ b/src/public/app/widgets/type_widgets/options/etapi.js @@ -1,4 +1,4 @@ -import { formatDate } from "../../../utils/formatters.js" +import { formatDateTime } from "../../../utils/formatters.js" import { t } from "../../../services/i18n.js"; import dialogService from "../../../services/dialog.js"; import OptionsWidget from "./options_widget.js"; @@ -96,7 +96,7 @@ export default class EtapiOptions extends OptionsWidget { $tokensTableBody.append( $("") .append($("").text(token.name)) - .append($("").text(formatDate(new Date(token.utcDateCreated)))) + .append($("").text(formatDateTime(token.utcDateCreated))) .append($("").append( $(``) .on("click", () => this.renameToken(token.etapiTokenId, token.name)), From 89334691b7d512b739b8ac0db7f9d548a2beabfb Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:43:51 +0200 Subject: [PATCH 09/10] client: fix a typo --- src/public/app/utils/formatters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/utils/formatters.js b/src/public/app/utils/formatters.js index be89f0649..2c996bb80 100644 --- a/src/public/app/utils/formatters.js +++ b/src/public/app/utils/formatters.js @@ -2,7 +2,7 @@ * Formats the given date and time to a string based on the current locale. * @param {string | Date | number} date * @param {"full" | "long" | "medium" | "short" | "none" | undefined} dateStyle - * @param {"full" | "long" | "medium" | "short" | "none" | undefined} tiemStyle + * @param {"full" | "long" | "medium" | "short" | "none" | undefined} timeStyle */ export function formatDateTime(date, dateStyle = "medium", timeStyle = "medium") { const locale = navigator.language; From 74ace248d5dde8a32e37e50bbf2f858d75a379f4 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Tue, 10 Dec 2024 18:48:48 +0200 Subject: [PATCH 10/10] client: date formatter utility: improve --- src/public/app/utils/formatters.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/public/app/utils/formatters.js b/src/public/app/utils/formatters.js index 2c996bb80..638404c89 100644 --- a/src/public/app/utils/formatters.js +++ b/src/public/app/utils/formatters.js @@ -12,9 +12,11 @@ export function formatDateTime(date, dateStyle = "medium", timeStyle = "medium") // Parse the given string as a date parsedDate = new Date(date); } else if (typeof date === "number" || date instanceof Date) { + // The given date is already a Date instance or a number parsedDate = date; } else { - throw new TypeError(); + // Invalid type + throw new TypeError(`Invalid type for the "date" argument.`); }; if (timeStyle === "none") {