Skip to content

Commit 89e8245

Browse files
committed
date picker start
1 parent 8820763 commit 89e8245

File tree

6 files changed

+276
-6
lines changed

6 files changed

+276
-6
lines changed

src/inputFields/AbstractInputField.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,38 @@ export abstract class AbstractInputField {
1212
}
1313

1414
/**
15-
* This will return the current content of the input field.
15+
* Returns the current content of the input field
1616
*/
1717
abstract getValue(): any;
1818

1919
/**
20-
* This will set the value on this input field, overriding the current content.
20+
* Sets the value on this input field, overriding the current content
2121
*
2222
* @param value
2323
*/
2424
abstract setValue(value: any): void;
2525

26+
/**
27+
* Checks if the value is the same as the value of this input field
28+
*
29+
* @param value
30+
*/
2631
abstract isEqualValue(value: any): boolean;
2732

33+
/**
34+
* Returns the default value of this input field
35+
*/
2836
abstract getDefaultValue(): any;
2937

38+
/**
39+
* Returns the HTML element this input field is wrapped in
40+
*/
3041
abstract getHtmlElement(): HTMLElement;
3142

43+
/**
44+
* Renders the input field as a child of the container
45+
*
46+
* @param container
47+
*/
3248
abstract render(container: HTMLDivElement): void;
3349
}

src/inputFields/DateInputField.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import {AbstractInputField} from './AbstractInputField';
2+
import {DropdownComponent} from 'obsidian';
3+
import {InputFieldMarkdownRenderChild} from '../InputFieldMarkdownRenderChild';
4+
5+
export class DateInputField extends AbstractInputField {
6+
container: HTMLDivElement;
7+
month: string;
8+
day: string;
9+
year: string;
10+
11+
months: Record<string, string> = {
12+
'1': 'January',
13+
'2': 'February',
14+
'3': 'March',
15+
'4': 'April',
16+
'5': 'May',
17+
'6': 'June',
18+
'7': 'July',
19+
'8': 'August',
20+
'9': 'September',
21+
'10': 'October',
22+
'11': 'November',
23+
'12': 'December',
24+
}
25+
days: Record<string, string>;
26+
years: Record<string, string>;
27+
28+
monthComponent: DropdownComponent;
29+
dayComponent: DropdownComponent;
30+
yearComponent: DropdownComponent;
31+
32+
33+
constructor(inputFieldMarkdownRenderChild: InputFieldMarkdownRenderChild, onValueChange: (value: any) => (void | Promise<void>)) {
34+
super(inputFieldMarkdownRenderChild, onValueChange);
35+
36+
this.days = {};
37+
for (let i = 0; i < 31; i++) {
38+
this.days[i.toString()] = i.toString();
39+
}
40+
41+
this.years = {};
42+
for (let i = 1970; i < 2030; i++) {
43+
this.years[i.toString()] = i.toString();
44+
}
45+
}
46+
47+
public getHtmlElement(): HTMLElement {
48+
return this.container;
49+
}
50+
51+
public getValue(): string {
52+
return `${this.month}/${this.day}/${this.year}`;
53+
}
54+
55+
public setValue(value: string): void {
56+
const valueParts = value.split('/');
57+
if (valueParts.length !== 3) {
58+
return;
59+
}
60+
this.month = valueParts[0];
61+
this.monthComponent.setValue(this.month);
62+
63+
this.day = valueParts[1];
64+
this.dayComponent.setValue(this.day);
65+
66+
this.year = valueParts[2];
67+
this.yearComponent.setValue(this.year);
68+
}
69+
70+
public isEqualValue(value: any): boolean {
71+
return value == this.getValue();
72+
}
73+
74+
public getDefaultValue(): any {
75+
return `1/1/2022`;
76+
}
77+
78+
private onMonthChange(value: string): void {
79+
this.month = value;
80+
this.onValueChange(this.getValue());
81+
}
82+
83+
private onDayChange(value: string): void {
84+
this.day = value;
85+
this.onValueChange(this.getValue());
86+
}
87+
88+
private onYearChange(value: string): void {
89+
this.year = value;
90+
this.onValueChange(this.getValue());
91+
}
92+
93+
public render(container: HTMLDivElement): void {
94+
this.monthComponent = new DropdownComponent(container);
95+
this.monthComponent.addOptions(this.months);
96+
this.monthComponent.setValue(this.month);
97+
this.monthComponent.onChange(this.onMonthChange.bind(this));
98+
99+
this.dayComponent = new DropdownComponent(container);
100+
this.dayComponent.addOptions(this.days);
101+
this.dayComponent.setValue(this.day);
102+
this.dayComponent.onChange(this.onDayChange.bind(this))
103+
104+
this.yearComponent = new DropdownComponent(container);
105+
this.yearComponent.addOptions(this.years);
106+
this.yearComponent.setValue(this.year);
107+
this.yearComponent.onChange(this.onYearChange.bind(this))
108+
109+
this.container = container;
110+
}
111+
112+
}

