2025-04-05 14:50:18 +00:00
|
|
|
import { App } from "obsidian";
|
|
|
|
|
import { PluginState } from "src/pluginState";
|
|
|
|
|
import { DateNavigatorOptions, DateNavigatorDOMElements, NavigationPeriod } from "./dateNavigator.types";
|
|
|
|
|
import { createPrevHandler, createNextHandler, createOpenModalHandler } from "./eventHandlers/dateNavigationHandlers";
|
|
|
|
|
import { buildDateNavigatorDOM, updateDateNavigatorDisplay } from "./dom/buildDateNavigatorDOM";
|
2025-04-09 10:15:31 +00:00
|
|
|
import { DATE_CHANGED_EVENT_NAME } from "../../pluginState";
|
|
|
|
|
import { createPeriodChangeHandler } from "./eventHandlers/periodChangeHandler";
|
2025-04-05 14:50:18 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates and manages the interactive Date Navigator header.
|
|
|
|
|
* Uses pluginState to get/set the current date.
|
|
|
|
|
* Updates its display when the date changes.
|
|
|
|
|
*/
|
|
|
|
|
export class DateNavigator {
|
|
|
|
|
private app: App;
|
|
|
|
|
private pluginState: PluginState;
|
|
|
|
|
private containerEl: HTMLElement;
|
2025-04-09 10:15:31 +00:00
|
|
|
private configPeriod: NavigationPeriod;
|
2025-04-05 14:50:18 +00:00
|
|
|
private elements: DateNavigatorDOMElements | null = null;
|
2025-04-09 10:15:31 +00:00
|
|
|
private isListening: boolean = false;
|
2025-04-05 14:50:18 +00:00
|
|
|
|
|
|
|
|
constructor(options: DateNavigatorOptions) {
|
|
|
|
|
this.app = options.app;
|
|
|
|
|
this.pluginState = options.pluginState;
|
|
|
|
|
this.containerEl = options.containerEl;
|
2025-04-09 10:15:31 +00:00
|
|
|
this.configPeriod = options.period ?? 'day';
|
2025-04-05 14:50:18 +00:00
|
|
|
|
|
|
|
|
if (!this.app || !this.pluginState || !this.containerEl) {
|
|
|
|
|
throw new Error("DateNavigator missing required options (app, pluginState, containerEl).");
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 10:15:31 +00:00
|
|
|
//? Set the global state's period to match this instance *on initialization*.
|
|
|
|
|
//? This means the last rendered navigator sets the global period.
|
|
|
|
|
if (this.pluginState.currentPeriod !== this.configPeriod) {
|
|
|
|
|
//? Note: This immediately changes global state and triggers event/recalc
|
|
|
|
|
this.pluginState.currentPeriod = this.configPeriod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//? Now build the UI using the synchronized (or initially matching) state
|
2025-04-05 14:50:18 +00:00
|
|
|
this._buildUI();
|
2025-04-09 10:15:31 +00:00
|
|
|
this._setupStateListener();
|
2025-04-05 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Builds the initial UI */
|
|
|
|
|
private _buildUI(): void {
|
2025-04-09 10:15:31 +00:00
|
|
|
const currentGlobalPeriod = this.pluginState.currentPeriod;
|
|
|
|
|
const currentSelectedDate = this.pluginState.selectedDate;
|
|
|
|
|
|
2025-04-05 14:50:18 +00:00
|
|
|
//~ Create bound handlers first
|
|
|
|
|
const handlers = {
|
2025-04-09 10:15:31 +00:00
|
|
|
handlePrev: createPrevHandler(this.pluginState, this.app),
|
|
|
|
|
handleNext: createNextHandler(this.pluginState, this.app),
|
|
|
|
|
handleOpenModal: createOpenModalHandler(this.pluginState, this.app),
|
|
|
|
|
handlePeriodChange: createPeriodChangeHandler(this.pluginState),
|
2025-04-05 14:50:18 +00:00
|
|
|
};
|
|
|
|
|
//~ Build DOM and store element references
|
2025-04-09 10:15:31 +00:00
|
|
|
this.elements = buildDateNavigatorDOM(
|
|
|
|
|
this.containerEl,
|
|
|
|
|
currentSelectedDate,
|
|
|
|
|
currentGlobalPeriod,
|
|
|
|
|
handlers
|
|
|
|
|
);
|
2025-04-05 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Updates the displayed date. Bound method for callbacks. */
|
2025-04-09 10:15:31 +00:00
|
|
|
private _updateDisplay = (): void => {
|
|
|
|
|
const currentIsoDate = this.pluginState.selectedDate;
|
|
|
|
|
const currentPeriod = this.pluginState.currentPeriod;
|
|
|
|
|
|
|
|
|
|
updateDateNavigatorDisplay(this.elements, currentIsoDate, currentPeriod);
|
2025-04-05 14:50:18 +00:00
|
|
|
};
|
|
|
|
|
|
2025-04-09 10:15:31 +00:00
|
|
|
/** Listen for the custom date change event from pluginState */
|
|
|
|
|
private _setupStateListener(): void {
|
|
|
|
|
if (this.isListening) return;
|
|
|
|
|
document.addEventListener(DATE_CHANGED_EVENT_NAME, this._updateDisplay);
|
|
|
|
|
this.isListening = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 14:50:18 +00:00
|
|
|
/** Cleans up the component (e.g., remove listeners, clear container) */
|
|
|
|
|
public destroy(): void {
|
|
|
|
|
this.containerEl.empty();
|
|
|
|
|
this.elements = null;
|
|
|
|
|
}
|
|
|
|
|
}
|