browser-extension-settings 0.6.5 → 0.7.0

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/common.ts CHANGED
@@ -1,4 +1,5 @@
1
- export const besVersion = 62
1
+ // Version 0.7.0
2
+ export const besVersion = 70
2
3
  export const openButton = `<svg viewBox="0 0 60.2601318359375 84.8134765625" version="1.1" xmlns="http://www.w3.org/2000/svg" class=" glyph-box" style="height: 9.62969px; width: 6.84191px;"><g transform="matrix(1 0 0 1 -6.194965820312518 77.63671875)"><path d="M66.4551-35.2539C66.4551-36.4746 65.9668-37.5977 65.0391-38.4766L26.3672-76.3672C25.4883-77.1973 24.4141-77.6367 23.1445-77.6367C20.6543-77.6367 18.7012-75.7324 18.7012-73.1934C18.7012-71.9727 19.1895-70.8496 19.9707-70.0195L55.5176-35.2539L19.9707-0.488281C19.1895 0.341797 18.7012 1.41602 18.7012 2.68555C18.7012 5.22461 20.6543 7.12891 23.1445 7.12891C24.4141 7.12891 25.4883 6.68945 26.3672 5.81055L65.0391-32.0312C65.9668-32.959 66.4551-34.0332 66.4551-35.2539Z"></path></g></svg>`
3
4
  export const openInNewTabButton = `<svg viewBox="0 0 72.127685546875 72.2177734375" version="1.1" xmlns="http://www.w3.org/2000/svg" class=" glyph-box" style="height: 8.19958px; width: 8.18935px;"><g transform="matrix(1 0 0 1 -12.451127929687573 71.3388671875)"><path d="M84.5703-17.334L84.5215-66.4551C84.5215-69.2383 82.7148-71.1914 79.7852-71.1914L30.6641-71.1914C27.9297-71.1914 26.0742-69.0918 26.0742-66.748C26.0742-64.4043 28.1738-62.4023 30.4688-62.4023L47.4609-62.4023L71.2891-63.1836L62.207-55.2246L13.8184-6.73828C12.9395-5.85938 12.4512-4.73633 12.4512-3.66211C12.4512-1.31836 14.5508 0.878906 16.9922 0.878906C18.1152 0.878906 19.1895 0.488281 20.0684-0.439453L68.5547-48.877L76.6113-58.0078L75.7324-35.2051L75.7324-17.1387C75.7324-14.8438 77.7344-12.6953 80.127-12.6953C82.4707-12.6953 84.5703-14.6973 84.5703-17.334Z"></path></g></svg>`
4
5
  export const settingButton = `<svg viewBox="0 0 16 16" version="1.1">
package/lib/settings.ts CHANGED
@@ -8,14 +8,12 @@ import {
8
8
  $$,
9
9
  addElement,
10
10
  addEventListener,
11
- addStyle,
12
11
  createHTML,
13
12
  doc,
14
13
  parseInt10,
15
14
  registerMenuCommand,
16
15
  removeEventListener,
17
- runWhenDomReady,
18
- runWhenHeadExists,
16
+ createElement,
19
17
  } from "browser-extension-utils"
20
18
  import styleText from "data-text:./style.scss"
21
19
  import {
@@ -23,14 +21,7 @@ import {
23
21
  getPrefferedLocale,
24
22
  } from "browser-extension-i18n"
25
23
  import { createSwitchOption } from "./switch"
26
- import {
27
- createExtensionList,
28
- addCurrentExtension,
29
- activeExtension,
30
- activeExtensionList,
31
- deactiveExtensionList,
32
- } from "./extension-list"
33
- import { besVersion, settingButton } from "./common"
24
+ import { besVersion } from "./common"
34
25
  import { i, resetI18n, localeNames } from "./messages/index"
35
26
 
36
27
  // Declare GM global variable for userscript environment
@@ -41,7 +32,7 @@ declare const GM:
41
32
  }
42
33
  | undefined
43
34
 
44
- const prefix = "browser_extension_settings_"
35
+ const prefix = "browser_extension_settings_v2_"
45
36
 
46
37
  type SettingsOptions = {
47
38
  id: string
@@ -116,20 +107,14 @@ type RelatedExtension = {
116
107
  url: string
117
108
  }
118
109
 
119
- type InstalledExtension = {
120
- id: string
121
- title: string
122
- version: string
110
+ const getSettingsElement = () => {
111
+ const wrapper = getSettingsWrapper()
112
+ return (
113
+ (wrapper?.querySelector(`.${prefix}main`) as HTMLElement | undefined) ||
114
+ undefined
115
+ )
123
116
  }
124
117
 
125
- const randomId = String(Math.round(Math.random() * 10_000))
126
- const settingsContainerId = prefix + "container_" + randomId
127
- const settingsElementId = prefix + "main_" + randomId
128
- const getSettingsElement = () => $("#" + settingsElementId)
129
- const getSettingsStyle: () => string = () =>
130
- styleText
131
- .replaceAll(/browser_extension_settings_container/gm, settingsContainerId)
132
- .replaceAll(/browser_extension_settings_main/gm, settingsElementId)
133
118
  const storageKey = "settings"
134
119
 
135
120
  let settingsOptions: SettingsOptions
@@ -184,26 +169,25 @@ const closeModal = () => {
184
169
  const settingsContainer = getSettingsContainer()
185
170
  if (settingsContainer) {
186
171
  settingsContainer.style.display = "none"
172
+ settingsContainer.remove()
187
173
  }
188
174
 
189
175
  removeEventListener(document, "click", onDocumentClick, true)
190
176
  removeEventListener(document, "keydown", onDocumentKeyDown, true)
177
+ removeEventListener(
178
+ globalThis,
179
+ "beforeShowSettings",
180
+ onBeforeShowSettings,
181
+ true
182
+ )
191
183
  }
192
184
 
193
185
  export function hideSettings() {
194
186
  closeModal()
195
187
  }
196
188
 
197
- function destroySettings() {
198
- closeModal()
199
- const settingsContainer = getSettingsContainer()
200
- if (settingsContainer) {
201
- settingsContainer.remove()
202
- }
203
- }
204
-
205
189
  function isSettingsShown() {
206
- const settingsContainer = getSettingsContainer()
190
+ const settingsContainer = $(`.${prefix}container`)
207
191
  if (settingsContainer) {
208
192
  return settingsContainer.style.display === "block"
209
193
  }
@@ -212,8 +196,15 @@ function isSettingsShown() {
212
196
  }
213
197
 
214
198
  const onDocumentClick = (event: Event) => {
215
- const target = event.target as HTMLElement
216
- if (target?.closest(`.${prefix}container`)) {
199
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
200
+ const path = (event as any).composedPath?.() || []
201
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
202
+ const insideContainer = path.some(
203
+ (node: unknown) =>
204
+ node instanceof HTMLElement &&
205
+ node.classList?.contains(`${prefix}container`)
206
+ )
207
+ if (insideContainer) {
217
208
  return
218
209
  }
219
210
 
@@ -246,8 +237,10 @@ async function updateOptions() {
246
237
  // console.log(key, type)
247
238
  switch (type) {
248
239
  case "switch": {
240
+ const root = getSettingsElement()!
249
241
  const checkbox = $(
250
- `#${settingsElementId} .option_groups .switch_option[data-key="${key}"] input`
242
+ `.option_groups .switch_option[data-key="${key}"] input`,
243
+ root
251
244
  ) as HTMLInputElement
