Skip to content

Commit 77356d3

Browse files
committed
refactor view fields
1 parent b15bb20 commit 77356d3

File tree

13 files changed

+279
-224
lines changed

13 files changed

+279
-224
lines changed

exampleVault/Advanced Examples/PF2e DC Calcualtor.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
playerLevel: 5
3-
spellLevel: 12
2+
playerLevel: 10
3+
spellLevel: 5
44
---
55

66
### DC by Proficiency

exampleVault/Button Example.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
count: 3
2+
count: 1
33
---
44
Meta Bind is getting Buttons
55

exampleVault/View Fields/JS View Field.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ result: "**5289** km"
1212
save to {result}
1313
---
1414
return engine.markdown.create(`**${context.bound.n1 * context.bound.n2}** km`);
15-
```
16-
17-
[test](test\ 1.excalidraw)
15+
```

exampleVault/View Fields/View Field.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ object:
1212
key: value
1313
file: Example Note with Embeds
1414
image: Other/Images/img_butterfly.webp
15+
someInputValue: 1
16+
someComputedValue: 2
1517
---
1618

1719
`INPUT[number:number1]`
@@ -70,7 +72,6 @@ Markdown:
7072

7173
Null:
7274
`VIEW[{someUnknownValue}][text]`
73-
some text
7475

75-
Input: `INPUT[number:someComputedValue]`
76+
Input: `INPUT[number:someInputValue]`
7677
Computed Value: `VIEW[{someInputValue} * 2][math:someComputedValue]`

src/fields/inputFields/AbstractInputField.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
130130
}
131131

132132
public mount(container: HTMLElement): void {
133+
this.onmount();
134+
133135
this.computedSignal.registerListener({
134136
callback: value => this.inputFieldComponent.setValue(this.reverseMapValue(value)),
135137
});
@@ -156,6 +158,8 @@ export abstract class AbstractInputField<MetadataValueType, ComponentValueType>
156158
}
157159

