add settings

This commit is contained in:
Grol Grol 2025-04-11 21:09:29 +03:00
parent c751add5fe
commit 3d1ea00009
6 changed files with 178 additions and 45 deletions

View file

@ -1,25 +1,45 @@
// checkboxUtils.test.ts
import { CheckboxUtils, CheckboxLineInfo } from '../src/checkboxUtils';
import { CheckboxUtils } from '../src/checkboxUtils';
import { CheckboxSyncPluginSettings } from '../src/types'; // Предполагаем, что типы в types.ts
// --- Mock Settings ---
const defaultSettings: Readonly<CheckboxSyncPluginSettings> = {
xOnlyMode: false, // По умолчанию: любой не-пробел считается 'checked'
enableAutomaticParentState: true,
enableAutomaticChildState: true,
};
const xOnlySettings: Readonly<CheckboxSyncPluginSettings> = {
xOnlyMode: true, // Только 'x' считается 'checked'
enableAutomaticParentState: true,
enableAutomaticChildState: true,
};
const settingsParentSyncDisabled: Readonly<CheckboxSyncPluginSettings> = {
xOnlyMode: false, // или true, если нужно тестировать комбинацию
enableAutomaticParentState: false, // Родитель НЕ обновляется от детей
enableAutomaticChildState: true,
};
const settingsChildSyncDisabled: Readonly<CheckboxSyncPluginSettings> = {
xOnlyMode: false,
enableAutomaticParentState: true, // Оставим true для этого варианта
enableAutomaticChildState: false, // Дети НЕ обновляются от родителя
};
// --- Test Suite ---
describe('CheckboxUtils', () => {
let utilsDefault: CheckboxUtils;
let utilsXOnly: CheckboxUtils;
let utilsParentSyncDisabled: CheckboxUtils;
let utilsChildSyncDisabled: CheckboxUtils
beforeEach(() => {
// Создаем новые экземпляры перед каждым тестом для изоляции
utilsDefault = new CheckboxUtils(defaultSettings);
utilsXOnly = new CheckboxUtils(xOnlySettings);
utilsParentSyncDisabled = new CheckboxUtils(settingsParentSyncDisabled);
utilsChildSyncDisabled = new CheckboxUtils(settingsChildSyncDisabled);
});
// --- matchCheckboxLine ---
@ -453,7 +473,7 @@ describe('CheckboxUtils', () => {
// --- syncText (Integration) ---
describe('syncText', () => {
it('should handle user checking parent (down -> up)', () => {
describe('When user changes parent state directly', () => {
const textBefore = [
'- [ ] Parent',
' - [ ] Child 1',
@ -465,17 +485,27 @@ describe('CheckboxUtils', () => {
' - [ ] Child 2',
].join('\n');
it('should propagate down when child sync is ENABLED', () => {
const result = utilsDefault.syncText(textAfterUserCheck, textBefore);
const expected = [ // Down propagation first, then up (which changes nothing here)
const expected = [
'- [x] Parent',
' - [x] Child 1',
' - [x] Child 2',
' - [x] Child 1', // Propagated down
' - [x] Child 2', // Propagated down
].join('\n');
expect(result).toBe(expected);
});
it('should handle user unchecking parent (down -> up)', () => {
const textBefore = [
it('should NOT propagate down when child sync is DISABLED', () => {
const result = utilsChildSyncDisabled.syncText(textAfterUserCheck, textBefore);
const expected = [ // Ожидаем, что дети НЕ изменились
'- [ ] Parent', // propagateStateFromChildren
' - [ ] Child 1',
' - [ ] Child 2',
].join('\n');
expect(result).toBe(expected);
});
const textBeforeUncheck = [
'- [x] Parent',
' - [x] Child 1',
' - [x] Child 2',
@ -486,16 +516,29 @@ describe('CheckboxUtils', () => {
' - [x] Child 2',
].join('\n');
const result = utilsDefault.syncText(textAfterUserUncheck, textBefore);
const expected = [ // Down propagation first, then up
it('should propagate down (uncheck) when child sync is ENABLED', () => {
const result = utilsDefault.syncText(textAfterUserUncheck, textBeforeUncheck);
const expected = [
'- [ ] Parent',
' - [ ] Child 1',
' - [ ] Child 2',
' - [ ] Child 1', // Propagated down
' - [ ] Child 2', // Propagated down
].join('\n');
expect(result).toBe(expected);
});
it('should handle user checking the last child, making parent checked (no down -> up)', () => {
it('should NOT propagate down (uncheck) when child sync is DISABLED', () => {
const result = utilsChildSyncDisabled.syncText(textAfterUserUncheck, textBeforeUncheck);
const expected = [ // Ожидаем, что дети НЕ изменились
'- [x] Parent', // propagateStateFromChildren
' - [x] Child 1',
' - [x] Child 2',
].join('\n');
expect(result).toBe(expected);
});
});
it('should update parent when parent sync is ENABLED and user checks last child', () => {
const textBefore = [
'- [ ] Parent',
' - [x] Child 1',
@ -517,7 +560,27 @@ describe('CheckboxUtils', () => {
expect(result).toBe(expected);
});
it('should handle user unchecking one child, making parent unchecked (no down -> up)', () => {
it('should NOT update parent when parent sync is DISABLED and user checks last child', () => {
const textBefore = [
'- [ ] Parent',
' - [x] Child 1',
' - [ ] Child 2', // User will check this
].join('\n');
const textAfterChildCheck = [
'- [ ] Parent', // State before syncText runs propagateFromChildren
' - [x] Child 1',
' - [x] Child 2', // User checked this
].join('\n');
const result = utilsParentSyncDisabled.syncText(textAfterChildCheck, textBefore); // Использует utilsParentSyncDisabled
const expected = [ // Родитель НЕ должен обновиться
'- [ ] Parent',
' - [x] Child 1',
' - [x] Child 2',
].join('\n');
expect(result).toBe(expected);
});
it('should update parent when parent sync is ENABLED and user unchecks child', () => {
const textBefore = [
'- [x] Parent',
' - [x] Child 1', // User will uncheck this
@ -539,7 +602,27 @@ describe('CheckboxUtils', () => {
expect(result).toBe(expected);
});
it('should handle multiple changes correctly (no down -> up)', () => {
it('should NOT update parent when parent sync is DISABLED and user unchecks child', () => {
const textBefore = [
'- [x] Parent',
' - [x] Child 1', // User will uncheck this
' - [x] Child 2',
].join('\n');
const textAfterChildUncheck = [
'- [x] Parent', // State before syncText runs propagateFromChildren
' - [ ] Child 1', // User unchecked this
' - [x] Child 2',
].join('\n');
const result = utilsParentSyncDisabled.syncText(textAfterChildUncheck, textBefore); // utilsParentSyncDisabled
const expected = [ // Родитель НЕ должен обновиться
'- [x] Parent',
' - [ ] Child 1',
' - [x] Child 2',
].join('\n');
expect(result).toBe(expected);
});
it('should update parent based on children when multiple lines change and parent sync is ENABLED', () => {
const textBefore = [
'- [ ] Parent',
' - [ ] Child 1',
@ -566,5 +649,25 @@ describe('CheckboxUtils', () => {
expect(result).toBe(expected);
});
it('should NOT update parent when multiple lines change and parent sync is DISABLED', () => {
const textBefore = [
'- [ ] Parent',
' - [ ] Child 1',
' - [ ] Child 2',
].join('\n');
const textAfterMultipleChanges = [ // User checks Parent and Child 1
'- [x] Parent',
' - [x] Child 1',
' - [ ] Child 2',
].join('\n');
const result = utilsParentSyncDisabled.syncText(textAfterMultipleChanges, textBefore); // utilsParentSyncDisabled
const expected = [ // Родитель НЕ корректируется, остается как есть
'- [x] Parent',
' - [x] Child 1',
' - [ ] Child 2',
].join('\n');
expect(result).toBe(expected);
});
});
});

View file

@ -5,8 +5,8 @@ describe("CheckboxUtils old", () => {
let checkboxUtilsSpaceOnly: CheckboxUtils;
beforeEach(() => {
checkboxUtilsXOnly = new CheckboxUtils({ xOnlyMode: true });
checkboxUtilsSpaceOnly = new CheckboxUtils({ xOnlyMode: false });
checkboxUtilsXOnly = new CheckboxUtils({ xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true, });
checkboxUtilsSpaceOnly = new CheckboxUtils({ xOnlyMode: false, enableAutomaticParentState: true, enableAutomaticChildState: true,});
});
describe("findCheckboxesLine", () => {
@ -120,7 +120,7 @@ describe("CheckboxUtils old", () => {
describe("updateSettings", () => {
test("updates xOnlyMode setting correctly", () => {
const settings = { xOnlyMode: true };
const settings = { xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true,};
const utils = new CheckboxUtils(settings);
expect(utils.isCheckedSymbol("-")).toBe(false);

View file

@ -20,10 +20,32 @@ export class CheckboxSyncPluginSettingTab extends PluginSettingTab {
toggle
.setValue(this.plugin.settings.xOnlyMode)
.onChange(async (value) => {
await this.plugin.updateSettings((settings) => {
await this.plugin.updateSettings(settings => {
settings.xOnlyMode = value;
});
})
);
new Setting(containerEl)
.setName('Update parent checkbox state automatically')
.setDesc('If enabled, the state of a parent checkbox will be automatically updated based on the state of its children (all children checked = parent checked). If disabled, only manually changing a parent will affect its children.')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableAutomaticParentState)
.onChange(async (value) => {
await this.plugin.updateSettings(settings => {
settings.enableAutomaticParentState = value;
});
}));
new Setting(containerEl)
.setName('Update child checkbox state automatically')
.setDesc('If enabled, changing the state of a parent checkbox will automatically update the state of all its direct and nested children. If disabled, changing a parent checkbox will not affect its children.')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableAutomaticChildState)
.onChange(async (value) => {
await this.plugin.updateSettings(settings => {
settings.enableAutomaticChildState = value;
});
}));
}
}

View file

@ -100,9 +100,13 @@ export class CheckboxUtils {
}
syncText(text: string, textBefore: string | undefined): string {
let newText;
let newText = text;
if (this.settings.enableAutomaticChildState) {
newText = this.propagateStateToChildrenFromSingleDiff(text, textBefore);
}
if (this.settings.enableAutomaticParentState) {
newText = this.propagateStateFromChildren(newText);
}
return newText;
}

View file

@ -9,6 +9,8 @@ import { FileChangeEventHandler } from "./events/FileChangeEventHandler";
const DEFAULT_SETTINGS: CheckboxSyncPluginSettings = {
xOnlyMode: true,
enableAutomaticParentState: true,
enableAutomaticChildState: true,
};
export default class CheckboxSyncPlugin extends Plugin {

View file

@ -1,3 +1,5 @@
export interface CheckboxSyncPluginSettings {
xOnlyMode: boolean;
enableAutomaticParentState: boolean;
enableAutomaticChildState: boolean;
}