forked from Mirrors/gomuks
web/preferences: improve preference proxies
This commit is contained in:
parent
f4be132313
commit
41074937d3
3 changed files with 49 additions and 17 deletions
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import { Preferences, existingPreferenceKeys, preferences } from "./preferences.ts"
|
||||
import { Preferences, isValidPreferenceKey, preferences } from "./preferences.ts"
|
||||
import { PreferenceContext } from "./types.ts"
|
||||
|
||||
function getObjectFromLocalStorage(key: string): Preferences {
|
||||
|
@ -28,11 +28,18 @@ function getObjectFromLocalStorage(key: string): Preferences {
|
|||
return {}
|
||||
}
|
||||
|
||||
const globalPrefKeys = Object.entries(preferences)
|
||||
.filter(([,pref]) => pref.allowedContexts.includes(PreferenceContext.Device))
|
||||
.map(([key]) => key)
|
||||
const roomPrefKeys = Object.entries(preferences)
|
||||
.filter(([,pref]) => pref.allowedContexts.includes(PreferenceContext.RoomDevice))
|
||||
.map(([key]) => key)
|
||||
|
||||
export function getLocalStoragePreferences(localStorageKey: string, onChange: () => void): Preferences {
|
||||
return new Proxy(getObjectFromLocalStorage(localStorageKey), {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
set(target: Preferences, key: keyof Preferences, newValue: any): boolean {
|
||||
if (!existingPreferenceKeys.has(key)) {
|
||||
set(target: Preferences, key: string | symbol, newValue: any): boolean {
|
||||
if (!isValidPreferenceKey(key)) {
|
||||
return false
|
||||
}
|
||||
target[key] = newValue
|
||||
|
@ -40,8 +47,8 @@ export function getLocalStoragePreferences(localStorageKey: string, onChange: ()
|
|||
onChange()
|
||||
return true
|
||||
},
|
||||
deleteProperty(target: Preferences, key: keyof Preferences): boolean {
|
||||
if (!existingPreferenceKeys.has(key)) {
|
||||
deleteProperty(target: Preferences, key: string | symbol): boolean {
|
||||
if (!isValidPreferenceKey(key)) {
|
||||
return false
|
||||
}
|
||||
delete target[key]
|
||||
|
@ -52,13 +59,15 @@ export function getLocalStoragePreferences(localStorageKey: string, onChange: ()
|
|||
return true
|
||||
},
|
||||
ownKeys(): string[] {
|
||||
console.warn("localStorage preference proxy ownKeys called")
|
||||
// This is only for debugging, so the performance doesn't matter that much
|
||||
return Object.entries(preferences)
|
||||
.filter(([,pref]) =>
|
||||
pref.allowedContexts.includes(localStorageKey === "global_prefs"
|
||||
? PreferenceContext.Device : PreferenceContext.RoomDevice))
|
||||
.map(([key]) => key)
|
||||
return localStorageKey === "global_prefs" ? globalPrefKeys : roomPrefKeys
|
||||
},
|
||||
getOwnPropertyDescriptor(_target: never, key: string | symbol): PropertyDescriptor | undefined {
|
||||
const keySet = localStorageKey === "global_prefs" ? globalPrefKeys : roomPrefKeys
|
||||
return (typeof key === "string" && keySet.includes(key)) ? {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
} : undefined
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import type { ContentURI } from "../../types"
|
||||
import { Preference, anyContext } from "./types.ts"
|
||||
|
||||
export const codeBlockStyles = [
|
||||
|
@ -56,7 +57,7 @@ export const preferences = {
|
|||
allowedValues: codeBlockStyles,
|
||||
}),
|
||||
pointer_cursor: new Preference<boolean>({
|
||||
displayName: "Pointer cursor",
|
||||
displayName: "Use pointer cursor",
|
||||
description: "Whether to use a pointer cursor for clickable elements.",
|
||||
allowedContexts: anyContext,
|
||||
defaultValue: false,
|
||||
|
@ -97,6 +98,12 @@ export const preferences = {
|
|||
allowedContexts: anyContext,
|
||||
defaultValue: true,
|
||||
}),
|
||||
custom_notification_sound: new Preference<ContentURI>({
|
||||
displayName: "Custom notification sound",
|
||||
description: "The mxc:// URI to a custom notification sound.",
|
||||
allowedContexts: anyContext,
|
||||
defaultValue: "",
|
||||
}),
|
||||
} as const
|
||||
|
||||
export const existingPreferenceKeys = new Set(Object.keys(preferences))
|
||||
|
@ -104,3 +111,7 @@ export const existingPreferenceKeys = new Set(Object.keys(preferences))
|
|||
export type Preferences = {
|
||||
-readonly [name in keyof typeof preferences]?: typeof preferences[name]["defaultValue"]
|
||||
}
|
||||
|
||||
export function isValidPreferenceKey(key: unknown): key is keyof Preferences {
|
||||
return typeof key === "string" && existingPreferenceKeys.has(key)
|
||||
}
|
||||
|
|
|
@ -14,18 +14,23 @@
|
|||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import type { RoomStateStore, StateStore } from "@/api/statestore"
|
||||
import { Preferences, existingPreferenceKeys, preferences } from "./preferences.ts"
|
||||
import { Preferences, isValidPreferenceKey, preferences } from "./preferences.ts"
|
||||
import { PreferenceContext, PreferenceValueType } from "./types.ts"
|
||||
|
||||
const prefKeys = Object.keys(preferences)
|
||||
|
||||
export function getPreferenceProxy(store: StateStore, room?: RoomStateStore): Preferences {
|
||||
return new Proxy({}, {
|
||||
set(): boolean {
|
||||
throw new Error("The preference proxy is read-only")
|
||||
},
|
||||
get(_target: never, key: keyof Preferences): PreferenceValueType | undefined {
|
||||
get(_target: never, key: keyof Preferences | symbol): PreferenceValueType | undefined {
|
||||
if (typeof key !== "string") {
|
||||
return
|
||||
}
|
||||
const pref = preferences[key]
|
||||
if (!pref) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
let val: typeof pref.defaultValue | undefined
|
||||
for (const ctx of pref.allowedContexts) {
|
||||
|
@ -47,7 +52,14 @@ export function getPreferenceProxy(store: StateStore, room?: RoomStateStore): Pr
|
|||
return pref.defaultValue
|
||||
},
|
||||
ownKeys(): string[] {
|
||||
return Array.from(existingPreferenceKeys)
|
||||
return prefKeys
|
||||
},
|
||||
getOwnPropertyDescriptor(_target: never, key: string | symbol): PropertyDescriptor | undefined {
|
||||
return isValidPreferenceKey(key) ? {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: false,
|
||||
} : undefined
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue