Skip to content

Commit 8af3723

Browse files
committed
make input fields mostly independent from the obsidian api
1 parent 3591a4c commit 8af3723

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+578
-325
lines changed

exampleVault/Examples.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
slider1: 8
2+
slider1: 4
33
suggest: test
44
toggle1: false
55
Domestic_tasks:

src/IPlugin.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { type IAPI } from './api/IAPI';
22
import { type MetaBindPluginSettings } from './settings/Settings';
3+
import { type MetadataManager } from './metadata/MetadataManager';
4+
import { type IInternalAPI } from './internalApi/IInternalAPI';
35

46
export interface IPlugin {
5-
api: IAPI;
7+
readonly api: IAPI;
8+
readonly internal: IInternalAPI;
9+
readonly metadataManager: MetadataManager;
10+
611
settings: MetaBindPluginSettings;
12+
713
getFilePathsByName: (name: string) => string[];
814
}

src/fields/inputFields/AbstractInputField.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
import { type InputFieldMDRC } from '../../renderChildren/InputFieldMDRC';
21
import { InputFieldComponent } from './InputFieldComponent';
32
import { type SvelteComponent } from 'svelte';
4-
import { ComputedSignal, type Listener, Notifier } from '../../utils/Signal';
3+
import { ComputedSignal, Signal } from '../../utils/Signal';
54

65
import { InputFieldArgumentType } from '../../config/FieldConfigs';
6+
import { type IInputFieldBase } from './IInputFieldBase';
7+
import { type MetadataSubscription } from '../../metadata/MetadataSubscription';
78

