browser-extension-settings 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +3 -137
- package/lib/index.js +1 -335
- package/lib/settings.js +224 -0
- package/lib/style.scss +263 -0
- package/lib/switch.js +29 -0
- package/package.json +7 -3
package/lib/index.d.ts
CHANGED
|
@@ -1,139 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export async function initSettings(options: Record<string, unknown>): void
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export async function showSettings(): void
|
|
4
4
|
|
|
5
|
-
export function
|
|
6
|
-
|
|
7
|
-
export function toCamelCase(text: string): string
|
|
8
|
-
|
|
9
|
-
export function $(
|
|
10
|
-
selectors: string,
|
|
11
|
-
element?: HTMLElement | Document
|
|
12
|
-
): HTMLElement | undefined
|
|
13
|
-
|
|
14
|
-
export function querySelector(
|
|
15
|
-
selectors: string,
|
|
16
|
-
element?: HTMLElement | Document
|
|
17
|
-
): HTMLElement | undefined
|
|
18
|
-
|
|
19
|
-
export function $$(
|
|
20
|
-
selectors: string,
|
|
21
|
-
element?: HTMLElement | Document
|
|
22
|
-
): HTMLElement[]
|
|
23
|
-
|
|
24
|
-
export function querySelectorAll(
|
|
25
|
-
selectors: string,
|
|
26
|
-
element?: HTMLElement | Document
|
|
27
|
-
): HTMLElement[]
|
|
28
|
-
|
|
29
|
-
export function createElement(
|
|
30
|
-
tagName: string,
|
|
31
|
-
attributes?: Record<string, unknown>
|
|
32
|
-
): HTMLElement
|
|
33
|
-
|
|
34
|
-
export function addElement(
|
|
35
|
-
tagName: string,
|
|
36
|
-
attributes?: Record<string, unknown>
|
|
37
|
-
): HTMLElement
|
|
38
|
-
|
|
39
|
-
export function addElement(
|
|
40
|
-
parentNode: HTMLElement,
|
|
41
|
-
tagName: string | HTMLElement,
|
|
42
|
-
attributes?: Record<string, unknown>
|
|
43
|
-
): HTMLElement
|
|
44
|
-
|
|
45
|
-
export function addStyle(styleText: string): HTMLElement
|
|
46
|
-
|
|
47
|
-
export function addEventListener(
|
|
48
|
-
element: HTMLElement | Document | EventTarget,
|
|
49
|
-
type: string,
|
|
50
|
-
listener: EventListenerOrEventListenerObject,
|
|
51
|
-
options?: boolean | AddEventListenerOptions
|
|
52
|
-
): void
|
|
53
|
-
|
|
54
|
-
export function addEventListener(
|
|
55
|
-
element: HTMLElement | Document | EventTarget,
|
|
56
|
-
type: string | Record<string, unknown>
|
|
57
|
-
): void
|
|
58
|
-
|
|
59
|
-
export function removeEventListener(
|
|
60
|
-
element: HTMLElement | Document | EventTarget,
|
|
61
|
-
type: string,
|
|
62
|
-
listener: EventListenerOrEventListenerObject,
|
|
63
|
-
options?: boolean | AddEventListenerOptions
|
|
64
|
-
): void
|
|
65
|
-
|
|
66
|
-
export function removeEventListener(
|
|
67
|
-
element: HTMLElement | Document | EventTarget,
|
|
68
|
-
type: string | Record<string, unknown>
|
|
69
|
-
): void
|
|
70
|
-
|
|
71
|
-
export function getAttribute(element: HTMLElement, name: string): string
|
|
72
|
-
|
|
73
|
-
export function setAttribute(
|
|
74
|
-
element: HTMLElement,
|
|
75
|
-
name: string,
|
|
76
|
-
value: string
|
|
77
|
-
): void
|
|
78
|
-
|
|
79
|
-
export function setAttributes(
|
|
80
|
-
element: HTMLElement,
|
|
81
|
-
attributes: Record<string, unknown>
|
|
82
|
-
): void
|
|
83
|
-
|
|
84
|
-
export function addAttribute(
|
|
85
|
-
element: HTMLElement,
|
|
86
|
-
name: string,
|
|
87
|
-
value: string
|
|
88
|
-
): void
|
|
89
|
-
|
|
90
|
-
export function addClass(element: HTMLElement, className: string): void
|
|
91
|
-
|
|
92
|
-
export function removeClass(element: HTMLElement, className: string): void
|
|
93
|
-
|
|
94
|
-
export function hasClass(element: HTMLElement, className: string): boolean
|
|
95
|
-
|
|
96
|
-
export type SetStyle = (
|
|
97
|
-
element: HTMLElement,
|
|
98
|
-
style: string | Record<string, unknown>,
|
|
99
|
-
overwrite?: boolean
|
|
100
|
-
) => void
|
|
101
|
-
|
|
102
|
-
export function setStyle(
|
|
103
|
-
element: HTMLElement,
|
|
104
|
-
style: string | Record<string, unknown>,
|
|
105
|
-
overwrite?: boolean
|
|
106
|
-
): void
|
|
107
|
-
|
|
108
|
-
export function toStyleMap(styleText: string): Record<string, string>
|
|
109
|
-
|
|
110
|
-
export function noStyleSpace(text: string): string
|
|
111
|
-
|
|
112
|
-
export function createSetStyle(styleText: string): SetStyle
|
|
113
|
-
|
|
114
|
-
export function isUrl(text: string): boolean
|
|
115
|
-
|
|
116
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
117
|
-
export function throttle(func: Function, interval: number): Function
|
|
118
|
-
|
|
119
|
-
export type MenuCallback = (event?: MouseEvent | KeyboardEvent) => void
|
|
120
|
-
export function registerMenuCommand(
|
|
121
|
-
name: string,
|
|
122
|
-
callback: MenuCallback,
|
|
123
|
-
accessKey?: string
|
|
124
|
-
): void
|
|
125
|
-
|
|
126
|
-
export function extendHistoryApi(): void
|
|
127
|
-
|
|
128
|
-
export const actionHref: string
|
|
129
|
-
|
|
130
|
-
export function getOffsetPosition(
|
|
131
|
-
element: HTMLElement | undefined,
|
|
132
|
-
referElement?: HTMLElement | undefined
|
|
133
|
-
): {
|
|
134
|
-
top: number
|
|
135
|
-
left: number
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
139
|
-
export function runOnce(key: string, func: Function): any
|
|
5
|
+
export function getSettingsValue(key: string): boolean | string | undefined
|
package/lib/index.js
CHANGED
|
@@ -1,335 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
export const win = window
|
|
4
|
-
|
|
5
|
-
export const uniq = (array) => [...new Set(array)]
|
|
6
|
-
|
|
7
|
-
export const toCamelCase = function (text) {
|
|
8
|
-
return text.replace(/^([A-Z])|[\s-_](\w)/g, function (match, p1, p2) {
|
|
9
|
-
if (p2) return p2.toUpperCase()
|
|
10
|
-
return p1.toLowerCase()
|
|
11
|
-
})
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const $ = (selectors, element) =>
|
|
15
|
-
(element || doc).querySelector(selectors)
|
|
16
|
-
export const $$ = (selectors, element) => [
|
|
17
|
-
...(element || doc).querySelectorAll(selectors),
|
|
18
|
-
]
|
|
19
|
-
export const querySelector = $
|
|
20
|
-
export const querySelectorAll = $$
|
|
21
|
-
|
|
22
|
-
export const createElement = (tagName, attributes) =>
|
|
23
|
-
setAttributes(doc.createElement(tagName), attributes)
|
|
24
|
-
|
|
25
|
-
export const addElement = (parentNode, tagName, attributes) => {
|
|
26
|
-
if (!parentNode) {
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (typeof parentNode === "string") {
|
|
31
|
-
attributes = tagName
|
|
32
|
-
tagName = parentNode
|
|
33
|
-
parentNode = doc.head
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (typeof tagName === "string") {
|
|
37
|
-
const element = createElement(tagName, attributes)
|
|
38
|
-
parentNode.append(element)
|
|
39
|
-
return element
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// tagName: HTMLElement
|
|
43
|
-
setAttributes(tagName, attributes)
|
|
44
|
-
parentNode.append(tagName)
|
|
45
|
-
return tagName
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const addStyle = (styleText) => {
|
|
49
|
-
const element = createElement("style", { textContent: styleText })
|
|
50
|
-
doc.head.append(element)
|
|
51
|
-
return element
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const addEventListener = (element, type, listener, options) => {
|
|
55
|
-
if (!element) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (typeof type === "object") {
|
|
60
|
-
for (const type1 in type) {
|
|
61
|
-
if (Object.hasOwn(type, type1)) {
|
|
62
|
-
element.addEventListener(type1, type[type1])
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
} else if (typeof type === "string" && typeof listener === "function") {
|
|
66
|
-
element.addEventListener(type, listener, options)
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const removeEventListener = (element, type, listener, options) => {
|
|
71
|
-
if (!element) {
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (typeof type === "object") {
|
|
76
|
-
for (const type1 in type) {
|
|
77
|
-
if (Object.hasOwn(type, type1)) {
|
|
78
|
-
element.removeEventListener(type1, type[type1])
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
} else if (typeof type === "string" && typeof listener === "function") {
|
|
82
|
-
element.removeEventListener(type, listener, options)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export const getAttribute = (element, name) =>
|
|
87
|
-
element ? element.getAttribute(name) : null
|
|
88
|
-
export const setAttribute = (element, name, value) =>
|
|
89
|
-
element ? element.setAttribute(name, value) : undefined
|
|
90
|
-
|
|
91
|
-
export const setAttributes = (element, attributes) => {
|
|
92
|
-
if (element && attributes) {
|
|
93
|
-
for (const name in attributes) {
|
|
94
|
-
if (Object.hasOwn(attributes, name)) {
|
|
95
|
-
const value = attributes[name]
|
|
96
|
-
if (value === undefined) {
|
|
97
|
-
continue
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (/^(value|textContent|innerText|innerHTML)$/.test(name)) {
|
|
101
|
-
element[name] = value
|
|
102
|
-
} else if (name === "style") {
|
|
103
|
-
setStyle(element, value, true)
|
|
104
|
-
} else if (/on\w+/.test(name)) {
|
|
105
|
-
const type = name.slice(2)
|
|
106
|
-
addEventListener(element, type, value)
|
|
107
|
-
} else {
|
|
108
|
-
setAttribute(element, name, value)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return element
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export const addAttribute = (element, name, value) => {
|
|
118
|
-
const orgValue = getAttribute(element, name)
|
|
119
|
-
if (!orgValue) {
|
|
120
|
-
setAttribute(element, name, value)
|
|
121
|
-
} else if (!orgValue.includes(value)) {
|
|
122
|
-
setAttribute(element, name, orgValue + " " + value)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export const addClass = (element, className) => {
|
|
127
|
-
if (!element || !element.classList) {
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
element.classList.add(className)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export const removeClass = (element, className) => {
|
|
135
|
-
if (!element || !element.classList) {
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
element.classList.remove(className)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const hasClass = (element, className) => {
|
|
143
|
-
if (!element || !element.classList) {
|
|
144
|
-
return false
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return element.classList.contains(className)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export const setStyle = (element, values, overwrite) => {
|
|
151
|
-
if (!element) {
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// element.setAttribute("style", value) -> Fail when violates CSP
|
|
156
|
-
const style = element.style
|
|
157
|
-
|
|
158
|
-
if (typeof values === "string") {
|
|
159
|
-
style.cssText = overwrite ? values : style.cssText + ";" + values
|
|
160
|
-
return
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (overwrite) {
|
|
164
|
-
style.cssText = ""
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
for (const key in values) {
|
|
168
|
-
if (Object.hasOwn(values, key)) {
|
|
169
|
-
style[key] = values[key].replace("!important", "")
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// convert `font-size: 12px; color: red` to `{"fontSize": "12px"; "color": "red"}`
|
|
175
|
-
// eslint-disable-next-line no-unused-vars
|
|
176
|
-
const toStyleKeyValues = (styleText) => {
|
|
177
|
-
const result = {}
|
|
178
|
-
const keyValues = styleText.split(/\s*;\s*/)
|
|
179
|
-
for (const keyValue of keyValues) {
|
|
180
|
-
const kv = keyValue.split(/\s*:\s*/)
|
|
181
|
-
// TODO: fix when key is such as -webkit-xxx
|
|
182
|
-
const key = toCamelCase(kv[0])
|
|
183
|
-
if (key) {
|
|
184
|
-
result[key] = kv[1]
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return result
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export const toStyleMap = (styleText) => {
|
|
192
|
-
styleText = noStyleSpace(styleText)
|
|
193
|
-
const map = {}
|
|
194
|
-
const keyValues = styleText.split("}")
|
|
195
|
-
for (const keyValue of keyValues) {
|
|
196
|
-
const kv = keyValue.split("{")
|
|
197
|
-
if (kv[0] && kv[1]) {
|
|
198
|
-
map[kv[0]] = kv[1]
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return map
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export const noStyleSpace = (text) => text.replace(/\s*([^\w-+%!])\s*/gm, "$1")
|
|
206
|
-
|
|
207
|
-
export const createSetStyle = (styleText) => {
|
|
208
|
-
const styleMap = toStyleMap(styleText)
|
|
209
|
-
return (element, value, overwrite) => {
|
|
210
|
-
if (typeof value === "object") {
|
|
211
|
-
setStyle(element, value, overwrite)
|
|
212
|
-
} else if (typeof value === "string") {
|
|
213
|
-
const key = noStyleSpace(value)
|
|
214
|
-
const value2 = styleMap[key]
|
|
215
|
-
setStyle(element, value2 || value, overwrite)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export const isUrl = (text) => /^https?:\/\//.test(text)
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
*
|
|
224
|
-
* @param { function } func
|
|
225
|
-
* @param { number } interval
|
|
226
|
-
* @returns
|
|
227
|
-
*/
|
|
228
|
-
export const throttle = (func, interval) => {
|
|
229
|
-
let timeoutId = null
|
|
230
|
-
let next = false
|
|
231
|
-
const handler = (...args) => {
|
|
232
|
-
if (timeoutId) {
|
|
233
|
-
next = true
|
|
234
|
-
} else {
|
|
235
|
-
func.apply(this, args)
|
|
236
|
-
timeoutId = setTimeout(() => {
|
|
237
|
-
timeoutId = null
|
|
238
|
-
if (next) {
|
|
239
|
-
next = false
|
|
240
|
-
handler()
|
|
241
|
-
}
|
|
242
|
-
}, interval)
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return handler
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (typeof Object.hasOwn !== "function") {
|
|
250
|
-
Object.hasOwn = (instance, prop) =>
|
|
251
|
-
Object.prototype.hasOwnProperty.call(instance, prop)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export const registerMenuCommand = () => undefined
|
|
255
|
-
|
|
256
|
-
export const extendHistoryApi = () => {
|
|
257
|
-
// https://dirask.com/posts/JavaScript-on-location-changed-event-on-url-changed-event-DKeyZj
|
|
258
|
-
const pushState = history.pushState
|
|
259
|
-
const replaceState = history.replaceState
|
|
260
|
-
|
|
261
|
-
history.pushState = function () {
|
|
262
|
-
// eslint-disable-next-line prefer-rest-params
|
|
263
|
-
pushState.apply(history, arguments)
|
|
264
|
-
window.dispatchEvent(new Event("pushstate"))
|
|
265
|
-
window.dispatchEvent(new Event("locationchange"))
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
history.replaceState = function () {
|
|
269
|
-
// eslint-disable-next-line prefer-rest-params
|
|
270
|
-
replaceState.apply(history, arguments)
|
|
271
|
-
window.dispatchEvent(new Event("replacestate"))
|
|
272
|
-
window.dispatchEvent(new Event("locationchange"))
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
window.addEventListener("popstate", function () {
|
|
276
|
-
window.dispatchEvent(new Event("locationchange"))
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
// Usage example:
|
|
280
|
-
// window.addEventListener("locationchange", function () {
|
|
281
|
-
// console.log("onlocationchange event occurred!")
|
|
282
|
-
// })
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// eslint-disable-next-line no-script-url
|
|
286
|
-
export const actionHref = "javascript:;"
|
|
287
|
-
|
|
288
|
-
export const getOffsetPosition = (element, referElement) => {
|
|
289
|
-
const position = { top: 0, left: 0 }
|
|
290
|
-
referElement = referElement || doc.body
|
|
291
|
-
|
|
292
|
-
while (element && element !== referElement) {
|
|
293
|
-
position.top += element.offsetTop
|
|
294
|
-
position.left += element.offsetLeft
|
|
295
|
-
element = element.offsetParent
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return position
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const runOnceCache = {}
|
|
302
|
-
export const runOnce = (key, func) => {
|
|
303
|
-
if (!key) {
|
|
304
|
-
return func()
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (Object.hasOwn(runOnceCache, key)) {
|
|
308
|
-
return runOnceCache[key]
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const result = func()
|
|
312
|
-
runOnceCache[key] = result
|
|
313
|
-
return result
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const cacheStore = {}
|
|
317
|
-
const makeKey = (key: string | any[]) =>
|
|
318
|
-
Array.isArray(key) ? key.join(":") : key
|
|
319
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
320
|
-
export const Cache = {
|
|
321
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
322
|
-
get: (key: string | any[]) => cacheStore[makeKey(key)],
|
|
323
|
-
add(key: string | any[], value: any) {
|
|
324
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
325
|
-
cacheStore[makeKey(key)] = value
|
|
326
|
-
},
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export const sleep = async (time: number) => {
|
|
330
|
-
return new Promise((resolve) => {
|
|
331
|
-
setTimeout(() => {
|
|
332
|
-
resolve(1)
|
|
333
|
-
}, time)
|
|
334
|
-
})
|
|
335
|
-
}
|
|
1
|
+
export { initSettings, showSettings, getSettingsValue } from "./settings.js"
|
package/lib/settings.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addValueChangeListener,
|
|
3
|
+
getValue,
|
|
4
|
+
setValue,
|
|
5
|
+
} from "browser-extension-storage"
|
|
6
|
+
import {
|
|
7
|
+
$,
|
|
8
|
+
addElement,
|
|
9
|
+
addEventListener,
|
|
10
|
+
addStyle,
|
|
11
|
+
doc,
|
|
12
|
+
removeEventListener,
|
|
13
|
+
} from "browser-extension-utils"
|
|
14
|
+
import styleText from "data-text:./style.scss"
|
|
15
|
+
import { createSwitchOption } from "./switch.js"
|
|
16
|
+
|
|
17
|
+
const settingsElementId =
|
|
18
|
+
"browser_extension_settings_" + String(Math.round(Math.random() * 10_000))
|
|
19
|
+
const getSettingsElement = () => $("#" + settingsElementId)
|
|
20
|
+
const getSettingsStyle = () =>
|
|
21
|
+
styleText.replace(/browser_extension_settings/gm, settingsElementId)
|
|
22
|
+
const storageKey = "settings"
|
|
23
|
+
|
|
24
|
+
let settingsOptions = {}
|
|
25
|
+
let settingsTable = {}
|
|
26
|
+
let settings = {}
|
|
27
|
+
async function getSettings() {
|
|
28
|
+
return (await getValue(storageKey)) ?? {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function saveSattingsValue(key, value) {
|
|
32
|
+
const settings = await getSettings()
|
|
33
|
+
settings[key] =
|
|
34
|
+
settingsTable[key] && settingsTable[key].defaultValue === value
|
|
35
|
+
? undefined
|
|
36
|
+
: value
|
|
37
|
+
|
|
38
|
+
await setValue(storageKey, settings)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getSettingsValue(key) {
|
|
42
|
+
return Object.hasOwn(settings, key)
|
|
43
|
+
? settings[key]
|
|
44
|
+
: settingsTable[key]?.defaultValue
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const modalHandler = (event) => {
|
|
48
|
+
let target = event.target
|
|
49
|
+
const settingsLayer = getSettingsElement()
|
|
50
|
+
if (settingsLayer) {
|
|
51
|
+
while (target !== settingsLayer && target) {
|
|
52
|
+
target = target.parentNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (target === settingsLayer) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
settingsLayer.style.display = "none"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
removeEventListener(document, "click", modalHandler)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function updateOptions() {
|
|
66
|
+
if (!getSettingsElement()) {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const key in settingsTable) {
|
|
71
|
+
if (Object.hasOwn(settingsTable, key)) {
|
|
72
|
+
const checkbox = $(
|
|
73
|
+
`#${settingsElementId} .option_groups .switch_option[data-key="${key}"] input`
|
|
74
|
+
)
|
|
75
|
+
if (checkbox) {
|
|
76
|
+
checkbox.checked = getSettingsValue(key)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const host = location.host
|
|
82
|
+
const group2 = $(`#${settingsElementId} .option_groups:nth-of-type(2)`)
|
|
83
|
+
if (group2) {
|
|
84
|
+
group2.style.display = getSettingsValue(
|
|
85
|
+
`enableCustomRulesForCurrentSite_${host}`
|
|
86
|
+
)
|
|
87
|
+
? "block"
|
|
88
|
+
: "none"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const customStyleValue = $(`#${settingsElementId} .option_groups textarea`)
|
|
92
|
+
if (customStyleValue) {
|
|
93
|
+
customStyleValue.value = settings[`customRulesForCurrentSite_${host}`] || ""
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createSettingsElement() {
|
|
98
|
+
let settingsLayer = getSettingsElement()
|
|
99
|
+
if (!settingsLayer) {
|
|
100
|
+
settingsLayer = addElement(document.body, "div", {
|
|
101
|
+
id: settingsElementId,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
if (settingsOptions.title) {
|
|
105
|
+
addElement(settingsLayer, "h2", { textContent: settingsOptions.title })
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const options = addElement(settingsLayer, "div", { class: "option_groups" })
|
|
109
|
+
for (const key in settingsTable) {
|
|
110
|
+
if (Object.hasOwn(settingsTable, key)) {
|
|
111
|
+
const item = settingsTable[key]
|
|
112
|
+
if (!item.type || item.type === "switch") {
|
|
113
|
+
const switchOption = createSwitchOption(item.title, {
|
|
114
|
+
async onchange(event) {
|
|
115
|
+
await saveSattingsValue(key, event.target.checked)
|
|
116
|
+
},
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
switchOption.dataset.key = key
|
|
120
|
+
|
|
121
|
+
addElement(options, switchOption)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const options2 = addElement(settingsLayer, "div", {
|
|
127
|
+
class: "option_groups",
|
|
128
|
+
})
|
|
129
|
+
let timeoutId
|
|
130
|
+
addElement(options2, "textarea", {
|
|
131
|
+
placeholder: `/* Custom rules for internal URLs, matching URLs will be opened in new tabs */`,
|
|
132
|
+
onkeyup(event) {
|
|
133
|
+
if (timeoutId) {
|
|
134
|
+
clearTimeout(timeoutId)
|
|
135
|
+
timeoutId = null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
timeoutId = setTimeout(async () => {
|
|
139
|
+
const host = location.host
|
|
140
|
+
await saveSattingsValue(
|
|
141
|
+
`customRulesForCurrentSite_${host}`,
|
|
142
|
+
event.target.value.trim()
|
|
143
|
+
)
|
|
144
|
+
}, 100)
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const tip = addElement(options2, "div", {
|
|
149
|
+
class: "tip",
|
|
150
|
+
})
|
|
151
|
+
addElement(tip, "a", {
|
|
152
|
+
class: "tip_anchor",
|
|
153
|
+
textContent: "Examples",
|
|
154
|
+
})
|
|
155
|
+
const tipContent = addElement(tip, "div", {
|
|
156
|
+
class: "tip_content",
|
|
157
|
+
innerHTML: `<p>Custom rules for internal URLs, matching URLs will be opened in new tabs</p>
|
|
158
|
+
<p>
|
|
159
|
+
- One line per url pattern<br>
|
|
160
|
+
- All URLs contains '/posts' or '/users/'<br>
|
|
161
|
+
<pre>/posts/
|
|
162
|
+
/users/</pre>
|
|
163
|
+
|
|
164
|
+
- Regex is supported<br>
|
|
165
|
+
<pre>^/(posts|members)/d+</pre>
|
|
166
|
+
|
|
167
|
+
- '*' for all URLs
|
|
168
|
+
</p>`,
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
if (settingsOptions.footer) {
|
|
172
|
+
const footer = addElement(settingsLayer, "footer")
|
|
173
|
+
footer.innerHTML =
|
|
174
|
+
typeof settingsOptions.footer === "string"
|
|
175
|
+
? settingsOptions.footer
|
|
176
|
+
: `<p>Made with ❤️ by
|
|
177
|
+
<a href="https://www.pipecraft.net/" target="_blank">
|
|
178
|
+
Pipecraft
|
|
179
|
+
</a></p>`
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return settingsLayer
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function addSideMenu(options) {
|
|
187
|
+
const menu =
|
|
188
|
+
$("#browser_extension_side_menu") ||
|
|
189
|
+
addElement(doc.body, "div", {
|
|
190
|
+
id: "browser_extension_side_menu",
|
|
191
|
+
"data-version": 1,
|
|
192
|
+
})
|
|
193
|
+
addElement(menu, "button", {
|
|
194
|
+
type: "button",
|
|
195
|
+
title: options.title ? "设置 - " + options.title : "设置",
|
|
196
|
+
onclick() {
|
|
197
|
+
setTimeout(showSettings, 1)
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export async function showSettings() {
|
|
203
|
+
const settingsLayer = createSettingsElement()
|
|
204
|
+
await updateOptions()
|
|
205
|
+
settingsLayer.style.display = "block"
|
|
206
|
+
|
|
207
|
+
addEventListener(document, "click", modalHandler)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const initSettings = async (options) => {
|
|
211
|
+
settingsOptions = options
|
|
212
|
+
settingsTable = options.settingsTable || {}
|
|
213
|
+
addValueChangeListener(storageKey, async () => {
|
|
214
|
+
settings = await getSettings()
|
|
215
|
+
await updateOptions()
|
|
216
|
+
if (typeof options.onValueChange === "function") {
|
|
217
|
+
options.onValueChange()
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
settings = await getSettings()
|
|
222
|
+
addStyle(getSettingsStyle())
|
|
223
|
+
addSideMenu(options)
|
|
224
|
+
}
|
package/lib/style.scss
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#browser_extension_settings {
|
|
2
|
+
--browser-extension-settings-background-color: #f3f3f3;
|
|
3
|
+
--browser-extension-settings-text-color: #444444;
|
|
4
|
+
--browser-extension-settings-link-color: #217dfc;
|
|
5
|
+
--sb-track-color: #00000000;
|
|
6
|
+
--sb-thumb-color: #33334480;
|
|
7
|
+
--sb-size: 2px;
|
|
8
|
+
|
|
9
|
+
position: fixed;
|
|
10
|
+
top: 10px;
|
|
11
|
+
right: 30px;
|
|
12
|
+
min-width: 250px;
|
|
13
|
+
max-height: 90%;
|
|
14
|
+
overflow-y: auto;
|
|
15
|
+
overflow-x: hidden;
|
|
16
|
+
scrollbar-color: var(--sb-thumb-color) var(--sb-track-color);
|
|
17
|
+
/* for Firefox */
|
|
18
|
+
scrollbar-width: thin;
|
|
19
|
+
display: none;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
padding: 10px 15px;
|
|
22
|
+
background-color: var(--browser-extension-settings-background-color);
|
|
23
|
+
color: var(--browser-extension-settings-text-color);
|
|
24
|
+
z-index: 100000;
|
|
25
|
+
border-radius: 5px;
|
|
26
|
+
-webkit-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
|
|
27
|
+
-moz-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
|
|
28
|
+
box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22) !important;
|
|
29
|
+
|
|
30
|
+
&::-webkit-scrollbar {
|
|
31
|
+
width: var(--sb-size);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&::-webkit-scrollbar-track {
|
|
35
|
+
background: var(--sb-track-color);
|
|
36
|
+
border-radius: 10px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&::-webkit-scrollbar-thumb {
|
|
40
|
+
background: var(--sb-thumb-color);
|
|
41
|
+
border-radius: 10px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
h2 {
|
|
45
|
+
text-align: center;
|
|
46
|
+
margin: 5px 0 0;
|
|
47
|
+
font-size: 18px;
|
|
48
|
+
font-weight: 600;
|
|
49
|
+
border: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
footer {
|
|
53
|
+
display: flex;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
font-size: 11px;
|
|
57
|
+
margin: 10px auto 0px;
|
|
58
|
+
background-color: var(--browser-extension-settings-background-color);
|
|
59
|
+
color: var(--browser-extension-settings-text-color);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
footer a {
|
|
63
|
+
color: var(--browser-extension-settings-link-color) !important;
|
|
64
|
+
text-decoration: none;
|
|
65
|
+
padding: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
footer p {
|
|
69
|
+
text-align: center;
|
|
70
|
+
padding: 0;
|
|
71
|
+
margin: 2px;
|
|
72
|
+
line-height: 13px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.option_groups {
|
|
76
|
+
background-color: #fff;
|
|
77
|
+
padding: 6px 15px 6px 15px;
|
|
78
|
+
border-radius: 10px;
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
margin: 10px 0 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.option_groups .action {
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
border-top: 1px solid #cccccc;
|
|
87
|
+
padding: 6px 0 6px 0;
|
|
88
|
+
color: var(--browser-extension-settings-link-color);
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.option_groups textarea {
|
|
93
|
+
margin: 10px 0 10px 0;
|
|
94
|
+
height: 100px;
|
|
95
|
+
width: 100%;
|
|
96
|
+
border: 1px solid darkgray;
|
|
97
|
+
border-radius: 4px;
|
|
98
|
+
box-sizing: border-box;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.switch_option {
|
|
102
|
+
display: flex;
|
|
103
|
+
justify-content: space-between;
|
|
104
|
+
align-items: center;
|
|
105
|
+
border-top: 1px solid #cccccc;
|
|
106
|
+
padding: 6px 0 6px 0;
|
|
107
|
+
font-size: 14px;
|
|
108
|
+
}
|
|
109
|
+
.switch_option:first-of-type,
|
|
110
|
+
.option_groups .action:first-of-type {
|
|
111
|
+
border-top: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.switch_option > span {
|
|
115
|
+
margin-right: 10px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.option_groups .tip {
|
|
119
|
+
position: relative;
|
|
120
|
+
margin: 0;
|
|
121
|
+
padding: 0 15px 0 0;
|
|
122
|
+
border: none;
|
|
123
|
+
max-width: none;
|
|
124
|
+
font-size: 14px;
|
|
125
|
+
|
|
126
|
+
.tip_anchor {
|
|
127
|
+
cursor: help;
|
|
128
|
+
text-decoration: underline;
|
|
129
|
+
}
|
|
130
|
+
.tip_content {
|
|
131
|
+
position: absolute;
|
|
132
|
+
bottom: 15px;
|
|
133
|
+
left: 0;
|
|
134
|
+
background-color: #ffffff;
|
|
135
|
+
color: var(--browser-extension-settings-text-color);
|
|
136
|
+
text-align: left;
|
|
137
|
+
padding: 10px;
|
|
138
|
+
display: none;
|
|
139
|
+
border-radius: 5px;
|
|
140
|
+
-webkit-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
|
|
141
|
+
-moz-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
|
|
142
|
+
box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22) !important;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.tip_anchor:hover + .tip_content,
|
|
146
|
+
.tip_content:hover {
|
|
147
|
+
display: block;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
p,
|
|
151
|
+
pre {
|
|
152
|
+
margin: revert;
|
|
153
|
+
padding: revert;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pre {
|
|
157
|
+
font-family: Consolas, panic sans, bitstream vera sans mono, Menlo,
|
|
158
|
+
microsoft yahei, monospace;
|
|
159
|
+
font-size: 13px;
|
|
160
|
+
letter-spacing: 0.015em;
|
|
161
|
+
line-height: 120%;
|
|
162
|
+
white-space: pre;
|
|
163
|
+
overflow: auto;
|
|
164
|
+
background-color: #f5f5f5;
|
|
165
|
+
word-break: normal;
|
|
166
|
+
overflow-wrap: normal;
|
|
167
|
+
padding: 0.5em;
|
|
168
|
+
border: none;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* https://uiverse.io/zanina-yassine/afraid-eel-50 */
|
|
173
|
+
/* The switch - the box around the slider */
|
|
174
|
+
.container {
|
|
175
|
+
--button-width: 51px;
|
|
176
|
+
--button-height: 24px;
|
|
177
|
+
--toggle-diameter: 20px;
|
|
178
|
+
--color-off: #e9e9eb;
|
|
179
|
+
--color-on: #34c759;
|
|
180
|
+
width: var(--button-width);
|
|
181
|
+
height: var(--button-height);
|
|
182
|
+
position: relative;
|
|
183
|
+
padding: 0;
|
|
184
|
+
margin: 0;
|
|
185
|
+
flex: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Hide default HTML checkbox */
|
|
189
|
+
input[type="checkbox"] {
|
|
190
|
+
opacity: 0;
|
|
191
|
+
width: 0;
|
|
192
|
+
height: 0;
|
|
193
|
+
position: absolute;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.switch {
|
|
197
|
+
width: 100%;
|
|
198
|
+
height: 100%;
|
|
199
|
+
display: block;
|
|
200
|
+
background-color: var(--color-off);
|
|
201
|
+
border-radius: calc(var(--button-height) / 2);
|
|
202
|
+
border: none;
|
|
203
|
+
cursor: pointer;
|
|
204
|
+
transition: all 0.2s ease-out;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.switch::before {
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* The slider */
|
|
212
|
+
.slider {
|
|
213
|
+
width: var(--toggle-diameter);
|
|
214
|
+
height: var(--toggle-diameter);
|
|
215
|
+
position: absolute;
|
|
216
|
+
left: 2px;
|
|
217
|
+
top: calc(50% - var(--toggle-diameter) / 2);
|
|
218
|
+
border-radius: 50%;
|
|
219
|
+
background: #ffffff;
|
|
220
|
+
box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.15), 0px 3px 1px rgba(0, 0, 0, 0.06);
|
|
221
|
+
transition: all 0.2s ease-out;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
input[type="checkbox"]:checked + .switch {
|
|
226
|
+
background-color: var(--color-on);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
input[type="checkbox"]:checked + .switch .slider {
|
|
230
|
+
left: calc(var(--button-width) - var(--toggle-diameter) - 2px);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#browser_extension_side_menu {
|
|
235
|
+
min-height: 200px;
|
|
236
|
+
width: 40px;
|
|
237
|
+
opacity: 0;
|
|
238
|
+
position: fixed;
|
|
239
|
+
top: 80px;
|
|
240
|
+
right: 0;
|
|
241
|
+
padding-top: 20px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#browser_extension_side_menu:hover {
|
|
245
|
+
opacity: 1;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#browser_extension_side_menu button {
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
width: 24px;
|
|
251
|
+
height: 24px;
|
|
252
|
+
border: none;
|
|
253
|
+
background-color: transparent;
|
|
254
|
+
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12.0002 16C14.2094 16 16.0002 14.2091 16.0002 12C16.0002 9.79086 14.2094 8 12.0002 8C9.79109 8 8.00023 9.79086 8.00023 12C8.00023 14.2091 9.79109 16 12.0002 16ZM12.0002 14C13.1048 14 14.0002 13.1046 14.0002 12C14.0002 10.8954 13.1048 10 12.0002 10C10.8957 10 10.0002 10.8954 10.0002 12C10.0002 13.1046 10.8957 14 12.0002 14Z' fill='black'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M15.1182 1.86489L15.5203 4.81406C15.8475 4.97464 16.1621 5.1569 16.4623 5.35898L19.2185 4.23223C19.6814 4.043 20.2129 4.2248 20.463 4.65787L22.5901 8.34213C22.8401 8.77521 22.7318 9.3264 22.3365 9.63266L19.9821 11.4566C19.9941 11.6362 20.0002 11.8174 20.0002 12C20.0002 12.1826 19.9941 12.3638 19.9821 12.5434L22.3365 14.3673C22.7318 14.6736 22.8401 15.2248 22.5901 15.6579L20.463 19.3421C20.2129 19.7752 19.6814 19.957 19.2185 19.7678L16.4623 18.641C16.1621 18.8431 15.8475 19.0254 15.5203 19.1859L15.1182 22.1351C15.0506 22.6306 14.6274 23 14.1273 23H9.87313C9.37306 23 8.94987 22.6306 8.8823 22.1351L8.48014 19.1859C8.15296 19.0254 7.83835 18.8431 7.53818 18.641L4.78195 19.7678C4.31907 19.957 3.78756 19.7752 3.53752 19.3421L1.41042 15.6579C1.16038 15.2248 1.26869 14.6736 1.66401 14.3673L4.01841 12.5434C4.00636 12.3638 4.00025 12.1826 4.00025 12C4.00025 11.8174 4.00636 11.6362 4.01841 11.4566L1.66401 9.63266C1.26869 9.3264 1.16038 8.77521 1.41041 8.34213L3.53752 4.65787C3.78755 4.2248 4.31906 4.043 4.78195 4.23223L7.53818 5.35898C7.83835 5.1569 8.15296 4.97464 8.48014 4.81406L8.8823 1.86489C8.94987 1.3694 9.37306 1 9.87313 1H14.1273C14.6274 1 15.0506 1.3694 15.1182 1.86489ZM13.6826 6.14004L14.6392 6.60948C14.8842 6.72975 15.1201 6.86639 15.3454 7.01805L16.231 7.61423L19.1674 6.41382L20.4216 8.58619L17.9153 10.5278L17.9866 11.5905C17.9956 11.7255 18.0002 11.8621 18.0002 12C18.0002 12.1379 17.9956 12.2745 17.9866 12.4095L17.9153 13.4722L20.4216 15.4138L19.1674 17.5862L16.231 16.3858L15.3454 16.982C15.1201 17.1336 14.8842 17.2702 14.6392 17.3905L13.6826 17.86L13.2545 21H10.746L10.3178 17.86L9.36131 17.3905C9.11626 17.2702 8.88037 17.1336 8.6551 16.982L7.76954 16.3858L4.83313 17.5862L3.57891 15.4138L6.0852 13.4722L6.01392 12.4095C6.00487 12.2745 6.00024 12.1379 6.00024 12C6.00024 11.8621 6.00487 11.7255 6.01392 11.5905L6.0852 10.5278L3.57891 8.58619L4.83312 6.41382L7.76953 7.61423L8.6551 7.01805C8.88037 6.86639 9.11625 6.72976 9.36131 6.60949L10.3178 6.14004L10.746 3H13.2545L13.6826 6.14004Z' fill='black'/%3E%3C/svg%3E");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#browser_extension_side_menu button:hover {
|
|
258
|
+
opacity: 70%;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#browser_extension_side_menu button:active {
|
|
262
|
+
opacity: 100%;
|
|
263
|
+
}
|
package/lib/switch.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addElement,
|
|
3
|
+
addEventListener,
|
|
4
|
+
createElement,
|
|
5
|
+
} from "browser-extension-utils"
|
|
6
|
+
|
|
7
|
+
export function createSwitch(options = {}) {
|
|
8
|
+
const container = createElement("label", { class: "container" })
|
|
9
|
+
const checkbox = createElement(
|
|
10
|
+
"input",
|
|
11
|
+
options.checked ? { type: "checkbox", checked: "" } : { type: "checkbox" }
|
|
12
|
+
)
|
|
13
|
+
addElement(container, checkbox)
|
|
14
|
+
const switchElm = createElement("span", { class: "switch" })
|
|
15
|
+
addElement(switchElm, "span", { class: "slider" })
|
|
16
|
+
addElement(container, switchElm)
|
|
17
|
+
if (options.onchange) {
|
|
18
|
+
addEventListener(checkbox, "change", options.onchange)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return container
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createSwitchOption(text, options) {
|
|
25
|
+
const div = createElement("div", { class: "switch_option" })
|
|
26
|
+
addElement(div, "span", { textContent: text })
|
|
27
|
+
div.append(createSwitch(options))
|
|
28
|
+
return div
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-extension-settings",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Settings module for developing browser extensions and userscripts
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Settings module for developing browser extensions and userscripts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"README.md"
|
|
38
38
|
],
|
|
39
39
|
"engines": {
|
|
40
|
-
"node": "^
|
|
40
|
+
"node": "^14.13.1 || >=16.0.0"
|
|
41
41
|
},
|
|
42
42
|
"xo": {
|
|
43
43
|
"space": 2,
|
|
@@ -49,5 +49,9 @@
|
|
|
49
49
|
"prefer-destructuring": 0,
|
|
50
50
|
"capitalized-comments": 0
|
|
51
51
|
}
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"browser-extension-storage": "^0.1.2",
|
|
55
|
+
"browser-extension-utils": "^0.1.4"
|
|
52
56
|
}
|
|
53
57
|
}
|