]> BookStack Code Mirror - bookstack/blob - resources/js/markdown/settings.ts
MD Editor: Updated actions to use input interface
[bookstack] / resources / js / markdown / settings.ts
1 type ChangeListener = (value: boolean|number) => void;
2
3 export class Settings {
4     protected changeListeners: Record<string, ChangeListener[]> = {};
5
6     protected settingMap: Record<string, boolean|number> = {
7         scrollSync: true,
8         showPreview: true,
9         editorWidth: 50,
10         plainEditor: false,
11     };
12
13     constructor(settingInputs: HTMLInputElement[]) {
14         this.loadFromLocalStorage();
15         this.applyToInputs(settingInputs);
16         this.listenToInputChanges(settingInputs);
17     }
18
19     protected applyToInputs(inputs: HTMLInputElement[]): void {
20         for (const input of inputs) {
21             const name = input.getAttribute('name')?.replace('md-', '');
22             if (name && name in this.settingMap) {
23                 const value = this.settingMap[name];
24                 if (typeof value === 'boolean') {
25                     input.checked = value;
26                 } else {
27                     input.value = value.toString();
28                 }
29             }
30         }
31     }
32
33     protected listenToInputChanges(inputs: HTMLInputElement[]): void {
34         for (const input of inputs) {
35             input.addEventListener('change', () => {
36                 const name = input.getAttribute('name')?.replace('md-', '');
37                 if (name && name in this.settingMap) {
38                     let value = (input.type === 'checkbox') ? input.checked : Number(input.value);
39                     this.set(name, value);
40                 }
41             });
42         }
43     }
44
45     protected loadFromLocalStorage(): void {
46         const lsValString = window.localStorage.getItem('md-editor-settings');
47         if (!lsValString) {
48             return;
49         }
50
51         try {
52             const lsVals = JSON.parse(lsValString);
53             for (const [key, value] of Object.entries(lsVals)) {
54                 if (value !== null && value !== undefined && key in this.settingMap) {
55                     this.settingMap[key] = value as boolean|number;
56                 }
57             }
58         } catch (error) {
59             console.warn('Failed to parse settings from localStorage:', error);
60         }
61     }
62
63     public set(key: string, value: boolean|number): void {
64         this.settingMap[key] = value;
65         window.localStorage.setItem('md-editor-settings', JSON.stringify(this.settingMap));
66
67         const listeners = this.changeListeners[key] || [];
68         for (const listener of listeners) {
69             listener(value);
70         }
71     }
72
73     public get(key: string): number|boolean|null {
74         return this.settingMap[key] ?? null;
75     }
76
77     public onChange(key: string, callback: ChangeListener): void {
78         const listeners = this.changeListeners[key] || [];
79         listeners.push(callback);
80         this.changeListeners[key] = listeners;
81     }
82 }