8-
export abstract class AbstractInputField<MetadataValueType, ComponentValueType> extends Notifier<
9-
MetadataValueType,
10-
Listener<MetadataValueType>
11-
> {
12-
readonly renderChild: InputFieldMDRC;
9+
export abstract class AbstractInputField<MetadataValueType, ComponentValueType> {
10+
readonly renderChild: IInputFieldBase;
1311
readonly inputFieldComponent: InputFieldComponent<ComponentValueType>;
12+
readonly inputSignal: Signal<unknown>;
1413
readonly signal: ComputedSignal<unknown, MetadataValueType>;
1514

16-
protected constructor(renderChild: InputFieldMDRC) {
17-
super();
15+
private metadataSubscription?: MetadataSubscription;
1816

17+
protected constructor(renderChild: IInputFieldBase) {
1918
this.renderChild = renderChild;
19+
this.inputSignal = new Signal<unknown>(undefined);
2020
this.inputFieldComponent = new InputFieldComponent<ComponentValueType>(this.getSvelteComponent());
2121

2222
this.signal = new ComputedSignal<unknown, MetadataValueType>(
23-
this.renderChild.inputSignal,
23+
this.inputSignal,
2424
(value: unknown): MetadataValueType => {
2525
const filteredValue = this.filterValue(value);
2626
return filteredValue ?? this.getDefaultValue();
@@ -31,12 +31,33 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
3131
callback: value => this.inputFieldComponent.setValue(this.reverseMapValue(value)),
3232
});
3333

34-
this.inputFieldComponent.registerListener({
35-
callback: value => {
36-
// console.log('input field component change', value);
37-
this.notifyListeners(this.mapValue(value));
38-
},
39-
});
34+
const fullBindTarget = this.renderChild.getFullBindTarget();
35+
36+
if (fullBindTarget) {
37+
this.inputFieldComponent.registerListener({
38+
callback: value => {
39+
// console.log('input field component change', value);
40+
this.notifySubscription(this.mapValue(value));
41+
},
42+
});
43+
44+
this.metadataSubscription = this.renderChild.plugin.metadataManager.subscribe(
45+
this.renderChild.getUuid(),
46+
this.inputSignal,
47+
fullBindTarget,
48+
() => this.renderChild.unload(),
49+
);
50+
}
51+
}
52+
53+
public destroy(): void {
54+
// we don't need to unregister the listener because the component will destroy all listeners on unmount
55+
56+
if (this.inputFieldComponent.isMounted()) {
57+
this.unmount();
58+
}
59+
60+
this.metadataSubscription?.unsubscribe();
4061
}
4162

4263
protected abstract getSvelteComponent(): typeof SvelteComponent;
@@ -96,7 +117,7 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
96117
*/
97118
public setValue(value: MetadataValueType): void {
98119
this.signal.set(value);
99-
this.notifyListeners(value);
120+
this.notifySubscription(value);
100121
}
101122

102123
/**
@@ -108,6 +129,10 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
108129
this.setValue(this.mapValue(value));
109130
}
110131

132+
private notifySubscription(value: MetadataValueType): void {
133+
this.metadataSubscription?.update(value);
134+
}
135+
111136
private getDefaultValue(): MetadataValueType {
112137
const defaultValueArgument = this.renderChild.getArgument(InputFieldArgumentType.DEFAULT_VALUE);
113138
if (!defaultValueArgument) {
@@ -128,4 +153,8 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
128153
public unmount(): void {
129154
this.inputFieldComponent.unmount();
130155
}
156+
157+
protected onmount(): void {}
158+
159+
protected onunmount(): void {}
131160
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { type BindTargetDeclaration, type FullBindTarget } from '../../parsers/inputFieldParser/InputFieldDeclaration';
2+
import { type InputFieldArgumentType } from '../../config/FieldConfigs';
3+
import { type InputFieldArgumentMapType } from '../fieldArguments/inputFieldArguments/InputFieldArgumentFactory';
4+
import { type IPlugin } from '../../IPlugin';
5+
6+
export interface IInputFieldBase {
7+
readonly plugin: IPlugin;
8+
9+
getUuid(): string;
10+
11+
getFilePath(): string;
12+
13+
isBound(): boolean;
14+
15+
getBindTarget(): BindTargetDeclaration | undefined;
16+
17+
getFullBindTarget(): FullBindTarget | undefined;
18+
19+
getArguments<T extends InputFieldArgumentType>(name: T): InputFieldArgumentMapType<T>[];
20+
21+
getArgument<T extends InputFieldArgumentType>(name: T): InputFieldArgumentMapType<T> | undefined;
22+
23+
load(): void;
24+
25+
unload(): void;
26+
}

src/fields/inputFields/InputFieldComponent.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { type Listener, Notifier } from '../../utils/Signal';
44
export class InputFieldComponent<Value> extends Notifier<Value, Listener<Value>> {
55
private readonly svelteComponent: typeof SvelteComponent;
66
private svelteComponentInstance?: SvelteComponent;
7+
private mounted: boolean;
78

89
constructor(svelteComponent: typeof SvelteComponent) {
910
super();
1011

12+
this.mounted = false;
1113
this.svelteComponent = svelteComponent;
1214
}
1315

@@ -45,6 +47,8 @@ export class InputFieldComponent<Value> extends Notifier<Value, Listener<Value>>
4547
target: container,
4648
props: props,
4749
});
50+
51+
this.mounted = true;
4852
}
4953

5054
/**
@@ -53,5 +57,11 @@ export class InputFieldComponent<Value> extends Notifier<Value, Listener<Value>>
5357
public unmount(): void {
5458
this.listeners = [];
5559
this.svelteComponentInstance?.$destroy();
60+
61+
this.mounted = false;
62+
}
63+
64+
public isMounted(): boolean {
65+
return this.mounted;
5666
}
5767
}

src/fields/inputFields/InputFieldFactory.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type InputFieldMDRC, RenderChildType } from '../../renderChildren/InputFieldMDRC';
1+
import { RenderChildType } from '../../renderChildren/InputFieldMDRC';
22
import { ErrorLevel, MetaBindParsingError } from '../../utils/errors/MetaBindErrors';
33
import { type IPlugin } from '../../IPlugin';
44
import { ToggleIPF } from './fields/Toggle/ToggleIPF';
@@ -22,8 +22,9 @@ import { type InputFieldConfig, InputFieldConfigs, InputFieldType } from '../../
2222
import { DocsHelper } from '../../utils/DocsHelper';
2323
import { InlineListSuggesterIPF } from './fields/InlineListSuggester/InlineListSuggesterIPF';
2424
import { InlineListIPF } from './fields/InlineList/InlineListIPF';
25+
import { type IInputFieldBase } from './IInputFieldBase';
2526

26-
export type NewInputField =
27+
export type InputField =
2728
| ToggleIPF
2829
| SliderIPF
2930
| TextIPF
@@ -54,8 +55,8 @@ export class InputFieldFactory {
5455
createInputField(
5556
type: InputFieldType,
5657
renderChildType: RenderChildType,
57-
renderChild: InputFieldMDRC,
58-
): NewInputField | undefined {
58+
renderChild: IInputFieldBase,
59+
): InputField | undefined {
5960
if (type !== InputFieldType.INVALID) {
6061
this.checkRenderChildTypeAllowed(type, renderChildType);
6162
}

src/fields/inputFields/fields/Date/DateIPF.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { AbstractInputField } from '../../AbstractInputField';
22
import { type moment } from 'obsidian';
33
import { type SvelteComponent } from 'svelte';
4-
import { type InputFieldMDRC } from '../../../../renderChildren/InputFieldMDRC';
54
import { DateParser } from '../../../../parsers/DateParser';
65
import DateComponent from './DateComponent.svelte';
76
import { parseUnknownToString } from '../../../../utils/Literal';
7+
import { type IInputFieldBase } from '../../IInputFieldBase';
88

99
export class DateIPF extends AbstractInputField<string, moment.Moment> {
10-
constructor(renderChild: InputFieldMDRC) {
10+
constructor(renderChild: IInputFieldBase) {
1111
super(renderChild);
1212
}
1313

src/fields/inputFields/fields/DatePicker/DatePickerIPF.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { AbstractInputField } from '../../AbstractInputField';
22
import { type OptionInputFieldArgument } from '../../../fieldArguments/inputFieldArguments/arguments/OptionInputFieldArgument';
3-
import { type InputFieldMDRC } from '../../../../renderChildren/InputFieldMDRC';
43
import { type SvelteComponent } from 'svelte';
54
import { type moment } from 'obsidian';
65
import DatePickerComponent from './DatePickerComponent.svelte';
76
import { DateParser } from '../../../../parsers/DateParser';
8-
import { DatePickerInputModal } from './DatePickerInputModal';
97
import { InputFieldArgumentType } from '../../../../config/FieldConfigs';
8+
import { type IInputFieldBase } from '../../IInputFieldBase';
109

1110
export class DatePickerIPF extends AbstractInputField<string | null, moment.Moment | null> {
1211
options: OptionInputFieldArgument[];
1312

14-
constructor(renderChild: InputFieldMDRC) {
13+
constructor(renderChild: IInputFieldBase) {
1514
super(renderChild);
1615

1716
this.options = this.renderChild.getArguments(InputFieldArgumentType.OPTION);
@@ -63,7 +62,7 @@ export class DatePickerIPF extends AbstractInputField<string | null, moment.Mome
6362
return {
6463
dateFormat: this.renderChild.plugin.settings.preferredDateFormat,
6564
showDatePicker: (): void => {
66-
new DatePickerInputModal(this.renderChild.plugin.app, this).open();
65+
this.renderChild.plugin.internal.openDatePickerModal(this);
6766
},
6867
};
6968
}

src/fields/inputFields/fields/Editor/EditorIPF.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { AbstractInputField } from '../../AbstractInputField';
2-
import { type InputFieldMDRC } from '../../../../renderChildren/InputFieldMDRC';
32
import { type SvelteComponent } from 'svelte';
43
import EditorComponent from './EditorComponent.svelte';
5-
import { MarkdownRenderer } from 'obsidian';
64
import { isLiteral } from '../../../../utils/Literal';
5+
import { type IInputFieldBase } from '../../IInputFieldBase';
76

87
export class EditorIPF extends AbstractInputField<string, string> {
9-
constructor(renderChild: InputFieldMDRC) {
8+
mdUnloadCallback: (() => void) | undefined;
9+
10+
constructor(renderChild: IInputFieldBase) {
1011
super(renderChild);
1112
}
1213

@@ -32,18 +33,22 @@ export class EditorIPF extends AbstractInputField<string, string> {
3233

3334
protected getMountArgs(): Record<string, unknown> {
3435
return {
35-
render: (el: HTMLElement, value: string) => this.renderInElement(el, value),
36+
render: (el: HTMLElement, value: string) => void this.renderInElement(el, value),
3637
};
3738
}
3839

39-
renderInElement(el: HTMLElement, value: string): void {
40+
async renderInElement(el: HTMLElement, value: string): Promise<void> {
41+
this.mdUnloadCallback?.();
4042
el.empty();
41-
void MarkdownRenderer.render(
42-
this.renderChild.plugin.app,
43+
this.mdUnloadCallback = await this.renderChild.plugin.internal.renderMarkdown(
4344
value,
4445
el,
45-
this.renderChild.filePath,
46-
this.renderChild,
46+
this.renderChild.getFilePath(),
4747
);
4848
}
49+
50+
protected onunmount(): void {
51+
super.onunmount();
52+
this.mdUnloadCallback?.();
53+
}
4954
}

src/fields/inputFields/fields/ImageSuggester/ImageSuggesterIPF.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { AbstractInputField } from '../../AbstractInputField';
2-
import { type InputFieldMDRC } from '../../../../renderChildren/InputFieldMDRC';
32
import { type SvelteComponent } from 'svelte';
43
import ImageSuggesterComponent from './ImageSuggesterComponent.svelte';
5-
import { openImageSuggesterModalForInputField } from './ImageSuggesterHelper';
64
import { isLiteral, type MBLiteral, stringifyLiteral } from '../../../../utils/Literal';
5+
import { type IInputFieldBase } from '../../IInputFieldBase';
76

87
export class ImageSuggesterIPF extends AbstractInputField<MBLiteral, string> {
9-
constructor(renderChild: InputFieldMDRC) {
8+
constructor(renderChild: IInputFieldBase) {
109
super(renderChild);
1110
}
1211

@@ -37,6 +36,6 @@ export class ImageSuggesterIPF extends AbstractInputField<MBLiteral, string> {
3736
}
3837

3938
openModal(): void {
40-
openImageSuggesterModalForInputField(this, selected => this.setInternalValue(selected));
39+
this.renderChild.plugin.internal.openImageSuggesterModal(this, selected => this.setInternalValue(selected));
4140
}
4241
}

0 commit comments

Comments
 (0)