mirror of
https://github.com/groldsf/obsidian_check_plugin.git
synced 2026-07-22 05:37:48 +00:00
refactor(settings): Add base structures for settings tab architecture
This commit is contained in:
parent
d1a76ae87c
commit
5074bf6464
5 changed files with 189 additions and 0 deletions
56
src/ui/SettingGroup.ts
Normal file
56
src/ui/SettingGroup.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { CheckboxSyncPluginSettings } from "src/types";
|
||||
import { ISettingComponent } from "./interfaces/ISettingComponent";
|
||||
|
||||
/**
|
||||
* Представляет группу связанных настроек в UI.
|
||||
*/
|
||||
export class SettingGroup {
|
||||
title: string;
|
||||
description?: string;
|
||||
components: ISettingComponent[];
|
||||
|
||||
/**
|
||||
* Создает экземпляр группы настроек.
|
||||
* @param title - Заголовок группы (отображается как h3).
|
||||
* @param components - Массив компонентов настроек, входящих в эту группу.
|
||||
* @param description - Опциональное описание группы (отображается как p).
|
||||
*/
|
||||
constructor(title: string, components: ISettingComponent[], description?: string) {
|
||||
this.title = title;
|
||||
this.components = components;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Рендерит заголовок группы и все ее компоненты.
|
||||
* @param container - HTML-элемент, куда рендерить группу.
|
||||
* @param currentSettings - Объект текущих настроек плагина.
|
||||
*/
|
||||
render(container: HTMLElement, currentSettings: CheckboxSyncPluginSettings): void {
|
||||
container.createEl('h3', { text: this.title });
|
||||
if (this.description) {
|
||||
container.createEl('p', { text: this.description, cls: 'setting-item-description' });
|
||||
}
|
||||
|
||||
// Рендерим каждый компонент, передавая ему текущее значение
|
||||
for (const component of this.components) {
|
||||
try {
|
||||
const key = component.getSettingKey();
|
||||
// Проверяем, существует ли ключ в настройках, чтобы избежать ошибок
|
||||
if (key in currentSettings) {
|
||||
component.render(container, currentSettings[key]);
|
||||
} else {
|
||||
console.warn(`Setting key "${key}" not found in current settings for component in group "${this.title}". Rendering with default or undefined value might occur.`);
|
||||
// Можно передать undefined или значение по умолчанию, если getSettingKey гарантированно работает
|
||||
// component.render(container, component.getDefaultValue());
|
||||
component.render(container, undefined); // Или рендерить с undefined
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error rendering component for key "${component.getSettingKey()}" in group "${this.title}":`, error);
|
||||
// Можно добавить placeholder или сообщение об ошибке в UI
|
||||
container.createDiv({ text: `Error rendering setting: ${component.getSettingKey()}`, cls: 'checkbox-sync-settings-error' });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/ui/components/BaseSettingComponent.ts
Normal file
27
src/ui/components/BaseSettingComponent.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { Setting } from 'obsidian';
|
||||
import { CheckboxSyncPluginSettings } from '../../types';
|
||||
import { ISettingComponent } from '../interfaces/ISettingComponent';
|
||||
import { ValidationError } from '../validation/types';
|
||||
// Убрали App и CheckboxSyncPlugin из импортов, если они не нужны ВСЕМ наследникам
|
||||
|
||||
export abstract class BaseSettingComponent implements ISettingComponent {
|
||||
protected setting: Setting; // Инициализируется в render конкретного компонента
|
||||
protected onChangeCallback: () => void = () => {};
|
||||
|
||||
// Конструктор теперь пустой или с минимальными общими зависимостями
|
||||
constructor() {}
|
||||
|
||||
// --- Методы для реализации наследниками ---
|
||||
abstract getSettingKey(): keyof CheckboxSyncPluginSettings;
|
||||
abstract getDefaultValue(): any;
|
||||
// render теперь должен сам создавать Setting и сохранять ссылку в this.setting
|
||||
abstract render(container: HTMLElement, currentValue: any): void;
|
||||
abstract getValueFromUi(): any;
|
||||
abstract setValueInUi(value: any): void;
|
||||
abstract validate(value: any): ValidationError | null;
|
||||
|
||||
// --- Общая реализация ---
|
||||
public setChangeListener(listener: () => void): void {
|
||||
this.onChangeCallback = listener;
|
||||
}
|
||||
}
|
||||
58
src/ui/interfaces/ISettingComponent.ts
Normal file
58
src/ui/interfaces/ISettingComponent.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { CheckboxSyncPluginSettings } from "src/types";
|
||||
import { ValidationError } from "../validation/types";
|
||||
|
||||
|
||||
/**
|
||||
* Интерфейс для компонента, отвечающего за одну настройку в UI.
|
||||
*/
|
||||
export interface ISettingComponent {
|
||||
/**
|
||||
* Получает ключ настройки, за которую отвечает этот компонент.
|
||||
* @returns Ключ из CheckboxSyncPluginSettings.
|
||||
*/
|
||||
getSettingKey(): keyof CheckboxSyncPluginSettings;
|
||||
|
||||
/**
|
||||
* Получает значение по умолчанию для этой настройки.
|
||||
* @returns Значение по умолчанию.
|
||||
*/
|
||||
getDefaultValue(): any;
|
||||
|
||||
/**
|
||||
* Рендерит UI-элементы для этой настройки в указанный контейнер.
|
||||
* @param container - HTML-элемент, куда добавлять настройку.
|
||||
* @param currentValue - Текущее сохраненное значение настройки.
|
||||
*/
|
||||
render(container: HTMLElement, currentValue: any): void;
|
||||
|
||||
/**
|
||||
* Считывает значение из UI-элементов компонента.
|
||||
* Может включать парсинг (например, JSON).
|
||||
* @returns Текущее значение из UI.
|
||||
* @throws Error если значение в UI некорректно для извлечения (например, невалидный JSON).
|
||||
*/
|
||||
getValueFromUi(): any;
|
||||
|
||||
/**
|
||||
* Устанавливает значение в UI-элементы компонента.
|
||||
* Может включать форматирование (например, JSON.stringify).
|
||||
* @param value - Значение для установки в UI.
|
||||
*/
|
||||
setValueInUi(value: any): void;
|
||||
|
||||
/**
|
||||
* Выполняет *индивидуальную* валидацию значения.
|
||||
* **Важно:** Этот метод должен быть тестируемым и не зависеть от Obsidian API.
|
||||
* Он принимает чистое значение и возвращает ошибку или null.
|
||||
* @param value - Чистое значение для валидации (обычно результат getValueFromUi).
|
||||
* @returns Объект ValidationError, если значение невалидно, иначе null.
|
||||
*/
|
||||
validate(value: any): ValidationError | null;
|
||||
|
||||
/**
|
||||
* Устанавливает колбэк, который будет вызван при изменении значения в UI.
|
||||
* Используется для управления флагом isDirty.
|
||||
* @param listener - Функция обратного вызова.
|
||||
*/
|
||||
setChangeListener(listener: () => void): void;
|
||||
}
|
||||
40
src/ui/validation/SettingsValidator.ts
Normal file
40
src/ui/validation/SettingsValidator.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// src/settings/validation/SettingsValidator.ts
|
||||
|
||||
import { CheckboxSyncPluginSettings } from '../../types'; // Путь к типам
|
||||
import { ValidationError } from './types'; // Путь к типам ошибок
|
||||
|
||||
/**
|
||||
* Отвечает за валидацию настроек, требующую проверки нескольких полей (перекрестная валидация).
|
||||
* **Важно:** Логика внутри методов не должна зависеть от Obsidian API для тестируемости.
|
||||
*/
|
||||
export class SettingsValidator {
|
||||
|
||||
/**
|
||||
* Выполняет перекрестную валидацию предоставленных данных настроек.
|
||||
* @param settingsData - Объект с текущими значениями настроек (или их частью).
|
||||
* @returns Массив объектов ValidationError, если найдены ошибки, иначе пустой массив.
|
||||
*/
|
||||
public validate(settingsData: Partial<CheckboxSyncPluginSettings>): ValidationError[] {
|
||||
const errors: ValidationError[] = [];
|
||||
|
||||
// Пример: Проверка пересечения списков символов (будет реализована позже)
|
||||
// if (settingsData.checkedSymbols && settingsData.uncheckedSymbols) {
|
||||
// const intersection = settingsData.checkedSymbols.filter(symbol => settingsData.uncheckedSymbols!.includes(symbol));
|
||||
// if (intersection.length > 0) {
|
||||
// errors.push({
|
||||
// // Можно не указывать поле, т.к. ошибка затрагивает несколько
|
||||
// message: `Symbols found in both Checked and Unchecked lists: ${JSON.stringify(intersection)}`
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// ... другие перекрестные проверки ...
|
||||
|
||||
// Пока возвращаем пустой массив, логика будет добавлена на Шаге 6
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Сюда можно добавить статические вспомогательные методы для валидации, если нужно
|
||||
// public static validateSymbolListsIntersection(listA: string[], listB: string[]): string[] {
|
||||
// return listA.filter(symbol => listB.includes(symbol));
|
||||
// }
|
||||
}
|
||||
8
src/ui/validation/types.ts
Normal file
8
src/ui/validation/types.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { CheckboxSyncPluginSettings } from "src/types";
|
||||
|
||||
export interface ValidationError {
|
||||
/** Ключ поля настройки, с которым связана ошибка (опционально). */
|
||||
field?: keyof CheckboxSyncPluginSettings;
|
||||
/** Сообщение об ошибке, понятное пользователю. */
|
||||
message: string;
|
||||
}
|
||||
Loading…
Reference in a new issue