src/inputFields/InputFieldFactory.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {SliderInputField} from './SliderInputField';
66
import {TextAreaInputField} from './TextAreaInputField';
77
import {SelectInputField} from './SelectInputField';
88
import {MultiSelectInputField} from './MultiSelectInputField';
9+
import {DateInputField} from './DateInputField';
910

1011
export enum InputFieldType {
1112
TOGGLE = 'toggle',
@@ -14,6 +15,7 @@ export enum InputFieldType {
1415
TEXT_AREA = 'text_area',
1516
SELECT = 'select',
1617
MULTI_SELECT = 'multi_select',
18+
DATE = 'date',
1719
INVALID = 'invalid',
1820
}
1921

@@ -67,6 +69,14 @@ export class InputFieldFactory {
6769
throw new Error(`can not create ${inputFieldType} as inline code block`);
6870
}
6971
return new MultiSelectInputField(args.inputFieldMarkdownRenderChild, args.onValueChanged);
72+
} else if (inputFieldType === InputFieldType.DATE) {
73+
if (args.type === InputFieldMarkdownRenderChildType.CODE_BLOCK && !DateInputField.allowCodeBlock) {
74+
throw new Error(`can not create ${inputFieldType} as code block`);
75+
}
76+
if (args.type === InputFieldMarkdownRenderChildType.INLINE_CODE_BLOCK && !DateInputField.allowInlineCodeBlock) {
77+
throw new Error(`can not create ${inputFieldType} as inline code block`);
78+
}
79+
return new DateInputField(args.inputFieldMarkdownRenderChild, args.onValueChanged);
7080
}
7181

7282
return null;

src/inputFields/SelectInputField.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class SelectInputField extends AbstractInputField {
2323
return this.elements.filter(x => x.isActive()).first()?.value ?? '';
2424
}
2525

