mirror of
https://github.com/groldsf/obsidian_check_plugin.git
synced 2026-07-22 05:37:48 +00:00
add settings
This commit is contained in:
parent
c751add5fe
commit
3d1ea00009
6 changed files with 178 additions and 45 deletions
|
|
@ -1,25 +1,45 @@
|
||||||
// checkboxUtils.test.ts
|
// checkboxUtils.test.ts
|
||||||
import { CheckboxUtils, CheckboxLineInfo } from '../src/checkboxUtils';
|
import { CheckboxUtils } from '../src/checkboxUtils';
|
||||||
import { CheckboxSyncPluginSettings } from '../src/types'; // Предполагаем, что типы в types.ts
|
import { CheckboxSyncPluginSettings } from '../src/types'; // Предполагаем, что типы в types.ts
|
||||||
|
|
||||||
// --- Mock Settings ---
|
// --- Mock Settings ---
|
||||||
const defaultSettings: Readonly<CheckboxSyncPluginSettings> = {
|
const defaultSettings: Readonly<CheckboxSyncPluginSettings> = {
|
||||||
xOnlyMode: false, // По умолчанию: любой не-пробел считается 'checked'
|
xOnlyMode: false, // По умолчанию: любой не-пробел считается 'checked'
|
||||||
|
enableAutomaticParentState: true,
|
||||||
|
enableAutomaticChildState: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const xOnlySettings: Readonly<CheckboxSyncPluginSettings> = {
|
const xOnlySettings: Readonly<CheckboxSyncPluginSettings> = {
|
||||||
xOnlyMode: true, // Только 'x' считается 'checked'
|
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 ---
|
// --- Test Suite ---
|
||||||
describe('CheckboxUtils', () => {
|
describe('CheckboxUtils', () => {
|
||||||
let utilsDefault: CheckboxUtils;
|
let utilsDefault: CheckboxUtils;
|
||||||
let utilsXOnly: CheckboxUtils;
|
let utilsXOnly: CheckboxUtils;
|
||||||
|
let utilsParentSyncDisabled: CheckboxUtils;
|
||||||
|
let utilsChildSyncDisabled: CheckboxUtils
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Создаем новые экземпляры перед каждым тестом для изоляции
|
// Создаем новые экземпляры перед каждым тестом для изоляции
|
||||||
utilsDefault = new CheckboxUtils(defaultSettings);
|
utilsDefault = new CheckboxUtils(defaultSettings);
|
||||||
utilsXOnly = new CheckboxUtils(xOnlySettings);
|
utilsXOnly = new CheckboxUtils(xOnlySettings);
|
||||||
|
utilsParentSyncDisabled = new CheckboxUtils(settingsParentSyncDisabled);
|
||||||
|
utilsChildSyncDisabled = new CheckboxUtils(settingsChildSyncDisabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- matchCheckboxLine ---
|
// --- matchCheckboxLine ---
|
||||||
|
|
@ -453,49 +473,72 @@ describe('CheckboxUtils', () => {
|
||||||
|
|
||||||
// --- syncText (Integration) ---
|
// --- syncText (Integration) ---
|
||||||
describe('syncText', () => {
|
describe('syncText', () => {
|
||||||
it('should handle user checking parent (down -> up)', () => {
|
describe('When user changes parent state directly', () => {
|
||||||
const textBefore = [
|
const textBefore = [
|
||||||
'- [ ] Parent',
|
'- [ ] Parent',
|
||||||
' - [ ] Child 1',
|
' - [ ] Child 1',
|
||||||
' - [ ] Child 2',
|
' - [ ] Child 2',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
const textAfterUserCheck = [
|
const textAfterUserCheck = [
|
||||||
'- [x] Parent', // User checked this
|
'- [x] Parent', // User checked this
|
||||||
' - [ ] Child 1',
|
' - [ ] Child 1',
|
||||||
' - [ ] Child 2',
|
' - [ ] Child 2',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const result = utilsDefault.syncText(textAfterUserCheck, textBefore);
|
it('should propagate down when child sync is ENABLED', () => {
|
||||||
const expected = [ // Down propagation first, then up (which changes nothing here)
|
const result = utilsDefault.syncText(textAfterUserCheck, textBefore);
|
||||||
'- [x] Parent',
|
const expected = [
|
||||||
' - [x] Child 1',
|
'- [x] Parent',
|
||||||
' - [x] Child 2',
|
' - [x] Child 1', // Propagated down
|
||||||
].join('\n');
|
' - [x] Child 2', // Propagated down
|
||||||
expect(result).toBe(expected);
|
].join('\n');
|
||||||
});
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle user unchecking parent (down -> up)', () => {
|
it('should NOT propagate down when child sync is DISABLED', () => {
|
||||||
const textBefore = [
|
const result = utilsChildSyncDisabled.syncText(textAfterUserCheck, textBefore);
|
||||||
'- [x] Parent',
|
const expected = [ // Ожидаем, что дети НЕ изменились
|
||||||
' - [x] Child 1',
|
'- [ ] Parent', // propagateStateFromChildren
|
||||||
' - [x] Child 2',
|
' - [ ] Child 1',
|
||||||
|
' - [ ] Child 2',
|
||||||
|
].join('\n');
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
const textBeforeUncheck = [
|
||||||
|
'- [x] Parent',
|
||||||
|
' - [x] Child 1',
|
||||||
|
' - [x] Child 2',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
const textAfterUserUncheck = [
|
const textAfterUserUncheck = [
|
||||||
'- [ ] Parent', // User unchecked this
|
'- [ ] Parent', // User unchecked this
|
||||||
' - [x] Child 1',
|
' - [x] Child 1',
|
||||||
' - [x] Child 2',
|
' - [x] Child 2',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const result = utilsDefault.syncText(textAfterUserUncheck, textBefore);
|
it('should propagate down (uncheck) when child sync is ENABLED', () => {
|
||||||
const expected = [ // Down propagation first, then up
|
const result = utilsDefault.syncText(textAfterUserUncheck, textBeforeUncheck);
|
||||||
'- [ ] Parent',
|
const expected = [
|
||||||
' - [ ] Child 1',
|
'- [ ] Parent',
|
||||||
' - [ ] Child 2',
|
' - [ ] Child 1', // Propagated down
|
||||||
].join('\n');
|
' - [ ] Child 2', // Propagated down
|
||||||
expect(result).toBe(expected);
|
].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 = [
|
const textBefore = [
|
||||||
'- [ ] Parent',
|
'- [ ] Parent',
|
||||||
' - [x] Child 1',
|
' - [x] Child 1',
|
||||||
|
|
@ -517,7 +560,27 @@ describe('CheckboxUtils', () => {
|
||||||
expect(result).toBe(expected);
|
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 = [
|
const textBefore = [
|
||||||
'- [x] Parent',
|
'- [x] Parent',
|
||||||
' - [x] Child 1', // User will uncheck this
|
' - [x] Child 1', // User will uncheck this
|
||||||
|
|
@ -539,7 +602,27 @@ describe('CheckboxUtils', () => {
|
||||||
expect(result).toBe(expected);
|
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 = [
|
const textBefore = [
|
||||||
'- [ ] Parent',
|
'- [ ] Parent',
|
||||||
' - [ ] Child 1',
|
' - [ ] Child 1',
|
||||||
|
|
@ -566,5 +649,25 @@ describe('CheckboxUtils', () => {
|
||||||
expect(result).toBe(expected);
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -5,8 +5,8 @@ describe("CheckboxUtils old", () => {
|
||||||
let checkboxUtilsSpaceOnly: CheckboxUtils;
|
let checkboxUtilsSpaceOnly: CheckboxUtils;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
checkboxUtilsXOnly = new CheckboxUtils({ xOnlyMode: true });
|
checkboxUtilsXOnly = new CheckboxUtils({ xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true, });
|
||||||
checkboxUtilsSpaceOnly = new CheckboxUtils({ xOnlyMode: false });
|
checkboxUtilsSpaceOnly = new CheckboxUtils({ xOnlyMode: false, enableAutomaticParentState: true, enableAutomaticChildState: true,});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("findCheckboxesLine", () => {
|
describe("findCheckboxesLine", () => {
|
||||||
|
|
@ -120,7 +120,7 @@ describe("CheckboxUtils old", () => {
|
||||||
describe("updateSettings", () => {
|
describe("updateSettings", () => {
|
||||||
test("updates xOnlyMode setting correctly", () => {
|
test("updates xOnlyMode setting correctly", () => {
|
||||||
|
|
||||||
const settings = { xOnlyMode: true };
|
const settings = { xOnlyMode: true, enableAutomaticParentState: true, enableAutomaticChildState: true,};
|
||||||
const utils = new CheckboxUtils(settings);
|
const utils = new CheckboxUtils(settings);
|
||||||
expect(utils.isCheckedSymbol("-")).toBe(false);
|
expect(utils.isCheckedSymbol("-")).toBe(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,32 @@ export class CheckboxSyncPluginSettingTab extends PluginSettingTab {
|
||||||
toggle
|
toggle
|
||||||
.setValue(this.plugin.settings.xOnlyMode)
|
.setValue(this.plugin.settings.xOnlyMode)
|
||||||
.onChange(async (value) => {
|
.onChange(async (value) => {
|
||||||
await this.plugin.updateSettings((settings) => {
|
await this.plugin.updateSettings(settings => {
|
||||||
settings.xOnlyMode = value;
|
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;
|
||||||
|
});
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,9 +100,13 @@ export class CheckboxUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
syncText(text: string, textBefore: string | undefined): string {
|
syncText(text: string, textBefore: string | undefined): string {
|
||||||
let newText;
|
let newText = text;
|
||||||
newText = this.propagateStateToChildrenFromSingleDiff(text, textBefore);
|
if (this.settings.enableAutomaticChildState) {
|
||||||
newText = this.propagateStateFromChildren(newText);
|
newText = this.propagateStateToChildrenFromSingleDiff(text, textBefore);
|
||||||
|
}
|
||||||
|
if (this.settings.enableAutomaticParentState) {
|
||||||
|
newText = this.propagateStateFromChildren(newText);
|
||||||
|
}
|
||||||
return newText;
|
return newText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { FileChangeEventHandler } from "./events/FileChangeEventHandler";
|
||||||
|
|
||||||
const DEFAULT_SETTINGS: CheckboxSyncPluginSettings = {
|
const DEFAULT_SETTINGS: CheckboxSyncPluginSettings = {
|
||||||
xOnlyMode: true,
|
xOnlyMode: true,
|
||||||
|
enableAutomaticParentState: true,
|
||||||
|
enableAutomaticChildState: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CheckboxSyncPlugin extends Plugin {
|
export default class CheckboxSyncPlugin extends Plugin {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
export interface CheckboxSyncPluginSettings {
|
export interface CheckboxSyncPluginSettings {
|
||||||
xOnlyMode: boolean;
|
xOnlyMode: boolean;
|
||||||
|
enableAutomaticParentState: boolean;
|
||||||
|
enableAutomaticChildState: boolean;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue