FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
FluentRead/userscript/settingsFull.ts at main · FluentRead/FluentRead · GitHub
FluentRead
/
FluentRead
Public
Notifications
You must be signed in to change notification settings
Fork
422
Star
8.2k
Code
Issues
12
Pull requests
4
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
FluentRead
/
userscript
/
settingsFull.ts
Copy path
More file actions
More file actions
Latest commit
History
History
History
164 lines (151 loc) · 6.71 KB
Breadcrumbs
FluentRead
/
userscript
/
settingsFull.ts
Copy path
File metadata and controls
164 lines (151 loc) · 6.71 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import
{
installOptionsApp
}
from
'@/src/app/options'
;
import
OptionsApp
from
'@/src/app/options/OptionsApp.vue'
;
import
{
createVueShadowUi
,
type
VueShadowMount
}
from
'@/src/platform/shadow-ui'
;
import
type
{
ShadowRootContentScriptUi
}
from
'wxt/utils/content-script-ui/shadow-root'
;
import
{
getUserscriptFunction
}
from
'./api'
;
import
{
buildUserscriptSettingsHash
,
buildUserscriptSettingsUrl
,
isUserscriptSettingsUrl
,
USERSCRIPT_SETTINGS_HASH
,
}
from
'./settingsPage'
;
export
{
buildUserscriptSettingsUrl
,
isUserscriptSettingsUrl
}
;
let
settingsUi
:
ShadowRootContentScriptUi
<
VueShadowMount
>
|
null
=
null
;
let
settingsMountPromise
:
Promise
<
void
>
|
null
=
null
;
let
settingsGeneration
=
0
;
let
hiddenBallHost
:
HTMLElement
|
null
=
null
;
let
previousBallSuspendedAttribute
:
string
|
null
=
null
;
let
ballObserver
:
MutationObserver
|
null
=
null
;
function
restoreHiddenBallHost
(
)
:
void
{
if
(
hiddenBallHost
&&
hiddenBallHost
.
getAttribute
(
'data-fluent-read-ui-suspended'
)
===
'true'
)
{
if
(
previousBallSuspendedAttribute
!==
null
)
{
hiddenBallHost
.
setAttribute
(
'data-fluent-read-ui-suspended'
,
previousBallSuspendedAttribute
)
;
}
else
{
hiddenBallHost
.
removeAttribute
(
'data-fluent-read-ui-suspended'
)
;
}
}
hiddenBallHost
=
null
;
previousBallSuspendedAttribute
=
null
;
}
function
restoreFloatingBall
(
)
:
void
{
ballObserver
?.
disconnect
(
)
;
ballObserver
=
null
;
restoreHiddenBallHost
(
)
;
}
function
hideFloatingBallBehindOverlay
(
)
:
void
{
if
(
typeof
document
===
'undefined'
||
ballObserver
)
return
;
const
sync
=
(
)
=>
{
const
nextHost
=
document
.
querySelector
<
HTMLElement
>
(
'#fluent-read-floating-ball-container[data-fluent-read-userscript-host="fluent-read-floating-ball-ui"]'
,
)
;
if
(
nextHost
===
hiddenBallHost
)
return
;
restoreHiddenBallHost
(
)
;
if
(
!
nextHost
)
return
;
hiddenBallHost
=
nextHost
;
previousBallSuspendedAttribute
=
nextHost
.
getAttribute
(
'data-fluent-read-ui-suspended'
)
;
nextHost
.
setAttribute
(
'data-fluent-read-ui-suspended'
,
'true'
)
;
}
;
if
(
typeof
MutationObserver
!==
'undefined'
)
{
ballObserver
=
new
MutationObserver
(
sync
)
;
ballObserver
.
observe
(
document
.
documentElement
,
{
childList
:
true
,
subtree
:
true
}
)
;
}
sync
(
)
;
}
function
showInPageFallback
(
ctx
:
unknown
,
section
?:
string
)
:
void
{
void
mountSettingsUi
(
ctx
,
section
)
.
catch
(
(
error
)
=>
{
console
.
error
(
'[FluentRead userscript] 设置标签页和页内回退都未能打开'
,
error
)
;
}
)
;
}
function
openSettingsTab
(
ctx
:
unknown
,
section
?:
string
)
:
boolean
{
const
settingsUrl
=
buildUserscriptSettingsUrl
(
window
.
location
.
href
,
section
)
;
if
(
settingsUrl
===
window
.
location
.
href
)
return
false
;
// Android WebView 的脚本管理器可能无视 active 参数,在后台打开标签页。
// 在移动端直接挂载页内设置,让点击悬浮球后立即看到操作结果。
if
(
typeof
navigator
!==
'undefined'
&&
/
A
n
d
r
o
i
d
/
i
.
test
(
navigator
.
userAgent
)
)
return
false
;
// Tampermonkey/Violentmonkey 等管理器提供的专用 API 可显式激活新标签页。
// 未提供此能力时直接使用页内面板;普通 window.open 可能只在后台
// 创建标签页,让用户误以为点击设置没有反应。
const
legacyOpenInTab
=
getUserscriptFunction
(
'GM_openInTab'
)
;
if
(
legacyOpenInTab
)
{
try
{
const
result
=
legacyOpenInTab
(
settingsUrl
,
{
active
:
true
,
insert
:
true
,
setParent
:
true
}
)
;
void
Promise
.
resolve
(
result
)
.
catch
(
(
)
=>
showInPageFallback
(
ctx
,
section
)
)
;
return
true
;
}
catch
{
// 部分管理器只声明 API 但运行时不可用,继续尝试现代接口。
}
}
const
modernOpenInTab
=
getUserscriptFunction
(
undefined
,
'openInTab'
)
;
if
(
modernOpenInTab
)
{
try
{
// Userscripts for Safari uses a boolean background flag and returns
// a Promise. Invoke it before any async work so the current click
// remains a valid user gesture for opening a new tab.
void
Promise
.
resolve
(
modernOpenInTab
(
settingsUrl
,
false
)
)
.
catch
(
(
)
=>
showInPageFallback
(
ctx
,
section
)
)
;
return
true
;
}
catch
{
// 直接使用页内面板。
}
}
return
false
;
}
export
async
function
openUserscriptSettings
(
ctx
:
unknown
,
section
?:
string
)
:
Promise
<
void
>
{
if
(
!
isUserscriptSettingsUrl
(
window
.
location
.
href
)
&&
openSettingsTab
(
ctx
,
section
)
)
return
;
await
mountSettingsUi
(
ctx
,
section
)
;
}
async
function
mountSettingsUi
(
ctx
:
unknown
,
section
?:
string
)
:
Promise
<
void
>
{
const
separateSettingsPage
=
isUserscriptSettingsUrl
(
window
.
location
.
href
)
;
if
(
separateSettingsPage
&&
section
)
{
const
nextHash
=
buildUserscriptSettingsHash
(
section
)
;
if
(
window
.
location
.
hash
!==
nextHash
)
window
.
location
.
hash
=
nextHash
;
}
if
(
settingsUi
)
return
;
if
(
settingsMountPromise
)
return
settingsMountPromise
;
const
generation
=
settingsGeneration
;
if
(
!
separateSettingsPage
)
hideFloatingBallBehindOverlay
(
)
;
const
mountPromise
=
createVueShadowUi
(
ctx
as
never
,
{
name
:
'fluent-read-userscript-settings-ui'
,
hostId
:
'fluent-read-userscript-settings-container'
,
component
:
OptionsApp
,
props
:
(
container
)
=>
{
const
root
=
container
.
getRootNode
(
)
;
const
shadowRoot
=
root
instanceof
ShadowRoot
?
root
:
null
;
return
{
appearanceRoot
:
shadowRoot
?.
host
instanceof
HTMLElement
?
shadowRoot
.
host
:
null
,
queryRoot
:
root
,
settingsHashPrefix
:
separateSettingsPage
?
USERSCRIPT_SETTINGS_HASH
:
undefined
,
initialSection
:
separateSettingsPage
?
undefined
:
section
,
locationRouting
:
separateSettingsPage
?
undefined
:
'internal'
,
onClose
:
separateSettingsPage
?
undefined
:
closeUserscriptSettings
,
}
;
}
,
configureApp
:
(
app
)
=>
installOptionsApp
(
app
,
{
documentRoot
:
null
}
)
,
viewport
:
true
,
zIndex
:
2_147_483_647
,
mode
:
'closed'
,
}
)
.
then
(
(
ui
)
=>
{
if
(
generation
!==
settingsGeneration
)
ui
.
remove
(
)
;
else
settingsUi
=
ui
;
}
)
;
settingsMountPromise
=
mountPromise
;
try
{
await
mountPromise
;
}
catch
(
error
)
{
if
(
generation
===
settingsGeneration
)
restoreFloatingBall
(
)
;
throw
error
;
}
finally
{
if
(
settingsMountPromise
===
mountPromise
)
settingsMountPromise
=
null
;
}
}
export
function
closeUserscriptSettings
(
)
:
void
{
settingsGeneration
+=
1
;
settingsMountPromise
=
null
;
const
ui
=
settingsUi
;
settingsUi
=
null
;
try
{
ui
?.
remove
(
)
;
}
finally
{
restoreFloatingBall
(
)
;
}
}
Back
|
FazBrowse Home
|
New Git URL