26-
setValue(value: string): void {
26+
setValue(value: any): void {
2727
for (const element of this.elements) {
2828
if (value === element.value) {
2929
element.setActive(true, false);
@@ -37,7 +37,7 @@ export class SelectInputField extends AbstractInputField {
3737
return this.getValue() == value;
3838
}
3939

40-
getDefaultValue(): string {
40+
getDefaultValue(): any {
4141
return '';
4242
}
4343

src/utils/Logger.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,40 @@ export class Logger {
44
static plugin: MetaBindPlugin;
55
static prefix: string = 'meta-bind |';
66

7+
/**
8+
* Logs to the console with the plugin prefix
9+
*
10+
* @param data
11+
*/
712
static log(...data: any): void {
813
console.log(this.prefix, ...data);
914
}
1015

16+
/**
17+
* Logs to the console with the plugin prefix, if dev mode is turned on in the plugin settings
18+
*
19+
* @param data
20+
*/
1121
static logDebug(...data: any): void {
1222
if (this.plugin.settings.devMode) {
1323
Logger.log(...data);
1424
}
1525
}
1626

27+
/**
28+
* Logs a warning to the console with the plugin prefix
29+
*
30+
* @param data
31+
*/
1732
static logWarning(...data: any): void {
1833
console.warn(this.prefix, data);
1934
}
2035

36+
/**
37+
* Logs an error to the console with the plugin prefix
38+
*
39+
* @param data
40+
*/
2141
static logError(...data: any): void {
2242
console.error(this.prefix, data);
2343
}

src/utils/Utils.ts

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
1+
/**
2+
* Gets the file name from a path
3+
*
4+
* @param path
5+
*/
16
export function getFileName(path: string) {
27
return path.split('/').at(-1);
38
}
49

10+
/**
11+
* Checks if a path is a path or a file name
12+
*
13+
* @param path
14+
*/
515
export function isPath(path: string) {
616
return path.split('/').length > 1;
717
}
818

19+
/**
20+
* Removes the file ending of a file name
21+
*
22+
* @param fileName
23+
*/
924
export function removeFileEnding(fileName: string) {
1025
const fileNameParts = fileName.split('.');
1126
if (fileNameParts.length === 1) {
@@ -19,16 +34,33 @@ export function removeFileEnding(fileName: string) {
1934
}
2035
}
2136

37+
/**
38+
* Clamp, unused
39+
*
40+
* @param num
41+
* @param min
42+
* @param max
43+
*/
2244
export function clamp(num: number, min: number, max: number): number {
2345
return Math.min(Math.max(num, min), max);
2446
}
2547

26-
27-
// js can't even implement modulo correctly...
48+
/**
49+
* js can't even implement modulo correctly...
50+
*
51+
* @param n
52+
* @param m
53+
*/
2854
export function mod(n: number, m: number): number {
2955
return ((n % m) + m) % m;
3056
}
3157

58+
/**
59+
* Checks if 2 arrays are equal, the arrays should have the same datatype
60+
*
61+
* @param arr1
62+
* @param arr2
63+
*/
3264
export function arrayEquals(arr1: any[], arr2: any[]) {
3365
if (arr1.length !== arr2.length) {
3466
return false;
@@ -42,3 +74,83 @@ export function arrayEquals(arr1: any[], arr2: any[]) {
4274

4375
return true;
4476
}
77+
78+
/**
79+
* Template "engine" from my media db plugin
80+
*
81+
* @param template
82+
* @param dataModel
83+
*/
84+
export function replaceTags(template: string, dataModel: any): string {
85+
const resolvedTemplate = template.replace(new RegExp('{{.*?}}', 'g'), (match: string) => replaceTag(match, dataModel));
86+
87+
return resolvedTemplate;
88+
}
89+
90+
/**
91+
* Takes in a template match and returns the replacement data
92+
*
93+
* @param match
94+
* @param dataModel
95+
*/
96+
function replaceTag(match: string, dataModel: any): string {
97+
let tag = match;
98+
tag = tag.substring(2);
99+
tag = tag.substring(0, tag.length - 2);
100+
tag = tag.trim();
101+
102+
let parts = tag.split(':');
103+
if (parts.length === 1) {
104+
let path = parts[0].split('.');
105+
106+
let obj = traverseObject(path, dataModel);
107+
108+
if (obj === undefined) {
109+
return '{{ INVALID TEMPLATE TAG - object undefined }}';
110+
}
111+
112+
return obj;
113+
} else if (parts.length === 2) {
114+
let operator = parts[0];
115+
116+
let path = parts[1].split('.');
117+
118+
let obj = traverseObject(path, dataModel);
119+
120+
if (obj === undefined) {
121+
return '{{ INVALID TEMPLATE TAG - object undefined }}';
122+
}
123+
124+
if (operator === 'LIST') {
125+
if (!Array.isArray(obj)) {
126+
return '{{ INVALID TEMPLATE TAG - operator LIST is only applicable on an array }}';
127+
}
128+
return obj.map((e: any) => `- ${e}`).join('\n');
129+
} else if (operator === 'ENUM') {
130+
if (!Array.isArray(obj)) {
131+
return '{{ INVALID TEMPLATE TAG - operator ENUM is only applicable on an array }}';
132+
}
133+
return obj.join(', ');
134+
}
135+
136+
return `{{ INVALID TEMPLATE TAG - unknown operator ${operator} }}`;
137+
}
138+
139+
return '{{ INVALID TEMPLATE TAG }}';
140+
}
141+
142+
/**
143+
* Traverses the object along a property path
144+
*
145+
* @param path
146+
* @param obj
147+
*/
148+
function traverseObject(path: Array<string>, obj: any): any {
149+
for (let part of path) {
150+
if (obj !== undefined) {
151+
obj = obj[part];
152+
}
153+
}
154+
155+
return obj;
156+
}

0 commit comments

Comments
 (0)