diff --git a/src/tracker.ts b/src/tracker.ts index 07b042f..9daf635 100644 --- a/src/tracker.ts +++ b/src/tracker.ts @@ -1,150 +1,150 @@ -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, totalToday, currentDiv, settings) + setCountdownValues(tracker, current, total, 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, totalToday, currentDiv, settings) - }, 1000) + setCountdownValues(tracker, current, total, 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)); } } @@ -169,10 +169,10 @@ export function getDurationToday(entry: Entry): number { } 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 { @@ -183,176 +183,175 @@ export function getTotalDurationToday(entries: Entry[]): number { } 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, totalToday: HTMLElement, currentDiv: HTMLDivElement, settings: SimpleTimeTrackerSettings): void { - let running = getRunningEntry(tracker.entries) +function setCountdownValues(tracker: Tracker, current: HTMLElement, total: 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)) - totalToday.setText(formatDuration(getTotalDurationToday(tracker.entries), settings)) + total.setText(formatDuration(getTotalDuration(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); } } @@ -362,25 +361,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") @@ -388,56 +387,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") @@ -445,100 +444,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; } } }