Skip to content

Commit cdb5085

Browse files
committed
setting-utils
1 parent deb0656 commit cdb5085

File tree

3 files changed

+254
-21
lines changed

3 files changed

+254
-21
lines changed

src/index.ts

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import "@/index.scss";
1818
import HelloExample from "@/hello.svelte";
1919
import SettingPannel from "@/libs/setting-panel.svelte";
2020

21+
import { SettingUtils } from "./libs/setting-utils";
22+
2123
const STORAGE_NAME = "menu-config";
2224
const TAB_TYPE = "custom_tab";
2325
const DOCK_TYPE = "dock_tab";
@@ -27,6 +29,7 @@ export default class PluginSample extends Plugin {
2729
private customTab: () => IModel;
2830
private isMobile: boolean;
2931
private blockIconEventBindThis = this.blockIconEvent.bind(this);
32+
private settingUtils: SettingUtils;
3033

3134
async onload() {
3235
this.data[STORAGE_NAME] = { readonlyText: "Readonly" };
@@ -158,32 +161,66 @@ export default class PluginSample extends Plugin {
158161
}
159162
});
160163

161-
const textareaElement = document.createElement("textarea");
162-
this.setting = new Setting({
163-
confirmCallback: () => {
164-
this.saveData(STORAGE_NAME, { readonlyText: textareaElement.value });
165-
}
164+
this.settingUtils = new SettingUtils(this, STORAGE_NAME);
165+
this.settingUtils.addItem({
166+
key: "Input",
167+
value: "",
168+
type: "textinput",
169+
title: "Readonly text",
170+
description: "Input description",
166171
});
167-
this.setting.addItem({
172+
this.settingUtils.addItem({
173+
key: "InputArea",
174+
value: "",
175+
type: "textarea",
168176
title: "Readonly text",
169-
createActionElement: () => {
170-
textareaElement.className = "b3-text-field fn__block";
171-
textareaElement.placeholder = "Readonly text in the menu";
172-
textareaElement.value = this.data[STORAGE_NAME].readonlyText;
173-
return textareaElement;
174-
},
177+
description: "Input description",
175178
});
176-
const btnaElement = document.createElement("button");
177-
btnaElement.className = "b3-button b3-button--outline fn__flex-center fn__size200";
178-
btnaElement.textContent = "Open";
179-
btnaElement.addEventListener("click", () => {
180-
window.open("https://github.com/siyuan-note/plugin-sample-vite-svelte");
179+
this.settingUtils.addItem({
180+
key: "Select",
181+
value: 1,
182+
type: "select",
183+
title: "Readonly text",
184+
description: "Select description",
185+
select: {
186+
options: [
187+
{
188+
val: 1,
189+
text: "Option 1"
190+
},
191+
{
192+
val: 2,
193+
text: "Option 2"
194+
}
195+
]
196+
}
197+
});
198+
this.settingUtils.addItem({
199+
key: "Slider",
200+
value: 50,
201+
type: "slider",
202+
title: "Slider text",
203+
description: "Slider description",
204+
slider: {
205+
min: 0,
206+
max: 100,
207+
step: 1,
208+
}
181209
});
182-
this.setting.addItem({
183-
title: "Open plugin url",
184-
description: "Open plugin url in browser",
185-
actionElement: btnaElement,
210+
this.settingUtils.addItem({
211+
key: "Btn",
212+
value: "",
213+
type: "button",
214+
title: "Button",
215+
description: "Button description",
216+
button: {
217+
label: "Button",
218+
callback: () => {
219+
showMessage("Button clicked");
220+
}
221+
}
186222
});
223+
this.settingUtils.load();
187224

188225
this.protyleSlash = [{
189226
filter: ["insert emoji 😊", "插入表情 😊", "crbqwx"],

src/libs/index.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "slider" | "button";
2+
interface ISettingItem {
3+
key: string;
4+
value: any;
5+
type: TSettingItemType;
6+
title: string;
7+
description?: string;
8+
slider?: {
9+
min: number;
10+
max: number;
11+
step: number;
12+
};
13+
select?: {
14+
options: {val: any; text: string}[];
15+
};
16+
button?: {
17+
label: string;
18+
callback: () => void;
19+
}
20+
}

src/libs/setting-utils.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { Plugin, Setting } from 'siyuan';
2+
3+
export class SettingUtils {
4+
plugin: Plugin;
5+
name: string;
6+
file: string;
7+
8+
settings: Map<string, ISettingItem> = new Map();
9+
elements: Map<string, HTMLElement> = new Map();
10+
11+
constructor(plugin: Plugin, name?: string, width?: string, height?: string) {
12+
this.name = name ?? 'settings';
13+
this.plugin = plugin;
14+
this.file = this.name.endsWith('.json') ? this.name : `${this.name}.json`;
15+
this.plugin.setting = new Setting({
16+
width: width,
17+
height: height,
18+
confirmCallback: () => {
19+
for (let key of this.settings.keys()) {
20+
this.updateValue(key);
21+
}
22+
let data = this.dump();
23+
this.plugin.data[this.name] = data;
24+
this.save();
25+
}
26+
});
27+
}
28+
29+
async load() {
30+
let data = await this.plugin.loadData(this.file);
31+
if (data) {
32+
for (let [key, item] of this.settings) {
33+
item.value = data?.[key] ?? item.value;
34+
}
35+
}
36+
}
37+
38+
async save() {
39+
let data = this.dump();
40+
await this.plugin.saveData(this.file, this.dump());
41+
return data;
42+
}
43+
44+
/**
45+
* Get setting item value
46+
* @param key key name
47+
* @returns setting item value
48+
*/
49+
get(key: string) {
50+
return this.settings.get(key)?.value;
51+
}
52+
53+
/**
54+
* 将设置项目导出为 JSON 对象
55+
* @returns object
56+
*/
57+
dump(): Object {
58+
let data: any = {};
59+
for (let [key, item] of this.settings) {
60+
if (item.type === 'button') continue;
61+
data[key] = item.value;
62+
}
63+
return data;
64+
}
65+
66+
addItem(item: ISettingItem) {
67+
this.settings.set(item.key, item);
68+
let itemElement: HTMLElement;
69+
switch (item.type) {
70+
case 'checkbox':
71+
let element: HTMLInputElement = document.createElement('input');
72+
element.type = 'checkbox';
73+
element.checked = item.value;
74+
element.className = "b3-switch fn__flex-center";
75+
itemElement = element;
76+
break;
77+
case 'select':
78+
let selectElement: HTMLSelectElement = document.createElement('select');
79+
selectElement.className = "b3-select fn__flex-center fn__size200";
80+
for (let option of item.select?.options ?? []) {
81+
let optionElement = document.createElement('option');
82+
optionElement.value = option.val;
83+
optionElement.text = option.text;
84+
selectElement.appendChild(optionElement);
85+
}
86+
selectElement.value = item.value;
87+
itemElement = selectElement;
88+
break;
89+
case 'slider':
90+
let sliderElement: HTMLInputElement = document.createElement('input');
91+
sliderElement.type = 'range';
92+
sliderElement.className = 'b3-slider fn__size200';
93+
sliderElement.ariaLabel = item.value;
94+
sliderElement.min = item.slider?.min.toString() ?? '0';
95+
sliderElement.max = item.slider?.max.toString() ?? '100';
96+
sliderElement.step = item.slider?.step.toString() ?? '1';
97+
sliderElement.value = item.value;
98+
itemElement = sliderElement;
99+
break;
100+
case 'textinput':
101+
let textInputElement: HTMLInputElement = document.createElement('input');
102+
textInputElement.className = 'b3-text-field fn__flex-center fn__size200';
103+
textInputElement.value = item.value;
104+
itemElement = textInputElement;
105+
break;
106+
case 'textarea':
107+
let textareaElement: HTMLTextAreaElement = document.createElement('textarea');
108+
textareaElement.className = "b3-text-field fn__block";
109+
textareaElement.value = item.value;
110+
itemElement = textareaElement;
111+
break;
112+
case 'button':
113+
let buttonElement: HTMLButtonElement = document.createElement('button');
114+
buttonElement.className = "b3-button b3-button--outline fn__flex-center fn__size200";
115+
buttonElement.innerText = item.button?.label ?? 'Button';
116+
buttonElement.onclick = item.button?.callback ?? (() => {});
117+
itemElement = buttonElement;
118+
break;
119+
}
120+
this.elements.set(item.key, itemElement);
121+
this.plugin.setting.addItem({
122+
title: item.title,
123+
description: item?.description,
124+
createActionElement: () => {
125+
let element = this.getElement(item.key);
126+
return element;
127+
}
128+
})
129+
}
130+
131+
private getElement(key: string) {
132+
let item = this.settings.get(key);
133+
let element = this.elements.get(key) as any;
134+
switch (item.type) {
135+
case 'checkbox':
136+
element.checked = item.value;
137+
break;
138+
case 'select':
139+
element.value = item.value;
140+
break;
141+
case 'slider':
142+
element.value = item.value;
143+
break;
144+
case 'textinput':
145+
element.value = item.value;
146+
break;
147+
case 'textarea':
148+
element.value = item.value;
149+
break;
150+
}
151+
return element;
152+
}
153+
154+
private updateValue(key: string) {
155+
let item = this.settings.get(key);
156+
let element = this.elements.get(key) as any;
157+
switch (item.type) {
158+
case 'checkbox':
159+
item.value = element.checked;
160+
break;
161+
case 'select':
162+
item.value = element.value;
163+
break;
164+
case 'slider':
165+
item.value = element.value;
166+
break;
167+
case 'textinput':
168+
item.value = element.value;
169+
break;
170+
case 'textarea':
171+
item.value = element.value;
172+
break;
173+
}
174+
}
175+
176+
}

0 commit comments

Comments
 (0)