252
245
  if (checkbox) {
253
246
  checkbox.checked = getSettingsValue(key) as boolean
@@ -257,8 +250,10 @@ async function updateOptions() {
257
250
  }
258
251
 
259
252
  case "select": {
253
+ const root = getSettingsElement()!
260
254
  const options = $$(
261
- `#${settingsElementId} .option_groups .select_option[data-key="${key}"] .bes_select option`
255
+ `.option_groups .select_option[data-key="${key}"] .bes_select option`,
256
+ root
262
257
  ) as HTMLOptionElement[]
263
258
 
264
259
  for (const option of options) {
@@ -269,8 +264,10 @@ async function updateOptions() {
269
264
  }
270
265
 
271
266
  case "textarea": {
267
+ const root = getSettingsElement()!
272
268
  const textArea = $(
273
- `#${settingsElementId} .option_groups textarea[data-key="${key}"]`
269
+ `.option_groups textarea[data-key="${key}"]`,
270
+ root
274
271
  ) as HTMLTextAreaElement
275
272
  if (textArea) {
276
273
  textArea.value = getSettingsValue(key) as string
@@ -292,48 +289,59 @@ async function updateOptions() {
292
289
  }
293
290
  }
294
291
 
295
- function getSettingsContainer() {
292
+ function getSettingsContainer(create = false) {
296
293
  const container = $(`.${prefix}container`)
297
294
  if (container) {
298
295
  const theVersion = parseInt10(container.dataset.besVersion, 0)
299
296
  if (theVersion < besVersion) {
300
- container.id = settingsContainerId
301
297
  container.dataset.besVersion = String(besVersion)
302
298
  }
303
299
 
304
300
  return container
305
301
  }
306
302
 
307
- return addElement(doc.body, "div", {
308
- id: settingsContainerId,
309
- class: `${prefix}container`,
310
- "data-bes-version": besVersion,
311
- style: "display: none;",
312
- })
303
+ if (create) {
304
+ return addElement(doc.body, "div", {
305
+ class: `${prefix}container`,
306
+ "data-bes-version": besVersion,
307
+ style: "display: none;",
308
+ })
309
+ }
313
310
  }
314
311
 
315
- function getSettingsWrapper() {
316
- const container = getSettingsContainer()
317
- return (
318
- $(`.${prefix}wrapper`, container) ||
319
- addElement(container, "div", {
320
- class: `${prefix}wrapper`,
321
- })
322
- )
312
+ function getSettingsShadowRoot(): ShadowRoot | undefined {
313
+ const container = getSettingsContainer(true)
314
+ if (container?.attachShadow) {
315
+ return container.shadowRoot || container.attachShadow({ mode: "open" })
316
+ }
317
+
318
+ return undefined
323
319
  }
324
320
 
325
- function initExtensionList() {
326
- const wrapper = getSettingsWrapper()
327
- if (!$(".extension_list_container", wrapper)) {
328
- const list = createExtensionList([])
329
- wrapper.append(list)
321
+ function getSettingsWrapper() {
322
+ const shadow = getSettingsShadowRoot()
323
+ if (!shadow) {
324
+ const container = getSettingsContainer(true)!
325
+ return (
326
+ $(`.${prefix}wrapper`, container) ||
327
+ addElement(container, "div", { class: `${prefix}wrapper` })
328
+ )
330
329
  }
331
330
 
332
- addCurrentExtension({
333
- id: settingsOptions.id,
334
- title: settingsOptions.title,
335
- onclick: showSettings,
336
- })
331
+ let wrapper = shadow.querySelector(`.${prefix}wrapper`)
332
+ if (!wrapper) {
333
+ wrapper = createElement("div", { class: `${prefix}wrapper` })
334
+ shadow.append(wrapper)
335
+
336
+ const existStyle = shadow.querySelector(`style`)
337
+ if (!existStyle) {
338
+ const styleElm = createElement("style")
339
+ styleElm.textContent = styleText
340
+ shadow.append(styleElm)
341
+ }
342
+ }
343
+
344
+ return wrapper as HTMLElement
337
345
  }
338
346
 
339
347
  function createSettingsElement() {
@@ -346,18 +354,9 @@ function createSettingsElement() {
346
354
  }
347
355
 
348
356
  settingsMain = addElement(wrapper, "div", {
349
- id: settingsElementId,
350
357
  class: `${prefix}main thin_scrollbar`,
351
358
  })
352
359
 
353
- // addElement(settingsMain, "a", {
354
- // textContent: i("settings.title"),
355
- // class: "navigation_go_previous",
356
- // onclick() {
357
- // activeExtensionList()
358
- // },
359
- // })
360
-
361
360
  if (settingsOptions.title) {
362
361
  addElement(settingsMain, "h2", { textContent: settingsOptions.title })
363
362
  }
@@ -538,41 +537,6 @@ function createSettingsElement() {
538
537
  return settingsMain
539
538
  }
540
539
 
541
- function addSideMenu() {
542
- if (!getSettingsValue("displaySettingsButtonInSideMenu")) {
543
- return
544
- }
545
-
546
- const menu =
547
- $("#browser_extension_side_menu") ||
548
- addElement(doc.body, "div", {
549
- id: "browser_extension_side_menu",
550
- "data-bes-version": besVersion,
551
- })
552
-
553
- const button = $("button[data-bes-version]", menu)
554
-
555
- if (button) {
556
- const theVersion = parseInt10(button.dataset.besVersion, 0)
557
- if (theVersion >= besVersion) {
558
- return
559
- }
560
-
561
- button.remove()
562
- }
563
-
564
- addElement(menu, "button", {
565
- type: "button",
566
- "data-bes-version": besVersion,
567
- title: i("settings.menu.settings"),
568
- onclick() {
569
- setTimeout(showSettings, 1)
570
- },
571
- // eslint-disable-next-line @typescript-eslint/naming-convention
572
- innerHTML: createHTML(settingButton),
573
- })
574
- }
575
-
576
540
  function addCommonSettings(settingsTable: SettingsTable) {
577
541
  let maxGroup = 0
578
542
  for (const key in settingsTable) {
@@ -613,8 +577,22 @@ function handleShowSettingsUrl() {
613
577
  }
614
578
  }
615
579
 
580
+ function onBeforeShowSettings() {
581
+ // Close opened modal before showing settings from other extension
582
+ closeModal()
583
+ }
584
+
616
585
  export async function showSettings() {
617
- const settingsContainer = getSettingsContainer()
586
+ // Close opened modal before showing settings
587
+ closeModal()
588
+
589
+ const event = new CustomEvent("beforeShowSettings")
590
+ globalThis.dispatchEvent(event)
591
+
592
+ // Listen to beforeShowSettings event to close opened modal before showing settings from other extension
593
+ addEventListener(globalThis, "beforeShowSettings", onBeforeShowSettings, true)
594
+
595
+ const settingsContainer = getSettingsContainer(true)!
618
596
 
619
597
  const settingsMain = createSettingsElement()
620
598
  await updateOptions()
@@ -673,7 +651,7 @@ export const initSettings = async (optionsProvider: () => SettingsOptions) => {
673
651
  console.log("lastLocale:", lastLocale, "newLocale:", newLocale)
674
652
  if (lastLocale !== newLocale) {
675
653
  const isShown = isSettingsShown()
676
- destroySettings()
654
+ closeModal()
677
655
  resetI18n(newLocale)
678
656
  lastLocale = newLocale
679
657
 
@@ -699,10 +677,6 @@ export const initSettings = async (optionsProvider: () => SettingsOptions) => {
699
677
  resetSettingsUI(optionsProvider)
700
678
  }, 50)
701
679
 
702
- runWhenHeadExists(() => {
703
- addStyle(getSettingsStyle())
704
- })
705
-
706
680
  void registerMenuCommand(i("settings.menu.settings"), showSettings, {
707
681
  accessKey: "o",
708
682
  })
package/lib/style.scss CHANGED
@@ -1,4 +1,4 @@
1
- #browser_extension_settings_container {
1
+ :host {
2
2
  --browser-extension-settings-background-color: #f2f2f7;
3
3
  --browser-extension-settings-text-color: #444444;
4
4
  --browser-extension-settings-link-color: #217dfc;
@@ -10,21 +10,16 @@
10
10
  position: fixed;
11
11
  top: 10px;
12
12
  right: 30px;
13
- max-height: 90%;
14
- height: 600px;
15
- overflow: hidden;
16
13
  display: none;
17
14
 
18
- z-index: 100000;
15
+ z-index: 200000;
19
16
  border-radius: 5px;
20
17
  -webkit-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
21
18
  -moz-box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22);
22
19
  box-shadow: 0px 10px 39px 10px rgba(62, 66, 66, 0.22) !important;
23
20
 
24
- .browser_extension_settings_wrapper {
21
+ .browser_extension_settings_v2_wrapper {
25
22
  display: flex;
26
- height: 100%;
27
- overflow: hidden;
28
23
  background-color: var(--browser-extension-settings-background-color);
29
24
  font-family: var(--font-family);
30
25
 
@@ -77,75 +72,6 @@
77
72
  font-family: var(--font-family);
78
73
  }
79
74
  }
80
-
81
- a.navigation_go_previous {
82
- color: var(--browser-extension-settings-link-color);
83
- cursor: pointer;
84
- display: none;
85
-
86
- &::before {
87
- content: "< ";
88
- }
89
- }
90
-
91
- .extension_list_container {
92
- overflow-x: auto;
93
- box-sizing: border-box;
94
- padding: 10px 15px;
95
- background-color: var(--browser-extension-settings-background-color);
96
- color: var(--browser-extension-settings-text-color);
97
-
98
- .installed_extension_list,
99
- .related_extension_list {
100
- div {
101
- background-color: #fff;
102
- font-size: 14px;
103
- border-top: 1px solid #cccccc;
104
- padding: 6px 15px 6px 15px;
105
-
106
- a,
107
- a:visited {
108
- display: flex;
109
- justify-content: space-between;
110
- align-items: center;
111
- cursor: pointer;
112
- text-decoration: none;
113
- color: var(--browser-extension-settings-text-color);
114
- font-family: var(--font-family);
115
-
116
- &:hover {
117
- text-decoration: none;
118
- color: var(--browser-extension-settings-text-color);
119
- }
120
-
121
- span {
122
- margin-right: 10px;
123
- line-height: 24px;
124
- font-family: var(--font-family);
125
- }
126
- }
127
-
128
- &.active,
129
- &:hover {
130
- background-color: #e4e4e6;
131
- }
132
-
133
- &.active a {
134
- cursor: default;
135
- }
136
-
137
- &:first-of-type {
138
- border-top: none;
139
- border-top-right-radius: 10px;
140
- border-top-left-radius: 10px;
141
- }
142
- &:last-of-type {
143
- border-bottom-right-radius: 10px;
144
- border-bottom-left-radius: 10px;
145
- }
146
- }
147
- }
148
- }
149
75
  }
150
76
 
151
77
  .thin_scrollbar {
@@ -169,9 +95,9 @@
169
95
  }
170
96
  }
171
97
 
172
- #browser_extension_settings_main {
173
- min-width: 250px;
174
- /*max-height: 90%;*/
98
+ .browser_extension_settings_v2_main {
99
+ min-width: 300px;
100
+ max-height: 90vh;
175
101
  overflow-y: auto;
176
102
  overflow-x: hidden;
177
103
 
@@ -217,8 +143,11 @@
217
143
  }
218
144
 
219
145
  .option_groups textarea {
146
+ background-color: var(--browser-extension-settings-background-color);
147
+ color: var(--browser-extension-settings-text-color);
220
148
  font-size: 12px;
221
149
  margin: 10px 0 10px 0;
150
+ padding: 4px 8px;
222
151
  height: 100px;
223
152
  width: 100%;
224
153
  border: 1px solid darkgray;
@@ -254,6 +183,7 @@
254
183
  }
255
184
 
256
185
  .bes_option > .bes_select {
186
+ color: var(--browser-extension-settings-text-color);
257
187
  box-sizing: border-box;
258
188
  background-color: #fff;
259
189
  height: 24px;
@@ -287,6 +217,8 @@
287
217
  background-color: #ffffff;
288
218
  color: var(--browser-extension-settings-text-color);
289
219
  text-align: left;
220
+ overflow-y: auto;
221
+ max-height: 300px;
290
222
  padding: 10px;
291
223
  display: none;
292
224
  border-radius: 5px;
@@ -392,62 +324,12 @@
392
324
  }
393
325
  }
394
326
 
395
- #browser_extension_side_menu {
396
- min-height: 80px;
397
- width: 30px;
398
- opacity: 0;
399
- position: fixed;
400
- top: 80px;
401
- right: 0;
402
- padding-top: 20px;
403
- z-index: 10000;
404
- }
405
-
406
- #browser_extension_side_menu:hover {
407
- opacity: 1;
408
- }
409
-
410
- #browser_extension_side_menu button {
411
- cursor: pointer;
412
- width: 24px;
413
- height: 24px;
414
- padding: 0;
415
- border: none;
416
- background-color: transparent;
417
- background-image: none;
418
-
419
- svg {
420
- width: 24px;
421
- height: 24px;
422
- }
423
- }
424
-
425
- #browser_extension_side_menu button:hover {
426
- opacity: 70%;
427
- }
428
-
429
- #browser_extension_side_menu button:active {
430
- opacity: 100%;
431
- }
432
-
433
327
  @media (max-width: 500px) {
434
- #browser_extension_settings_container {
328
+ :host {
435
329
  right: 10px;
330
+ }
436
331
 
437
- .browser_extension_settings_wrapper {
438
- a.navigation_go_previous {
439
- display: block;
440
- }
441
-
442
- .extension_list_container {
443
- display: none;
444
- }
445
- .extension_list_container.bes_active {
446
- display: block;
447
- }
448
- .extension_list_container.bes_active + div {
449
- display: none;
450
- }
451
- }
332
+ .browser_extension_settings_v2_main {
333
+ max-height: 85%;
452
334
  }
453
335
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-extension-settings",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "Settings module for developing browser extensions and userscripts",
5
5
  "type": "module",
6
6
  "main": "./lib/index.ts",