From 5da0053f6a47a28d13848936047f109a250cdce2 Mon Sep 17 00:00:00 2001
From: iamvann
Date: Fri, 16 May 2025 22:42:08 +0800
Subject: [PATCH 1/4] options (setting) feature: add UI for cutom date time
format (Alt+t) under options/Text Notes
---
.../widgets/type_widgets/content_widget.js | 2 +
.../options/text_notes/date_time_format.js | 74 +++++++++++++++++++
2 files changed, 76 insertions(+)
create mode 100644 src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
diff --git a/src/public/app/widgets/type_widgets/content_widget.js b/src/public/app/widgets/type_widgets/content_widget.js
index fe7f105af..aaa33470f 100644
--- a/src/public/app/widgets/type_widgets/content_widget.js
+++ b/src/public/app/widgets/type_widgets/content_widget.js
@@ -8,6 +8,7 @@ import KeyboardShortcutsOptions from "./options/shortcuts.js";
import HeadingStyleOptions from "./options/text_notes/heading_style.js";
import TableOfContentsOptions from "./options/text_notes/table_of_contents.js";
import HighlightsListOptions from "./options/text_notes/highlights_list.js";
+import DateTimeFormatOptions from "./options/text_notes/date_time_format.js";
import TextAutoReadOnlySizeOptions from "./options/text_notes/text_auto_read_only_size.js";
import VimKeyBindingsOptions from "./options/code_notes/vim_key_bindings.js";
import WrapLinesOptions from "./options/code_notes/wrap_lines.js";
@@ -66,6 +67,7 @@ const CONTENT_WIDGETS = {
HeadingStyleOptions,
TableOfContentsOptions,
HighlightsListOptions,
+ DateTimeFormatOptions,
TextAutoReadOnlySizeOptions
],
_optionsCodeNotes: [
diff --git a/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
new file mode 100644
index 000000000..5bf427778
--- /dev/null
+++ b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
@@ -0,0 +1,74 @@
+import OptionsWidget from "../options_widget.js";
+
+const TPL = `
+
+
Custom Date/Time Format (Alt+T)
+
+
+ Define a custom format for the date and time inserted using the Alt+T shortcut.
+ Uses Day.js format tokens.
+ Refer to the Day.js documentation for valid tokens.
+
+
+ Important: If you provide a string that Day.js cannot interpret as a format,
+ the literal string you typed might be inserted. If the format string is empty, or if Day.js
+ encounters an internal error with your format, a default format (e.g., YYYY-MM-DD HH:mm) will be used.
+
+`;
+
+export default class DateTimeFormatOptions extends OptionsWidget {
+ doRender() {
+ this.$widget = $(TPL);
+ this.$formatInput = this.$widget.find(
+ "input.custom-datetime-format-input"
+ );
+
+ //listen to input
+ this.$formatInput.on("input", () => {
+ const formatString = this.$formatInput.val();
+
+ this.updateOption("customDateTimeFormatString", formatString);
+ });
+
+ return this.$widget; //render method to return the widget
+ }
+
+ async optionsLoaded(options) {
+ //todo: update the key in updateOption
+ const currentFormat = options.customDateTimeFormatString || "";
+
+
+ if (this.$formatInput) {
+ this.$formatInput.val(currentFormat);
+ } else {
+
+ console.warn(
+ "DateTimeFormatOptions: $formatInput not initialized when optionsLoaded was called. Attempting to find again."
+ );
+ const inputField = this.$widget.find(
+ "input.custom-datetime-format-input"
+ );
+ if (inputField.length) {
+ this.$formatInput = inputField;
+ this.$formatInput.val(currentFormat);
+ } else {
+ console.error(
+ "DateTimeFormatOptions: Could not find format input field in optionsLoaded."
+ );
+ }
+ }
+ }
+}
From d26e8758ca339fa1740922f61d45af89d90a71b1 Mon Sep 17 00:00:00 2001
From: iamvann
Date: Fri, 16 May 2025 23:20:02 +0800
Subject: [PATCH 2/4] implement custom date/time formatting for Alt + T
---
src/public/app/services/utils.js | 28 +++++++++-
.../app/widgets/type_widgets/editable_text.js | 55 +++++++++++++------
.../options/text_notes/date_time_format.js | 1 -
src/routes/api/options.js | 3 +-
4 files changed, 65 insertions(+), 22 deletions(-)
diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js
index b88146012..59e7f22c4 100644
--- a/src/public/app/services/utils.js
+++ b/src/public/app/services/utils.js
@@ -73,8 +73,32 @@ function formatDateISO(date) {
return `${date.getFullYear()}-${padNum(date.getMonth() + 1)}-${padNum(date.getDate())}`;
}
-function formatDateTime(date) {
- return `${formatDate(date)} ${formatTime(date)}`;
+// old version
+// function formatDateTime(date) {
+// return `${formatDate(date)} ${formatTime(date)}`;
+// }
+
+// In utils.js
+// import dayjs from 'dayjs'; // Assuming dayjs is available in this scope
+
+function formatDateTime(date, userSuppliedFormat) {
+ const DEFAULT_FORMAT = 'YYYY-MM-DD HH:mm';
+ let formatToUse = DEFAULT_FORMAT;
+
+ if (userSuppliedFormat && typeof userSuppliedFormat === 'string' && userSuppliedFormat.trim() !== "") {
+ formatToUse = userSuppliedFormat.trim();
+ }
+
+ if (!date) {
+ date = new Date();
+ }
+
+ try {
+ return dayjs(date).format(formatToUse);
+ } catch (e) {
+ console.warn(`Trilium: Day.js encountered an error with format string "${formatToUse}". Falling back to default. Error: ${e.message}`);
+ return dayjs(date).format(DEFAULT_FORMAT);
+ }
}
function localNowDateTime() {
diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js
index 48cb041aa..1867a58d9 100644
--- a/src/public/app/widgets/type_widgets/editable_text.js
+++ b/src/public/app/widgets/type_widgets/editable_text.js
@@ -109,9 +109,9 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
(await mimeTypesService.getMimeTypes())
.filter(mt => mt.enabled)
.map(mt => ({
- language: mt.mime.toLowerCase().replace(/[\W_]+/g,"-"),
- label: mt.title
- }));
+ language: mt.mime.toLowerCase().replace(/[\W_]+/g, "-"),
+ label: mt.title
+ }));
// CKEditor since version 12 needs the element to be visible before initialization. At the same time,
// we want to avoid flicker - i.e., show editor only once everything is ready. That's why we have separate
@@ -211,7 +211,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
this.watchdog?.editor.editing.view.focus();
}
- show() {}
+ show() { }
getEditor() {
return this.watchdog?.editor;
@@ -225,10 +225,29 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
}
}
- insertDateTimeToTextCommand() {
- const date = new Date();
- const dateString = utils.formatDateTime(date);
+ // old version
+ // insertDateTimeToTextCommand() {
+ // const date = new Date();
+ // const dateString = utils.formatDateTime(date);
+ // this.addTextToEditor(dateString);
+ // }
+
+ // new version
+ async insertDateTimeToTextCommand() {
+ const date = new Date();
+ let userPreferredFormat = ""; //Default
+
+ try {
+ const allOptions = await server.get('options');
+
+ if (allOptions && typeof allOptions.customDateTimeFormatString === 'string') {
+ userPreferredFormat = allOptions.customDateTimeFormatString;
+ }
+ } catch (e) {
+ console.error("Trilium: Failed to fetch options for custom date/time format. Using default.", e);
+ }
+ const dateString = utils.formatDateTime(date, userPreferredFormat);
this.addTextToEditor(dateString);
}
@@ -237,7 +256,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
this.watchdog.editor.model.change(writer => {
const insertPosition = this.watchdog.editor.model.document.selection.getFirstPosition();
- writer.insertText(linkTitle, {linkHref: linkHref}, insertPosition);
+ writer.insertText(linkTitle, { linkHref: linkHref }, insertPosition);
});
}
@@ -250,7 +269,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
});
}
- addTextToActiveEditorEvent({text}) {
+ addTextToActiveEditorEvent({ text }) {
if (!this.isActive()) {
return;
}
@@ -283,7 +302,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
return !selection.isCollapsed;
}
- async executeWithTextEditorEvent({callback, resolve, ntxId}) {
+ async executeWithTextEditorEvent({ callback, resolve, ntxId }) {
if (!this.isNoteContext(ntxId)) {
return;
}
@@ -300,7 +319,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
addLinkToTextCommand() {
const selectedText = this.getSelectedText();
- this.triggerCommand('showAddLinkDialog', {textTypeWidget: this, text: selectedText})
+ this.triggerCommand('showAddLinkDialog', { textTypeWidget: this, text: selectedText })
}
getSelectedText() {
@@ -347,29 +366,29 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
}
addIncludeNoteToTextCommand() {
- this.triggerCommand("showIncludeNoteDialog", {textTypeWidget: this});
+ this.triggerCommand("showIncludeNoteDialog", { textTypeWidget: this });
}
addIncludeNote(noteId, boxSize) {
- this.watchdog.editor.model.change( writer => {
+ this.watchdog.editor.model.change(writer => {
// Insert * at the current selection position
// in a way that will result in creating a valid model structure
this.watchdog.editor.model.insertContent(writer.createElement('includeNote', {
noteId: noteId,
boxSize: boxSize
}));
- } );
+ });
}
async addImage(noteId) {
const note = await froca.getNote(noteId);
- this.watchdog.editor.model.change( writer => {
+ this.watchdog.editor.model.change(writer => {
const encodedTitle = encodeURIComponent(note.title);
const src = `api/images/${note.noteId}/${encodedTitle}`;
- this.watchdog.editor.execute( 'insertImage', { source: src } );
- } );
+ this.watchdog.editor.execute('insertImage', { source: src });
+ });
}
async createNoteForReferenceLink(title) {
@@ -385,7 +404,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
return resp.note.getBestNotePathString();
}
- async refreshIncludedNoteEvent({noteId}) {
+ async refreshIncludedNoteEvent({ noteId }) {
this.refreshIncludedNote(this.$editor, noteId);
}
}
diff --git a/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
index 5bf427778..96d70665e 100644
--- a/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
+++ b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
@@ -47,7 +47,6 @@ export default class DateTimeFormatOptions extends OptionsWidget {
}
async optionsLoaded(options) {
- //todo: update the key in updateOption
const currentFormat = options.customDateTimeFormatString || "";
diff --git a/src/routes/api/options.js b/src/routes/api/options.js
index efd70a07e..5f317945b 100644
--- a/src/routes/api/options.js
+++ b/src/routes/api/options.js
@@ -57,7 +57,8 @@ const ALLOWED_OPTIONS = new Set([
'customSearchEngineName',
'customSearchEngineUrl',
'promotedAttributesOpenInRibbon',
- 'editedNotesOpenInRibbon'
+ 'editedNotesOpenInRibbon',
+ 'customDateTimeFormatString'
]);
function getOptions() {
From 26f6c28c71553725221b89f3fabb890ccc536c64 Mon Sep 17 00:00:00 2001
From: iamvann
Date: Fri, 16 May 2025 23:27:25 +0800
Subject: [PATCH 3/4] fix: add import server to editable_text.js
---
src/public/app/services/utils.js | 12 +++++++-----
src/public/app/widgets/type_widgets/editable_text.js | 1 +
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js
index 59e7f22c4..99871035a 100644
--- a/src/public/app/services/utils.js
+++ b/src/public/app/services/utils.js
@@ -81,23 +81,25 @@ function formatDateISO(date) {
// In utils.js
// import dayjs from 'dayjs'; // Assuming dayjs is available in this scope
+// new version
function formatDateTime(date, userSuppliedFormat) {
- const DEFAULT_FORMAT = 'YYYY-MM-DD HH:mm';
- let formatToUse = DEFAULT_FORMAT;
+ let formatToUse;
if (userSuppliedFormat && typeof userSuppliedFormat === 'string' && userSuppliedFormat.trim() !== "") {
formatToUse = userSuppliedFormat.trim();
+ } else {
+ formatToUse = 'YYYY-MM-DD HH:mm'; // Trilium's default format
}
if (!date) {
- date = new Date();
+ date = new Date();
}
try {
return dayjs(date).format(formatToUse);
} catch (e) {
- console.warn(`Trilium: Day.js encountered an error with format string "${formatToUse}". Falling back to default. Error: ${e.message}`);
- return dayjs(date).format(DEFAULT_FORMAT);
+ console.warn(`Day.js: Invalid format string "${formatToUse}". Falling back. Error:`, e.message);
+ return dayjs(date).format('YYYY-MM-DD HH:mm');
}
}
diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js
index 1867a58d9..897add401 100644
--- a/src/public/app/widgets/type_widgets/editable_text.js
+++ b/src/public/app/widgets/type_widgets/editable_text.js
@@ -9,6 +9,7 @@ import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
import link from "../../services/link.js";
import appContext from "../../components/app_context.js";
import dialogService from "../../services/dialog.js";
+import server from '../../services/server.js';
const ENABLE_INSPECTOR = false;
From 2844331f1043137d57e0ada0441e89689900dbbc Mon Sep 17 00:00:00 2001
From: iamvann
Date: Sat, 17 May 2025 01:26:26 +0800
Subject: [PATCH 4/4] docs(options):Ensures UI descriptions accurately reflect
Day.js handling of unrecognized format
---
.../options/text_notes/date_time_format.js | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
index 96d70665e..7eb5916c3 100644
--- a/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
+++ b/src/public/app/widgets/type_widgets/options/text_notes/date_time_format.js
@@ -9,11 +9,13 @@ const TPL = `
Uses Day.js format tokens.
Refer to the Day.js documentation for valid tokens.
-
- Important: If you provide a string that Day.js cannot interpret as a format,
- the literal string you typed might be inserted. If the format string is empty, or if Day.js
- encounters an internal error with your format, a default format (e.g., YYYY-MM-DD HH:mm) will be used.
-
+
+ Important: If you provide a format string that Day.js does not recognize
+ (e.g., mostly plain text without valid Day.js tokens),
+ the text you typed might be inserted literally. If the format string is left empty,
+ or if Day.js encounters a critical internal error with your format,
+ a default format (e.g., YYYY-MM-DD HH:mm) will be used.
+