From d26e8758ca339fa1740922f61d45af89d90a71b1 Mon Sep 17 00:00:00 2001 From: iamvann Date: Fri, 16 May 2025 23:20:02 +0800 Subject: [PATCH] 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() {