From d4188127b311c4e746f330c4f1005a4ce6d07dc2 Mon Sep 17 00:00:00 2001 From: hen Date: Thu, 14 Nov 2024 00:52:05 -0300 Subject: [PATCH] add total today --- src/tracker.ts | 451 ++++++++++++++++++++++++++----------------------- 1 file changed, 241 insertions(+), 210 deletions(-) diff --git a/src/tracker.ts b/src/tracker.ts index 48476a1..07b042f 100644 --- a/src/tracker.ts +++ b/src/tracker.ts @@ -1,327 +1,358 @@ -import { moment, MarkdownSectionInformation, ButtonComponent, TextComponent, TFile, MarkdownRenderer, Component, MarkdownRenderChild } from "obsidian"; -import { SimpleTimeTrackerSettings } from "./settings"; -import { ConfirmModal } from "./confirm-modal"; +import { moment, MarkdownSectionInformation, ButtonComponent, TextComponent, TFile, MarkdownRenderer, Component, MarkdownRenderChild } from "obsidian" +import { SimpleTimeTrackerSettings } from "./settings" +import { ConfirmModal } from "./confirm-modal" export interface Tracker { - entries: Entry[]; + entries: Entry[] } export interface Entry { - name: string; - startTime: string; - endTime: string; - subEntries?: Entry[]; - collapsed?: boolean; + name: string + startTime: string + endTime: string + subEntries?: Entry[] + collapsed?: boolean } export async function saveTracker(tracker: Tracker, fileName: string, section: MarkdownSectionInformation): Promise { - let file = app.vault.getAbstractFileByPath(fileName) as TFile; + let file = app.vault.getAbstractFileByPath(fileName) as TFile if (!file) - return; - let content = await app.vault.read(file); + return + let content = await app.vault.read(file) // figure out what part of the content we have to edit - let lines = content.split("\n"); - let prev = lines.filter((_, i) => i <= section.lineStart).join("\n"); - let next = lines.filter((_, i) => i >= section.lineEnd).join("\n"); + let lines = content.split("\n") + let prev = lines.filter((_, i) => i <= section.lineStart).join("\n") + let next = lines.filter((_, i) => i >= section.lineEnd).join("\n") // edit only the code block content, leave the rest untouched - content = `${prev}\n${JSON.stringify(tracker)}\n${next}`; + content = `${prev}\n${JSON.stringify(tracker)}\n${next}` - await app.vault.modify(file, content); + await app.vault.modify(file, content) } export function loadTracker(json: string): Tracker { if (json) { try { - let ret = JSON.parse(json); - updateLegacyInfo(ret.entries); - return ret; + let ret = JSON.parse(json) + updateLegacyInfo(ret.entries) + return ret } catch (e) { - console.log(`Failed to parse Tracker from ${json}`); + console.log(`Failed to parse Tracker from ${json}`) } } - return { entries: [] }; + return { entries: [] } } export async function loadAllTrackers(fileName: string): Promise<{ section: MarkdownSectionInformation, tracker: Tracker }[]> { - let file = app.vault.getAbstractFileByPath(fileName); - let content = (await app.vault.cachedRead(file as TFile)).split("\n"); + let file = app.vault.getAbstractFileByPath(fileName) + let content = (await app.vault.cachedRead(file as TFile)).split("\n") - let trackers: { section: MarkdownSectionInformation, tracker: Tracker }[] = []; - let curr: Partial | undefined; + let trackers: { section: MarkdownSectionInformation, tracker: Tracker }[] = [] + let curr: Partial | undefined for (let i = 0; i < content.length; i++) { - let line = content[i]; + let line = content[i] if (line.trimEnd() == "```simple-time-tracker") { - curr = { lineStart: i + 1, text: "" }; + curr = { lineStart: i + 1, text: "" } } else if (curr) { if (line.trimEnd() == "```") { - curr.lineEnd = i - 1; - let tracker = loadTracker(curr.text); - trackers.push({ section: curr as MarkdownSectionInformation, tracker: tracker }); - curr = undefined; + curr.lineEnd = i - 1 + let tracker = loadTracker(curr.text) + trackers.push({ section: curr as MarkdownSectionInformation, tracker: tracker }) + curr = undefined } else { - curr.text += `${line}\n`; + curr.text += `${line}\n` } } } - return trackers; + return trackers } -type GetFile = () => string; +type GetFile = () => string export function displayTracker(tracker: Tracker, element: HTMLElement, getFile: GetFile, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings, component: MarkdownRenderChild): void { - element.addClass("simple-time-tracker-container"); + element.addClass("simple-time-tracker-container") // add start/stop controls - let running = isRunning(tracker); + let running = isRunning(tracker) let btn = new ButtonComponent(element) .setClass("clickable-icon") .setIcon(`lucide-${running ? "stop" : "play"}-circle`) .setTooltip(running ? "End" : "Start") .onClick(async () => { if (running) { - endRunningEntry(tracker); + endRunningEntry(tracker) } else { - startNewEntry(tracker, newSegmentNameBox.getValue()); + startNewEntry(tracker, newSegmentNameBox.getValue()) } - await saveTracker(tracker, getFile(), getSectionInfo()); - }); - btn.buttonEl.addClass("simple-time-tracker-btn"); + await saveTracker(tracker, getFile(), getSectionInfo()) + }) + btn.buttonEl.addClass("simple-time-tracker-btn") let newSegmentNameBox = new TextComponent(element) .setPlaceholder("Segment name") - .setDisabled(running); - newSegmentNameBox.inputEl.addClass("simple-time-tracker-txt"); + .setDisabled(running) + newSegmentNameBox.inputEl.addClass("simple-time-tracker-txt") // add timers - let timer = element.createDiv({ cls: "simple-time-tracker-timers" }); - let currentDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" }); - let current = currentDiv.createEl("span", { cls: "simple-time-tracker-timer-time" }); - currentDiv.createEl("span", { text: "Current" }); - let totalDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" }); - let total = totalDiv.createEl("span", { cls: "simple-time-tracker-timer-time", text: "0s" }); - totalDiv.createEl("span", { text: "Total" }); + let timer = element.createDiv({ cls: "simple-time-tracker-timers" }) + let currentDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" }) + let current = currentDiv.createEl("span", { cls: "simple-time-tracker-timer-time" }) + currentDiv.createEl("span", { text: "Current" }) + let totalDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" }) + let total = totalDiv.createEl("span", { cls: "simple-time-tracker-timer-time", text: "0s" }) + totalDiv.createEl("span", { text: "Total" }) + let totalTodayDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" }) + let totalToday = totalTodayDiv.createEl("span", { cls: "simple-time-tracker-timer-time", text: "0s" }) + totalTodayDiv.createEl("span", { text: "Total Today" }) if (tracker.entries.length > 0) { // add table - let table = element.createEl("table", { cls: "simple-time-tracker-table" }); + let table = element.createEl("table", { cls: "simple-time-tracker-table" }) table.createEl("tr").append( createEl("th", { text: "Segment" }), createEl("th", { text: "Start time" }), createEl("th", { text: "End time" }), createEl("th", { text: "Duration" }), - createEl("th")); + createEl("th")) for (let entry of orderedEntries(tracker.entries, settings)) - addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, getFile, getSectionInfo, settings, 0, component); + addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, getFile, getSectionInfo, settings, 0, component) // add copy buttons - let buttons = element.createEl("div", { cls: "simple-time-tracker-bottom" }); + let buttons = element.createEl("div", { cls: "simple-time-tracker-bottom" }) new ButtonComponent(buttons) .setButtonText("Copy as table") - .onClick(() => navigator.clipboard.writeText(createMarkdownTable(tracker, settings))); + .onClick(() => navigator.clipboard.writeText(createMarkdownTable(tracker, settings))) new ButtonComponent(buttons) .setButtonText("Copy as CSV") - .onClick(() => navigator.clipboard.writeText(createCsv(tracker, settings))); + .onClick(() => navigator.clipboard.writeText(createCsv(tracker, settings))) } - setCountdownValues(tracker, current, total, currentDiv, settings); + setCountdownValues(tracker, current, total, totalToday, currentDiv, settings) let intervalId = window.setInterval(() => { // we delete the interval timer when the element is removed if (!element.isConnected) { - window.clearInterval(intervalId); - return; + window.clearInterval(intervalId) + return } - setCountdownValues(tracker, current, total, currentDiv, settings); - }, 1000); + setCountdownValues(tracker, current, total, totalToday, currentDiv, settings) + }, 1000) } export function getDuration(entry: Entry): number { if (entry.subEntries) { - return getTotalDuration(entry.subEntries); + return getTotalDuration(entry.subEntries) } else { - let endTime = entry.endTime ? moment(entry.endTime) : moment(); - return endTime.diff(moment(entry.startTime)); + let endTime = entry.endTime ? moment(entry.endTime) : moment() + return endTime.diff(moment(entry.startTime)) + } +} + +export function getDurationToday(entry: Entry): number { + if (entry.subEntries) { + return getTotalDurationToday(entry.subEntries) + } else { + let today = moment().startOf('day') + let endTime = entry.endTime ? moment(entry.endTime) : moment() + let startTime = moment(entry.startTime) + + if (endTime.isBefore(today)) { + return 0 + } + + if (startTime.isBefore(today)) { + startTime = today + } + + return endTime.diff(startTime) } } export function getTotalDuration(entries: Entry[]): number { - let ret = 0; + let ret = 0 for (let entry of entries) - ret += getDuration(entry); - return ret; + ret += getDuration(entry) + return ret +} + +export function getTotalDurationToday(entries: Entry[]): number { + let ret = 0 + for (let entry of entries) + ret += getDurationToday(entry) + return ret } export function isRunning(tracker: Tracker): boolean { - return !!getRunningEntry(tracker.entries); + return !!getRunningEntry(tracker.entries) } export function getRunningEntry(entries: Entry[]): Entry { for (let entry of entries) { // if this entry has sub entries, check if one of them is running if (entry.subEntries) { - let running = getRunningEntry(entry.subEntries); + let running = getRunningEntry(entry.subEntries) if (running) - return running; + return running } else { // if this entry has no sub entries and no end time, it's running if (!entry.endTime) - return entry; + return entry } } - return null; + return null } export function createMarkdownTable(tracker: Tracker, settings: SimpleTimeTrackerSettings): string { - let table = [["Segment", "Start time", "End time", "Duration"]]; + let table = [["Segment", "Start time", "End time", "Duration"]] for (let entry of orderedEntries(tracker.entries, settings)) - table.push(...createTableSection(entry, settings)); - table.push(["**Total**", "", "", `**${formatDuration(getTotalDuration(tracker.entries), settings)}**`]); + table.push(...createTableSection(entry, settings)) + table.push(["**Total**", "", "", `**${formatDuration(getTotalDuration(tracker.entries), settings)}**`]) - let ret = ""; + let ret = "" // calculate the width every column needs to look neat when monospaced - let widths = Array.from(Array(4).keys()).map(i => Math.max(...table.map(a => a[i].length))); + let widths = Array.from(Array(4).keys()).map(i => Math.max(...table.map(a => a[i].length))) for (let r = 0; r < table.length; r++) { // add separators after first row if (r == 1) - ret += "| " + Array.from(Array(4).keys()).map(i => "-".repeat(widths[i])).join(" | ") + " |\n"; + ret += "| " + Array.from(Array(4).keys()).map(i => "-".repeat(widths[i])).join(" | ") + " |\n" - let row: string[] = []; + let row: string[] = [] for (let i = 0; i < 4; i++) - row.push(table[r][i].padEnd(widths[i], " ")); - ret += "| " + row.join(" | ") + " |\n"; + row.push(table[r][i].padEnd(widths[i], " ")) + ret += "| " + row.join(" | ") + " |\n" } - return ret; + return ret } export function createCsv(tracker: Tracker, settings: SimpleTimeTrackerSettings): string { - let ret = ""; + let ret = "" for (let entry of orderedEntries(tracker.entries, settings)) { for (let row of createTableSection(entry, settings)) - ret += row.join(settings.csvDelimiter) + "\n"; + ret += row.join(settings.csvDelimiter) + "\n" } - return ret; + return ret } export function orderedEntries(entries: Entry[], settings: SimpleTimeTrackerSettings): Entry[] { - return settings.reverseSegmentOrder ? entries.slice().reverse() : entries; + return settings.reverseSegmentOrder ? entries.slice().reverse() : entries } export function formatTimestamp(timestamp: string, settings: SimpleTimeTrackerSettings): string { - return moment(timestamp).format(settings.timestampFormat); + return moment(timestamp).format(settings.timestampFormat) } export function formatDuration(totalTime: number, settings: SimpleTimeTrackerSettings): string { - let ret = ""; - let duration = moment.duration(totalTime); - let hours = settings.fineGrainedDurations ? duration.hours() : Math.floor(duration.asHours()); + let ret = "" + let duration = moment.duration(totalTime) + let hours = settings.fineGrainedDurations ? duration.hours() : Math.floor(duration.asHours()) if (settings.timestampDurations) { if (settings.fineGrainedDurations) { - let days = Math.floor(duration.asDays()); + let days = Math.floor(duration.asDays()) if (days > 0) - ret += days + "."; + ret += days + "." } - ret += `${hours.toString().padStart(2, "0")}:${duration.minutes().toString().padStart(2, "0")}:${duration.seconds().toString().padStart(2, "0")}`; + ret += `${hours.toString().padStart(2, "0")}:${duration.minutes().toString().padStart(2, "0")}:${duration.seconds().toString().padStart(2, "0")}` } else { if (settings.fineGrainedDurations) { - let years = Math.floor(duration.asYears()); + let years = Math.floor(duration.asYears()) if (years > 0) - ret += years + "y "; + ret += years + "y " if (duration.months() > 0) - ret += duration.months() + "M "; + ret += duration.months() + "M " if (duration.days() > 0) - ret += duration.days() + "d "; + ret += duration.days() + "d " } if (hours > 0) - ret += hours + "h "; + ret += hours + "h " if (duration.minutes() > 0) - ret += duration.minutes() + "m "; - ret += duration.seconds() + "s"; + ret += duration.minutes() + "m " + ret += duration.seconds() + "s" } - return ret; + return ret } function startSubEntry(entry: Entry, name: string): void { // if this entry is not split yet, we add its time as a sub-entry instead if (!entry.subEntries) { - entry.subEntries = [{ ...entry, name: `Part 1` }]; - entry.startTime = null; - entry.endTime = null; + entry.subEntries = [{ ...entry, name: `Part 1` }] + entry.startTime = null + entry.endTime = null } if (!name) - name = `Part ${entry.subEntries.length + 1}`; - entry.subEntries.push({ name: name, startTime: moment().toISOString(), endTime: null, subEntries: undefined }); + name = `Part ${entry.subEntries.length + 1}` + entry.subEntries.push({ name: name, startTime: moment().toISOString(), endTime: null, subEntries: undefined }) } function startNewEntry(tracker: Tracker, name: string): void { if (!name) - name = `Segment ${tracker.entries.length + 1}`; - let entry: Entry = { name: name, startTime: moment().toISOString(), endTime: null, subEntries: undefined }; - tracker.entries.push(entry); + name = `Segment ${tracker.entries.length + 1}` + let entry: Entry = { name: name, startTime: moment().toISOString(), endTime: null, subEntries: undefined } + tracker.entries.push(entry) } function endRunningEntry(tracker: Tracker): void { - let entry = getRunningEntry(tracker.entries); - entry.endTime = moment().toISOString(); + let entry = getRunningEntry(tracker.entries) + entry.endTime = moment().toISOString() } function removeEntry(entries: Entry[], toRemove: Entry): boolean { if (entries.contains(toRemove)) { - entries.remove(toRemove); - return true; + entries.remove(toRemove) + return true } else { for (let entry of entries) { if (entry.subEntries && removeEntry(entry.subEntries, toRemove)) { // if we only have one sub entry remaining, we can merge back into our main entry if (entry.subEntries.length == 1) { - let single = entry.subEntries[0]; - entry.startTime = single.startTime; - entry.endTime = single.endTime; - entry.subEntries = undefined; + let single = entry.subEntries[0] + entry.startTime = single.startTime + entry.endTime = single.endTime + entry.subEntries = undefined } - return true; + return true } } } - return false; + return false } -function setCountdownValues(tracker: Tracker, current: HTMLElement, total: HTMLElement, currentDiv: HTMLDivElement, settings: SimpleTimeTrackerSettings): void { - let running = getRunningEntry(tracker.entries); +function setCountdownValues(tracker: Tracker, current: HTMLElement, total: HTMLElement, totalToday: HTMLElement, currentDiv: HTMLDivElement, settings: SimpleTimeTrackerSettings): void { + let running = getRunningEntry(tracker.entries) if (running && !running.endTime) { - current.setText(formatDuration(getDuration(running), settings)); - currentDiv.hidden = false; + current.setText(formatDuration(getDuration(running), settings)) + currentDiv.hidden = false } else { - currentDiv.hidden = true; + currentDiv.hidden = true } - total.setText(formatDuration(getTotalDuration(tracker.entries), settings)); + total.setText(formatDuration(getTotalDuration(tracker.entries), settings)) + totalToday.setText(formatDuration(getTotalDurationToday(tracker.entries), settings)) } function formatEditableTimestamp(timestamp: string, settings: SimpleTimeTrackerSettings): string { - return moment(timestamp).format(settings.editableTimestampFormat); + return moment(timestamp).format(settings.editableTimestampFormat) } function unformatEditableTimestamp(formatted: string, settings: SimpleTimeTrackerSettings): string { - return moment(formatted, settings.editableTimestampFormat).toISOString(); + return moment(formatted, settings.editableTimestampFormat).toISOString() } function updateLegacyInfo(entries: Entry[]): void { for (let entry of entries) { // in 0.1.8, timestamps were changed from unix to iso if (entry.startTime && !isNaN(+entry.startTime)) - entry.startTime = moment.unix(+entry.startTime).toISOString(); + entry.startTime = moment.unix(+entry.startTime).toISOString() if (entry.endTime && !isNaN(+entry.endTime)) - entry.endTime = moment.unix(+entry.endTime).toISOString(); + entry.endTime = moment.unix(+entry.endTime).toISOString() // in 1.0.0, sub-entries were made optional if (entry.subEntries == null || !entry.subEntries.length) - entry.subEntries = undefined; + entry.subEntries = undefined if (entry.subEntries) - updateLegacyInfo(entry.subEntries); + updateLegacyInfo(entry.subEntries) } } @@ -331,25 +362,25 @@ function createTableSection(entry: Entry, settings: SimpleTimeTrackerSettings): entry.name, entry.startTime ? formatTimestamp(entry.startTime, settings) : "", entry.endTime ? formatTimestamp(entry.endTime, settings) : "", - entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""]]; + entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""]] if (entry.subEntries) { for (let sub of orderedEntries(entry.subEntries, settings)) - ret.push(...createTableSection(sub, settings)); + ret.push(...createTableSection(sub, settings)) } - return ret; + return ret } function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableElement, newSegmentNameBox: TextComponent, trackerRunning: boolean, getFile: GetFile, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings, indent: number, component: MarkdownRenderChild): void { - let entryRunning = getRunningEntry(tracker.entries) == entry; - let row = table.createEl("tr"); + let entryRunning = getRunningEntry(tracker.entries) == entry + let row = table.createEl("tr") - let nameField = new EditableField(row, indent, entry.name); - let startField = new EditableTimestampField(row, (entry.startTime), settings); - let endField = new EditableTimestampField(row, (entry.endTime), settings); + let nameField = new EditableField(row, indent, entry.name) + let startField = new EditableTimestampField(row, (entry.startTime), settings) + let endField = new EditableTimestampField(row, (entry.endTime), settings) - row.createEl("td", { text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : "" }); + row.createEl("td", { text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : "" }) - renderNameAsMarkdown(nameField.label, getFile, component); + renderNameAsMarkdown(nameField.label, getFile, component) let expandButton = new ButtonComponent(nameField.label) .setClass("clickable-icon") @@ -357,56 +388,56 @@ function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableEle .setIcon(`chevron-${entry.collapsed ? "left" : "down"}`) .onClick(async () => { if (entry.collapsed) { - entry.collapsed = undefined; + entry.collapsed = undefined } else { - entry.collapsed = true; + entry.collapsed = true } - await saveTracker(tracker, getFile(), getSectionInfo()); - }); + await saveTracker(tracker, getFile(), getSectionInfo()) + }) if (!entry.subEntries) - expandButton.buttonEl.style.visibility = "hidden"; + expandButton.buttonEl.style.visibility = "hidden" - let entryButtons = row.createEl("td"); - entryButtons.addClass("simple-time-tracker-table-buttons"); + let entryButtons = row.createEl("td") + entryButtons.addClass("simple-time-tracker-table-buttons") new ButtonComponent(entryButtons) .setClass("clickable-icon") .setIcon(`lucide-play`) .setTooltip("Continue") .setDisabled(trackerRunning) .onClick(async () => { - startSubEntry(entry, newSegmentNameBox.getValue()); - await saveTracker(tracker, getFile(), getSectionInfo()); - }); + startSubEntry(entry, newSegmentNameBox.getValue()) + await saveTracker(tracker, getFile(), getSectionInfo()) + }) let editButton = new ButtonComponent(entryButtons) .setClass("clickable-icon") .setTooltip("Edit") .setIcon("lucide-pencil") .onClick(async () => { if (nameField.editing()) { - entry.name = nameField.endEdit(); - expandButton.buttonEl.style.display = null; - startField.endEdit(); - entry.startTime = startField.getTimestamp(); + entry.name = nameField.endEdit() + expandButton.buttonEl.style.display = null + startField.endEdit() + entry.startTime = startField.getTimestamp() if (!entryRunning) { - endField.endEdit(); - entry.endTime = endField.getTimestamp(); + endField.endEdit() + entry.endTime = endField.getTimestamp() } - await saveTracker(tracker, getFile(), getSectionInfo()); - editButton.setIcon("lucide-pencil"); + await saveTracker(tracker, getFile(), getSectionInfo()) + editButton.setIcon("lucide-pencil") - renderNameAsMarkdown(nameField.label, getFile, component); + renderNameAsMarkdown(nameField.label, getFile, component) } else { - nameField.beginEdit(entry.name); - expandButton.buttonEl.style.display = "none"; + nameField.beginEdit(entry.name) + expandButton.buttonEl.style.display = "none" // only allow editing start and end times if we don't have sub entries if (!entry.subEntries) { - startField.beginEdit(entry.startTime); + startField.beginEdit(entry.startTime) if (!entryRunning) - endField.beginEdit(entry.endTime); + endField.beginEdit(entry.endTime) } - editButton.setIcon("lucide-check"); + editButton.setIcon("lucide-check") } - }); + }) new ButtonComponent(entryButtons) .setClass("clickable-icon") .setTooltip("Remove") @@ -414,100 +445,100 @@ function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableEle .setDisabled(entryRunning) .onClick(async () => { - const confirmed = await showConfirm("Are you sure you want to delete this entry?"); + const confirmed = await showConfirm("Are you sure you want to delete this entry?") if (!confirmed) { - return; + return } - removeEntry(tracker.entries, entry); - await saveTracker(tracker, getFile(), getSectionInfo()); - }); + removeEntry(tracker.entries, entry) + await saveTracker(tracker, getFile(), getSectionInfo()) + }) if (entry.subEntries && !entry.collapsed) { for (let sub of orderedEntries(entry.subEntries, settings)) - addEditableTableRow(tracker, sub, table, newSegmentNameBox, trackerRunning, getFile, getSectionInfo, settings, indent + 1, component); + addEditableTableRow(tracker, sub, table, newSegmentNameBox, trackerRunning, getFile, getSectionInfo, settings, indent + 1, component) } } function showConfirm(message: string): Promise { return new Promise((resolve) => { - const modal = new ConfirmModal(app, message, resolve); - modal.open(); - }); + const modal = new ConfirmModal(app, message, resolve) + modal.open() + }) } function renderNameAsMarkdown(label: HTMLSpanElement, getFile: GetFile, component: Component): void { // we don't have to wait here since async code only occurs when a file needs to be loaded (like a linked image) - void MarkdownRenderer.renderMarkdown(label.innerHTML, label, getFile(), component); + void MarkdownRenderer.renderMarkdown(label.innerHTML, label, getFile(), component) // rendering wraps it in a paragraph - label.innerHTML = label.querySelector("p").innerHTML; + label.innerHTML = label.querySelector("p").innerHTML } class EditableField { - cell: HTMLTableCellElement; - label: HTMLSpanElement; - box: TextComponent; + cell: HTMLTableCellElement + label: HTMLSpanElement + box: TextComponent constructor(row: HTMLTableRowElement, indent: number, value: string) { - this.cell = row.createEl("td"); - this.label = this.cell.createEl("span", { text: value }); - this.label.style.marginLeft = `${indent}em`; - this.box = new TextComponent(this.cell).setValue(value); - this.box.inputEl.addClass("simple-time-tracker-input"); - this.box.inputEl.hide(); + this.cell = row.createEl("td") + this.label = this.cell.createEl("span", { text: value }) + this.label.style.marginLeft = `${indent}em` + this.box = new TextComponent(this.cell).setValue(value) + this.box.inputEl.addClass("simple-time-tracker-input") + this.box.inputEl.hide() } editing(): boolean { - return this.label.hidden; + return this.label.hidden } beginEdit(value: string): void { - this.label.hidden = true; - this.box.setValue(value); - this.box.inputEl.show(); + this.label.hidden = true + this.box.setValue(value) + this.box.inputEl.show() } endEdit(): string { - const value = this.box.getValue(); - this.label.setText(value); - this.box.inputEl.hide(); - this.label.hidden = false; - return value; + const value = this.box.getValue() + this.label.setText(value) + this.box.inputEl.hide() + this.label.hidden = false + return value } } class EditableTimestampField extends EditableField { - settings: SimpleTimeTrackerSettings; + settings: SimpleTimeTrackerSettings constructor(row: HTMLTableRowElement, value: string, settings: SimpleTimeTrackerSettings) { - super(row, 0, value ? formatTimestamp(value, settings) : ""); - this.settings = settings; + super(row, 0, value ? formatTimestamp(value, settings) : "") + this.settings = settings } beginEdit(value: string): void { - super.beginEdit(value ? formatEditableTimestamp(value, this.settings) : ""); + super.beginEdit(value ? formatEditableTimestamp(value, this.settings) : "") } endEdit(): string { - const value = this.box.getValue(); - let displayValue = value; + const value = this.box.getValue() + let displayValue = value if (value) { - const timestamp = unformatEditableTimestamp(value, this.settings); - displayValue = formatTimestamp(timestamp, this.settings); + const timestamp = unformatEditableTimestamp(value, this.settings) + displayValue = formatTimestamp(timestamp, this.settings) } - this.label.setText(displayValue); - this.box.inputEl.hide(); - this.label.hidden = false; - return value; + this.label.setText(displayValue) + this.box.inputEl.hide() + this.label.hidden = false + return value } getTimestamp(): string { if (this.box.getValue()) { - return unformatEditableTimestamp(this.box.getValue(), this.settings); + return unformatEditableTimestamp(this.box.getValue(), this.settings) } else { - return null; + return null } } }