158160
public unmount(): void {
161+
this.onunmount();
162+
159163
this.computedSignal.unregisterAllListeners();
160164
this.metadataSubscription?.unsubscribe();
161165

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,108 @@
1-
import { type ViewFieldDeclaration } from '../../parsers/viewFieldParser/ViewFieldDeclaration';
2-
import { type ViewFieldMDRC, type ViewFieldVariable } from '../../renderChildren/ViewFieldMDRC';
1+
import { type ViewFieldVariable } from '../../renderChildren/ViewFieldMDRC';
32

43
import { ViewFieldArgumentType } from '../../config/FieldConfigs';
54
import { stringifyUnknown } from '../../utils/Literal';
5+
import { type IViewFieldBase } from './IViewFieldBase';
6+
import {
7+
type ComputedMetadataSubscription,
8+
type ComputedSubscriptionDependency,
9+
} from '../../metadata/ComputedMetadataSubscription';
10+
import { Signal } from '../../utils/Signal';
611

712
export abstract class AbstractViewField {
8-
protected renderChild: ViewFieldMDRC;
9-
container?: HTMLElement;
13+
readonly base: IViewFieldBase;
14+
readonly inputSignal: Signal<unknown>;
15+
16+
private metadataSubscription?: ComputedMetadataSubscription;
17+
18+
variables: ViewFieldVariable[];
1019

20+
container?: HTMLElement;
1121
// hidden argument
22+
1223
hidden: boolean;
1324

14-
protected constructor(renderChild: ViewFieldMDRC) {
15-
this.renderChild = renderChild;
25+
protected constructor(base: IViewFieldBase) {
26+
this.base = base;
27+
this.inputSignal = new Signal<unknown>(undefined);
28+
29+
this.variables = [];
30+
1631
this.hidden = false;
1732
}
1833

19-
abstract buildVariables(declaration: ViewFieldDeclaration): ViewFieldVariable[];
34+
protected abstract buildVariables(): void;
2035

2136
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
22-
abstract computeValue(variables: ViewFieldVariable[]): unknown | Promise<unknown>;
23-
24-
abstract getDefaultDisplayValue(): string;
37+
protected abstract computeValue(): unknown | Promise<unknown>;
2538

26-
async render(container: HTMLElement): Promise<void> {
39+
private async initialRender(container: HTMLElement): Promise<void> {
2740
this.container = container;
2841
this.container.addClass('mb-view-text');
2942

30-
this.hidden = this.renderChild.getArgument(ViewFieldArgumentType.HIDDEN)?.value ?? false;
43+
this.hidden = this.base.getArgument(ViewFieldArgumentType.HIDDEN)?.value ?? false;
3144

3245
if (this.hidden) {
3346
this.container.addClass('mb-view-hidden');
3447
}
3548

36-
await this._render(container);
49+
await this.onInitialRender(container);
3750

38-
await this.update(this.getDefaultDisplayValue());
51+
await this.rerender('');
3952
}
4053

41-
async update(value: unknown): Promise<void> {
54+
protected abstract onInitialRender(container: HTMLElement): void | Promise<void>;
55+
56+
private async rerender(value: unknown): Promise<void> {
4257
if (!this.container) {
4358
return;
4459
}
4560

4661
if (!this.hidden) {
47-
const text = stringifyUnknown(value, this.renderChild.plugin.settings.viewFieldDisplayNullAsEmpty) ?? '';
62+
const text = stringifyUnknown(value, this.base.plugin.settings.viewFieldDisplayNullAsEmpty) ?? '';
4863
this.container.empty();
49-
await this._update(this.container, text);
64+
await this.onRerender(this.container, text);
5065
}
5166
}
5267

53-
protected abstract _render(container: HTMLElement): void | Promise<void>;
68+
protected abstract onRerender(container: HTMLElement, text: string): void | Promise<void>;
69+
70+
public destroy(): void {
71+
this.unmount();
72+
}
73+
74+
public mount(container: HTMLElement): void {
75+
this.onmount();
76+
77+
this.buildVariables();
78+
79+
this.inputSignal.registerListener({ callback: value => void this.rerender(value) });
80+
81+
this.metadataSubscription = this.base.plugin.metadataManager.subscribeComputed(
82+
this.base.getUuid(),
83+
this.inputSignal,
84+
this.base.getDeclaration().writeToBindTarget,
85+
this.variables.map((x): ComputedSubscriptionDependency => {
86+
return {
87+
bindTarget: x.bindTargetDeclaration,
88+
callbackSignal: x.inputSignal,
89+
};
90+
}),
91+
async () => await this.computeValue(),
92+
() => this.base.unload(),
93+
);
94+
95+
void this.initialRender(container);
96+
}
97+
98+
public unmount(): void {
99+
this.onunmount();
100+
101+
this.inputSignal.unregisterAllListeners();
102+
this.metadataSubscription?.unsubscribe();
103+
}
54104

55-
protected abstract _update(container: HTMLElement, text: string): void | Promise<void>;
105+
protected onmount(): void {}
56106

57-
abstract destroy(): void;
107+
protected onunmount(): void {}
58108
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { type ViewFieldArgumentType } from '../../config/FieldConfigs';
2+
import { type IPlugin } from '../../IPlugin';
3+
import { type ViewFieldArgumentMapType } from '../fieldArguments/viewFieldArguments/ViewFieldArgumentFactory';
4+
import { type ViewFieldDeclaration } from '../../parsers/viewFieldParser/ViewFieldDeclaration';
5+
6+
export interface IViewFieldBase {
7+
readonly plugin: IPlugin;
8+
9+
getUuid(): string;
10+
11+
getFilePath(): string;
12+
13+
getDeclaration(): ViewFieldDeclaration;
14+
15+
getArguments<T extends ViewFieldArgumentType>(name: T): ViewFieldArgumentMapType<T>[];
16+
17+
getArgument<T extends ViewFieldArgumentType>(name: T): ViewFieldArgumentMapType<T> | undefined;
18+
19+
load(): void;
20+
21+
unload(): void;
22+
}
Lines changed: 34 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { AbstractViewField } from '../AbstractViewField';
2-
import { type ViewFieldMDRC, type ViewFieldVariable } from '../../../renderChildren/ViewFieldMDRC';
3-
import { type ViewFieldDeclaration } from '../../../parsers/viewFieldParser/ViewFieldDeclaration';
2+
import { type ViewFieldMDRC } from '../../../renderChildren/ViewFieldMDRC';
43
import { Signal } from '../../../utils/Signal';
54
import { getUUID } from '../../../utils/Utils';
65
import { ErrorLevel, MetaBindExpressionError, MetaBindValidationError } from '../../../utils/errors/MetaBindErrors';
@@ -15,11 +14,11 @@ export class LinkVF extends AbstractViewField {
1514
super(renderChild);
1615
}
1716

18-
public buildVariables(declaration: ViewFieldDeclaration): ViewFieldVariable[] {
17+
protected buildVariables(): void {
1918
// filter out empty strings
20-
const entries: (string | BindTargetDeclaration)[] = declaration.templateDeclaration.filter(x =>
21-
typeof x === 'string' ? x : true,
22-
);
19+
const entries: (string | BindTargetDeclaration)[] = this.base
20+
.getDeclaration()
21+
.templateDeclaration.filter(x => (typeof x === 'string' ? x : true));
2322

2423
if (entries.length !== 1) {
2524
throw new MetaBindValidationError({
@@ -38,87 +37,62 @@ export class LinkVF extends AbstractViewField {
3837
});
3938
}
4039

41-
const variable: ViewFieldVariable = {
42-
bindTargetDeclaration: firstEntry,
43-
inputSignal: new Signal<unknown>(undefined),
44-
uuid: getUUID(),
45-
contextName: `MB_VAR_0`,
46-
};
47-
48-
return [variable];
49-
}
50-
51-
protected _render(container: HTMLElement): void {
52-
this.component = new LinkListComponent({
53-
target: container,
54-
props: {
55-
mdLinkList: [],
40+
this.variables = [
41+
{
42+
bindTargetDeclaration: firstEntry,
43+
inputSignal: new Signal<unknown>(undefined),
44+
uuid: getUUID(),
45+
contextName: `MB_VAR_0`,
5646
},
57-
});
58-
}
59-
60-
protected async _update(container: HTMLElement, text: string): Promise<void> {
61-
const linkList = MDLinkParser.parseLinkList(text);
62-
this.component = new LinkListComponent({
63-
target: container,
64-
props: {
65-
mdLinkList: linkList,
66-
},
67-
});
68-
}
69-
70-
public destroy(): void {
71-
this.component?.$destroy();
47+
];
7248
}
7349

74-
computeValue(variables: ViewFieldVariable[]): string {
75-
if (variables.length !== 1) {
50+
protected computeValue(): string {
51+
if (this.variables.length !== 1) {
7652
throw new MetaBindExpressionError({
7753
errorLevel: ErrorLevel.CRITICAL,
7854
effect: 'failed to evaluate link view field',
7955
cause: 'there should be exactly one variable',
8056
});
8157
}
8258

83-
const variable = variables[0];
59+
const variable = this.variables[0];
8460
const content = variable.inputSignal.get();
8561

8662
// we want the return value to be a human-readable string, since someone could save this to the frontmatter
8763
if (typeof content === 'string') {
88-
return this.convertToLink(content);
64+
return MDLinkParser.convertToLinkString(content);
8965
} else if (Array.isArray(content)) {
9066
const strings = content.filter(x => typeof x === 'string') as string[];
9167
return strings
92-
.map(x => this.convertToLink(x))
68+
.map(x => MDLinkParser.convertToLinkString(x))
9369
.filter(x => x !== '')
9470
.join(', ');
9571
} else {
9672
return '';
9773
}
9874
}
9975

100-
convertToLink(str: string): string {
101-
if (MDLinkParser.isLink(str)) {
102-
return str;
103-
} else if (MDLinkParser.isLink(`[[${str}]]`)) {
104-
return `[[${str}]]`;
105-
} else if (this.getUrl(str)) {
106-
const url = this.getUrl(str)!;
107-
return `[${url.hostname}](${str})`;
108-
} else {
109-
return '';
110-
}
76+
protected onInitialRender(container: HTMLElement): void {
77+
this.component = new LinkListComponent({
78+
target: container,
79+
props: {
80+
mdLinkList: [],
81+
},
82+
});
11183
}
11284

113-
getUrl(str: string): URL | undefined {
114-
try {
115-
return new URL(str);
116-
} catch (e) {
117-
return undefined;
118-
}
85+
protected async onRerender(container: HTMLElement, text: string): Promise<void> {
86+
const linkList = MDLinkParser.parseLinkList(text);
87+
this.component = new LinkListComponent({
88+
target: container,
89+
props: {
90+
mdLinkList: linkList,
91+
},
92+
});
11993
}
12094

121-
public getDefaultDisplayValue(): string {
122-
return '';
95+
protected onunmount(): void {
96+
this.component?.$destroy();
12397
}
12498
}

0 commit comments

Comments
 (0)