mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
Merge pull request #2083 from TriliumNext/date/time
feat: Add configurable date/time format for Alt+T shortcut
This commit is contained in:
commit
0af1c8b3be
@ -115,6 +115,7 @@ function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
|
|||||||
export default {
|
export default {
|
||||||
updateDisplayedShortcuts,
|
updateDisplayedShortcuts,
|
||||||
setupActionsForElement,
|
setupActionsForElement,
|
||||||
|
getAction,
|
||||||
getActions,
|
getActions,
|
||||||
getActionsForScope
|
getActionsForScope
|
||||||
};
|
};
|
||||||
|
@ -124,8 +124,12 @@ function formatDateISO(date: Date) {
|
|||||||
return `${date.getFullYear()}-${padNum(date.getMonth() + 1)}-${padNum(date.getDate())}`;
|
return `${date.getFullYear()}-${padNum(date.getMonth() + 1)}-${padNum(date.getDate())}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDateTime(date: Date) {
|
function formatDateTime(date: Date, userSuppliedFormat?: string): string {
|
||||||
return `${formatDate(date)} ${formatTime(date)}`;
|
if (userSuppliedFormat?.trim()) {
|
||||||
|
return dayjs(date).format(userSuppliedFormat);
|
||||||
|
} else {
|
||||||
|
return `${formatDate(date)} ${formatTime(date)}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function localNowDateTime() {
|
function localNowDateTime() {
|
||||||
|
@ -1431,6 +1431,12 @@
|
|||||||
"label": "Automatic read-only size (text notes)",
|
"label": "Automatic read-only size (text notes)",
|
||||||
"unit": "characters"
|
"unit": "characters"
|
||||||
},
|
},
|
||||||
|
"custom_date_time_format": {
|
||||||
|
"title": "Custom Date/Time Format",
|
||||||
|
"description": "Customize the format of the date and time inserted via <kbd></kbd> or the toolbar. See <a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Day.js docs</a> for available format tokens.",
|
||||||
|
"format_string": "Format string:",
|
||||||
|
"formatted_time": "Formatted date/time:"
|
||||||
|
},
|
||||||
"i18n": {
|
"i18n": {
|
||||||
"title": "Localization",
|
"title": "Localization",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
|
@ -189,7 +189,7 @@ export function buildClassicToolbar(multilineToolbar: boolean) {
|
|||||||
{
|
{
|
||||||
label: "Insert",
|
label: "Insert",
|
||||||
icon: "plus",
|
icon: "plus",
|
||||||
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak"]
|
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||||
},
|
},
|
||||||
"|",
|
"|",
|
||||||
"outdent",
|
"outdent",
|
||||||
@ -222,6 +222,7 @@ export function buildFloatingToolbar() {
|
|||||||
"|",
|
"|",
|
||||||
"code",
|
"code",
|
||||||
"link",
|
"link",
|
||||||
|
"bookmark",
|
||||||
"removeFormat",
|
"removeFormat",
|
||||||
"internallink",
|
"internallink",
|
||||||
"cuttonote"
|
"cuttonote"
|
||||||
@ -243,7 +244,7 @@ export function buildFloatingToolbar() {
|
|||||||
{
|
{
|
||||||
label: "Insert",
|
label: "Insert",
|
||||||
icon: "plus",
|
icon: "plus",
|
||||||
items: ["bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak"]
|
items: ["bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||||
},
|
},
|
||||||
"|",
|
"|",
|
||||||
"outdent",
|
"outdent",
|
||||||
|
@ -8,6 +8,7 @@ import HeadingStyleOptions from "./options/text_notes/heading_style.js";
|
|||||||
import TableOfContentsOptions from "./options/text_notes/table_of_contents.js";
|
import TableOfContentsOptions from "./options/text_notes/table_of_contents.js";
|
||||||
import HighlightsListOptions from "./options/text_notes/highlights_list.js";
|
import HighlightsListOptions from "./options/text_notes/highlights_list.js";
|
||||||
import TextAutoReadOnlySizeOptions from "./options/text_notes/text_auto_read_only_size.js";
|
import TextAutoReadOnlySizeOptions from "./options/text_notes/text_auto_read_only_size.js";
|
||||||
|
import DateTimeFormatOptions from "./options/text_notes/date_time_format.js";
|
||||||
import CodeEditorOptions from "./options/code_notes/code_editor.js";
|
import CodeEditorOptions from "./options/code_notes/code_editor.js";
|
||||||
import CodeAutoReadOnlySizeOptions from "./options/code_notes/code_auto_read_only_size.js";
|
import CodeAutoReadOnlySizeOptions from "./options/code_notes/code_auto_read_only_size.js";
|
||||||
import CodeMimeTypesOptions from "./options/code_notes/code_mime_types.js";
|
import CodeMimeTypesOptions from "./options/code_notes/code_mime_types.js";
|
||||||
@ -88,7 +89,8 @@ const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", (typeof NoteContextAw
|
|||||||
CodeBlockOptions,
|
CodeBlockOptions,
|
||||||
TableOfContentsOptions,
|
TableOfContentsOptions,
|
||||||
HighlightsListOptions,
|
HighlightsListOptions,
|
||||||
TextAutoReadOnlySizeOptions
|
TextAutoReadOnlySizeOptions,
|
||||||
|
DateTimeFormatOptions
|
||||||
],
|
],
|
||||||
_optionsCodeNotes: [
|
_optionsCodeNotes: [
|
||||||
CodeEditorOptions,
|
CodeEditorOptions,
|
||||||
|
@ -266,7 +266,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
item.on("change:isOpen", () => {
|
item.on("change:isOpen", () => {
|
||||||
if (!("isOpen" in item) || !item.isOpen ) {
|
if (!("isOpen" in item) || !item.isOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,9 +375,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
insertDateTimeToTextCommand() {
|
insertDateTimeToTextCommand() {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const dateString = utils.formatDateTime(date);
|
const customDateTimeFormat = options.get("customDateTimeFormat");
|
||||||
|
const dateString = utils.formatDateTime(date, customDateTimeFormat);
|
||||||
|
|
||||||
this.addTextToEditor(dateString);
|
this.addTextToEditor(dateString);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
import OptionsWidget from "../options_widget.js";
|
||||||
|
import { t } from "../../../../services/i18n.js";
|
||||||
|
import type { OptionMap } from "@triliumnext/commons";
|
||||||
|
import utils from "../../../../services/utils.js";
|
||||||
|
import keyboardActionsService from "../../../../services/keyboard_actions.js";
|
||||||
|
import linkService from "../../../.././services/link.js";
|
||||||
|
|
||||||
|
const TPL = /*html*/`
|
||||||
|
<div class="options-section">
|
||||||
|
<h4>${t("custom_date_time_format.title")}</h4>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
${t("custom_date_time_format.description")}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="form-group row align-items-center">
|
||||||
|
<div class="col-6">
|
||||||
|
<label for="custom-date-time-format">${t("custom_date_time_format.format_string")}</label>
|
||||||
|
<input type="text" id="custom-date-time-format" class="form-control custom-date-time-format" placeholder="YYYY-MM-DD HH:mm">
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label>${t("custom_date_time_format.formatted_time")}</label>
|
||||||
|
<div class="formatted-date"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default class DateTimeFormatOptions extends OptionsWidget {
|
||||||
|
|
||||||
|
private $formatInput!: JQuery<HTMLInputElement>;
|
||||||
|
private $formattedDate!: JQuery<HTMLInputElement>;
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
this.$widget = $(TPL);
|
||||||
|
|
||||||
|
this.$formatInput = this.$widget.find("input.custom-date-time-format");
|
||||||
|
this.$formattedDate = this.$widget.find(".formatted-date");
|
||||||
|
|
||||||
|
this.$formatInput.on("input", () => {
|
||||||
|
const dateString = utils.formatDateTime(new Date(), this.$formatInput.val());
|
||||||
|
this.$formattedDate.text(dateString);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$formatInput.on('blur keydown', (e) => {
|
||||||
|
if (e.type === 'blur' || (e.type === 'keydown' && e.key === 'Enter')) {
|
||||||
|
this.updateOption("customDateTimeFormat", this.$formatInput.val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.$widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
async optionsLoaded(options: OptionMap) {
|
||||||
|
const shortcutKey = (await keyboardActionsService.getAction("insertDateTimeToText")).effectiveShortcuts.join(", ");
|
||||||
|
const $link = await linkService.createLink("_hidden/_options/_optionsShortcuts", {
|
||||||
|
"title": shortcutKey,
|
||||||
|
"showTooltip": false
|
||||||
|
});
|
||||||
|
this.$widget.find(".description").find("kbd").replaceWith($link);
|
||||||
|
|
||||||
|
const customDateTimeFormat = options.customDateTimeFormat || "YYYY-MM-DD HH:mm";
|
||||||
|
this.$formatInput.val(customDateTimeFormat);
|
||||||
|
const dateString = utils.formatDateTime(new Date(), customDateTimeFormat);
|
||||||
|
this.$formattedDate.text(dateString);
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,7 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
|
|||||||
"headingStyle",
|
"headingStyle",
|
||||||
"autoCollapseNoteTree",
|
"autoCollapseNoteTree",
|
||||||
"autoReadonlySizeText",
|
"autoReadonlySizeText",
|
||||||
|
"customDateTimeFormat",
|
||||||
"autoReadonlySizeCode",
|
"autoReadonlySizeCode",
|
||||||
"overrideThemeFonts",
|
"overrideThemeFonts",
|
||||||
"dailyBackupEnabled",
|
"dailyBackupEnabled",
|
||||||
|
12
packages/ckeditor5/src/icons/date-time.svg
Normal file
12
packages/ckeditor5/src/icons/date-time.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||||
|
<path d="M43.6,6.8h-4V5.2c0-1.8-1.4-3.2-3.2-3.2c-1.8,0-3.2,1.4-3.2,3.2v1.6H18.8V5.2c0-1.8-1.4-3.2-3.2-3.2
|
||||||
|
s-3.2,1.4-3.2,3.2v1.6h-4c-2.6,0-4.8,2.2-4.8,4.8v1.6c0,0.9,0.7,1.6,1.6,1.6h41.6c0.9,0,1.6-0.7,1.6-1.6v-1.6
|
||||||
|
C48.4,9,46.2,6.8,43.6,6.8z"/>
|
||||||
|
<path d="M46.8,19.6H5.2c-0.9,0-1.6,0.7-1.6,1.6v24c0,2.6,2.2,4.8,4.8,4.8h35.2c2.6,0,4.8-2.2,4.8-4.8v-24
|
||||||
|
C48.4,20.3,47.7,19.6,46.8,19.6z M26,46.7c-6.6,0-11.9-5.4-11.9-11.9c0-6.6,5.4-11.9,11.9-11.9s11.9,5.4,11.9,11.9
|
||||||
|
C37.9,41.4,32.6,46.7,26,46.7z"/>
|
||||||
|
<path d="M27.2,34.3v-5.1c0-0.4-0.4-0.8-0.8-0.8h-0.8c-0.4,0-0.8,0.4-0.8,0.8v5.6c0,0.3,0.1,0.6,0.4,0.8l3.8,3.8
|
||||||
|
c0.3,0.3,0.8,0.3,1.1,0l0.6-0.6c0.3-0.3,0.3-0.8,0-1.1L27.2,34.3z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 958 B |
@ -5,6 +5,7 @@ import UploadimagePlugin from "./plugins/uploadimage.js";
|
|||||||
import ItalicAsEmPlugin from "./plugins/italic_as_em.js";
|
import ItalicAsEmPlugin from "./plugins/italic_as_em.js";
|
||||||
import StrikethroughAsDel from "./plugins/strikethrough_as_del.js";
|
import StrikethroughAsDel from "./plugins/strikethrough_as_del.js";
|
||||||
import InternalLinkPlugin from "./plugins/internallink.js";
|
import InternalLinkPlugin from "./plugins/internallink.js";
|
||||||
|
import InsertDateTimePlugin from "./plugins/insert_date_time.js";
|
||||||
import ReferenceLink from "./plugins/referencelink.js";
|
import ReferenceLink from "./plugins/referencelink.js";
|
||||||
import RemoveFormatLinksPlugin from "./plugins/remove_format_links.js";
|
import RemoveFormatLinksPlugin from "./plugins/remove_format_links.js";
|
||||||
import IndentBlockShortcutPlugin from "./plugins/indent_block_shortcut.js";
|
import IndentBlockShortcutPlugin from "./plugins/indent_block_shortcut.js";
|
||||||
@ -36,6 +37,7 @@ const TRILIUM_PLUGINS: typeof Plugin[] = [
|
|||||||
ItalicAsEmPlugin,
|
ItalicAsEmPlugin,
|
||||||
StrikethroughAsDel,
|
StrikethroughAsDel,
|
||||||
InternalLinkPlugin,
|
InternalLinkPlugin,
|
||||||
|
InsertDateTimePlugin,
|
||||||
RemoveFormatLinksPlugin,
|
RemoveFormatLinksPlugin,
|
||||||
IndentBlockShortcutPlugin,
|
IndentBlockShortcutPlugin,
|
||||||
MarkdownImportPlugin,
|
MarkdownImportPlugin,
|
||||||
|
31
packages/ckeditor5/src/plugins/insert_date_time.ts
Normal file
31
packages/ckeditor5/src/plugins/insert_date_time.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { ButtonView, Plugin } from 'ckeditor5';
|
||||||
|
import dateTimeIcon from '../icons/date-time.svg?raw';
|
||||||
|
|
||||||
|
export default class InsertDateTimePlugin extends Plugin {
|
||||||
|
init() {
|
||||||
|
const editor = this.editor;
|
||||||
|
|
||||||
|
editor.ui.componentFactory.add('dateTime', locale => {
|
||||||
|
const view = new ButtonView( locale );
|
||||||
|
|
||||||
|
view.set( {
|
||||||
|
label: 'Date time',
|
||||||
|
icon: dateTimeIcon,
|
||||||
|
tooltip: true
|
||||||
|
} );
|
||||||
|
|
||||||
|
// enable internal link only if the editor is not read only
|
||||||
|
view.bind('isEnabled').to(editor, 'isReadOnly', isReadOnly => !isReadOnly);
|
||||||
|
|
||||||
|
view.on('execute', () => {
|
||||||
|
const editorEl = editor.editing.view.getDomRoot();
|
||||||
|
const component = glob.getComponentByEl(editorEl);
|
||||||
|
|
||||||
|
component.triggerCommand('insertDateTimeToText');
|
||||||
|
editor.editing.view.focus();
|
||||||
|
} );
|
||||||
|
|
||||||
|
return view;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,7 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi
|
|||||||
passwordDerivedKeySalt: string;
|
passwordDerivedKeySalt: string;
|
||||||
encryptedDataKey: string;
|
encryptedDataKey: string;
|
||||||
hoistedNoteId: string;
|
hoistedNoteId: string;
|
||||||
|
customDateTimeFormat: string;
|
||||||
|
|
||||||
// Multi-Factor Authentication
|
// Multi-Factor Authentication
|
||||||
mfaEnabled: boolean;
|
mfaEnabled: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user