diff options
Diffstat (limited to 'js/KeyValueStore.ts')
-rw-r--r-- | js/KeyValueStore.ts | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/js/KeyValueStore.ts b/js/KeyValueStore.ts new file mode 100644 index 0000000..fd8f39e --- /dev/null +++ b/js/KeyValueStore.ts | |||
@@ -0,0 +1,89 @@ | |||
1 | type KeyValueStoreCallback<T> = (value: T) => void; | ||
2 | |||
3 | interface IKeyValueStoreParam<T> { | ||
4 | value: T; | ||
5 | valueRange?: T[]; | ||
6 | callbacks?: KeyValueStoreCallback<T>[]; | ||
7 | } | ||
8 | |||
9 | type KeyValueStoreData<T> = { [K in keyof T]: IKeyValueStoreParam<T[K]> }; | ||
10 | |||
11 | class KeyValueStore<T> { | ||
12 | constructor(private data: KeyValueStoreData<T>) { | ||
13 | for (const id of Object.keys(data)) { | ||
14 | const props = data[id as keyof typeof data]; | ||
15 | |||
16 | if (props.valueRange && props.valueRange.indexOf(props.value) === -1) { | ||
17 | throw new Error(`Invalid value "${props.value}" for ID "${id}"`); | ||
18 | } | ||
19 | } | ||
20 | } | ||
21 | |||
22 | public getValue(id: keyof T) { | ||
23 | return this.data[id].value; | ||
24 | } | ||
25 | |||
26 | public setValue<K extends keyof T>(id: K, value: T[K]) { | ||
27 | const props = this.data[id]; | ||
28 | |||
29 | if (props.valueRange) { | ||
30 | const valueIndex = props.valueRange.indexOf(value); | ||
31 | if (valueIndex === -1) { | ||
32 | throw new Error(`Invalid value "${value}" for ID "${id}"`); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | props.value = value; | ||
37 | |||
38 | if (props.callbacks) { | ||
39 | props.callbacks.forEach(callback => { | ||
40 | callback(value); | ||
41 | }); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | public cycleValue<K extends keyof T>(id: K, dir: -1 | 1 = 1) { | ||
46 | const props = this.data[id]; | ||
47 | |||
48 | if (!props) { | ||
49 | throw new Error(`Invalid ID "${id}"`); | ||
50 | } | ||
51 | |||
52 | let value = props.value; | ||
53 | |||
54 | if (props.valueRange) { | ||
55 | let valueIndex = props.valueRange.indexOf(value) + dir; | ||
56 | |||
57 | if (valueIndex >= props.valueRange.length) { | ||
58 | valueIndex = 0; | ||
59 | } else if (valueIndex < 0) { | ||
60 | valueIndex = props.valueRange.length - 1; | ||
61 | } | ||
62 | |||
63 | value = props.value = props.valueRange[valueIndex]; | ||
64 | } else if (typeof value === "number") { | ||
65 | (value as number) += dir; | ||
66 | props.value = value; | ||
67 | } else { | ||
68 | throw new Error(`Can't cycle "${id}"`); | ||
69 | } | ||
70 | |||
71 | if (props.callbacks) { | ||
72 | props.callbacks.forEach(callback => { | ||
73 | callback(value); | ||
74 | }); | ||
75 | } | ||
76 | |||
77 | return value; | ||
78 | } | ||
79 | |||
80 | public addCallback<K extends keyof T>(id: K, callback: KeyValueStoreCallback<T[K]>) { | ||
81 | const props = this.data[id]; | ||
82 | |||
83 | if (!props.callbacks) { | ||
84 | props.callbacks = []; | ||
85 | } | ||
86 | |||
87 | props.callbacks.push(callback); | ||
88 | } | ||
89 | } | ||